Skip to content

Instantly share code, notes, and snippets.

@skplunkerin
Last active August 26, 2016 15:58
Show Gist options
  • Save skplunkerin/7185fc7291f4fc51787386f0af0d7e5c to your computer and use it in GitHub Desktop.
Save skplunkerin/7185fc7291f4fc51787386f0af0d7e5c to your computer and use it in GitHub Desktop.
ruby on rails tutorials

The Basics

1. Chapter Foreward

Have you ever wanted to keep track of your Starship Fleet, but just can't trust to use the available Starship Fleet Tracker? Mercenary, you're not alone... for all we know the Fleet Trackers out there are controlled by the Empire, the Hutts, or even worse... Microsoft! Let's trust the best source we can, ourselves. Besides, we're mercs... if we can't handle this job we might as well just pack our bags and go work back home at the moisture farm, which... we know we don't want that right? Yeah... didn't think so, so let's hop to it!

2. Creating a new Rails project

I'm not going to get your merc environment setup for you, but if you need help check out my scribbles here.

# Create Project (and cd into project)
$ rails new starship_fleet

# Start the Rails server
$ rails s

# visit your new site: http://127.0.0.1:3000

3. Creating a new Controller for our home page

Note: Controller names are typically "plural". In this case (and usually for a home page), we skip that "standard" and go for a "singular" named controller instead. Checkout Step 8 for the plural rule in action.

g = generate, and can be used interchangeably. (i.e. rails generate controller welcome)

$ rails g controller welcome

4. Updating Routes to use our new home page controller

Edit file: config/routes.rb and add the following to line 2.

root 'welcome#index'

Now... reloading your webpage will show a big fat Unknown action error, let's fix that.

Edit file: app/controllers/welcome_controller.rb to look like the following:

class WelcomeController < ApplicationController
  def index
  end
end

HA! Take that ~insert derogatory name here`! I've never been much for those bugs... Now reload your page again. :) Well well well... these bugs are just asking for it, so let's give it to 'em!

Create file: app/views/welcome/index.html.erb with the following content.

<h1>Howdy Partner...</h1>
<p>
  It's been awhile, hasn't it... You're looking good! Let's get our Starship Fleet taken care of, it's about time you actually do some work around here.
</p>

Alright, now load that page again! Hey! Looks like we're not alone. Good thing too, we've got alot of work up ahead of us. Come on partner, let's get to it.

5. Editing our home page View

Edit file: app/views/welcome/index.html.erb to look something like the following.

<h1>Starship Fleet Tracker</h1>
<p>
  It's about time we start tracking our Fleet... all those Starships are just piling up aren't they? Let's make sure this memory of mine doesn't go bad
 on us before this is done.
</p>

6. Creating a Model for ship data

Ok, here's where things get fun! Let's get our Model under way... think of it like our "Hangar" that holds all of our Starships... OH! JUST LIKE DATABASE! Yeah, think of it like that! Like, the door to a database of information... yeahhhh... I'm liking where this is going.

NOTE: The rule of thumb for creating a Model is to use "singular" names. Yeah, Controller names should be "plural", and Model names "singular"... don't ask questions!

$ rails g model ship

This created two important things for us:

  1. A Model file (app/models/ship.rb) which will be used to specify relationships, data requirements, and any kind of logic for our data that we need.
  2. A Migration file (db/migrate/yyyymmdd######_create_ships.rb) where we will specify the Database table being created, the available columns, and the column data types.

Let's udpate file: db/migrate/yyyymmdd######_create_ships.rb to have the following contents:

class CreateShips < ActiveRecord::Migration
  def change
    create_table :ships do |t|
      t.string    :name
      
      t.timestamps null: false 
    end
  end
end

7. Running our first Migration

Wipe that stupid grin off your face, we're not done yet! All we did was write down a quick blueprint on a napkin, let's actually build something now.

$ rake db:migrate

By default, a new Rails project comes equipped with a basic SQLite Database. For now, we'll stick with this implementation but be aware that if you're wanting to use MySQL, Postgres, or any other Database solution there's more steps involved (i.e., install ruby gems, setup your Database Solution, update the projects database configuration, etc).

Alright... who like's save points? Heck, I sure do! We're mercs right?! Last thing I want to do is get myself mixed up with some bad decisions without being able to revert back to my last good decision... not that that ever happens to us mercs, we're professionals! (but just in case, let's cover our tracks!)

$ git init
$ git add --all
$ git config user.email handsomejack@perkswithmercs.com
$ git commit -m "- Initialize project with home page and Ship model/migration"

I know we're friends, so I'll tell you this once... I'm not your mom! Make sure you keep your save points recent and up-to-date cause I'm sure as hell aen't going to remind ya... again!

8. Creating a Controller for ship CRUD interface

It doesn't look like it, but our Database is pipe'n hot! Let's create a Controller so we can start using it already.

$ rails g controller ships index show new create edit update destroy

Wait, what is this after ships? Well, I'll let you in on a little secret... never buy a droid with a bad motivator, NEVER! Anyways, let's see how our new file: app/controllers/ships_controller.rb is looking:

class ShipsController < ApplicationController
  def index 
  end

  def show
  end

  def new
  end

  def create
  end
  
  def edit
  end

  def update
  end

  def destroy
  end
end

Alright, looks like all of the functions we'll need are created for us. Let's see if we need to create our corresponding Views.

Check the files under app/views/ships/, does it look anything like the following?

ships/
  create.html.erb
  edit.html.erb
  destroy.html.erb
  index.html.erb
  new.html.erb
  show.html.erb
  update.html.erb

If so, you're doing it all wrong! Let's get rid of what we're not going to use. Delete create.html.erb, destroy.html.erb, and update.html.erb until we look like:

ships/
  edit.html.erb
  index.html.erb
  new.html.erb
  show.html.erb

Good job! I knew you had hears, you might be useful yet!

9. Updating Routes for RESTful architecture

RESTful architecture:

  • GET
  • POST
  • PATCH / PUT
  • DELETE

You might not know it yet, but the Controller methods we setup have put us in a good spot to use the RESTful architecture. Remember, having a Controller means nothing unless we check out file: config/routes.rb... looks like it's gotten all messed up, does yours look like this?

Rails.application.routes.draw do
  get 'ships/index'

  get 'ships/show'

  get 'ships/new'

  get 'ships/create'

  get 'ships/edit'

  get 'ships/update'

  get 'ships/destroy'

  root 'welcome#index'

[...file abbreviated...]

Crap! Let's clean this mess up... what did I tell you about droids with bad motivators, huh? Always messing things up...

Rails.application.routes.draw do
  root 'welcome#index'
  resources :ships

[...file abbreviated...]

Well neat... now we're looking pretty nice, but how do we even load our new pages? Let's check what Routes we have available:

$ rake routes

See anything, familiar...?

   Prefix Verb   URI Pattern               Controller#Action
     root GET    /                         welcome#index
    ships GET    /ships(.:format)          ships#index
          POST   /ships(.:format)          ships#create
 new_ship GET    /ships/new(.:format)      ships#new
edit_ship GET    /ships/:id/edit(.:format) ships#edit
     ship GET    /ships/:id(.:format)      ships#show
          PATCH  /ships/:id(.:format)      ships#update
          PUT    /ships/:id(.:format)      ships#update
          DELETE /ships/:id(.:format)      ships#destroy

If this looks right, let's try loading the #index method by visiting http://127.0.0.1:3000/ships/ and see what happens. Perfect, no bugs here right? Told you you can count on me.

10. Adding Create form in our Views

I don't have time to explain it! Just keep up with me, will ya!?

First, let's link to our #new View.

Edit file: app/views/ships/index.html.erb to contain:

<h1>Starship Fleet</h1>
<hr />

<%= link_to "Add New Starship to Fleet", new_ship_path %>

<h2>Starship Fleet</h2>        
<ul>
  <li>Starships will be listed here...</li>
</ul>

Before we go reloading our page and clicking on our new link, how about we actually have a form to add our new Starship.

Edit file: app/views/ships/new.html.erb to have:

<h1>Add New Starship</h1>      

<% if @ship.errors.any? %>
  <div class="error_messages">
    <h2>Look, if you're going to do the job then do it right the first time!</h2>
    <ul>
      <% for message in @ship.errors.full_messages %>
        <li><%= message %></li>
      <% end %>
    </ul>
  </div>
<% end %>
<%= form_for @ship do |f| %>   
  <div>
    <%= f.label :name %><br /> 
    <%= f.text_field :name, placeholder: "X-Wing" %> 
  </div>
  <div>
    <%= f.submit "Add" %>      
  </div>
<% end %>

Before this will work, make sure you update the #new method inside of file: apps/controllers/ships_controller.rb to the following:

  def new
    @ship = Ship.new
  end

Now go ahead, reload it and just try adding your new Starship... hahah, blew up didn't it? STOP PUSHING BUTTONS UNTIL WE'RE DONE! Geez... always jumping the gun.

11. Strong Parameters in our Controller

Now, we need to do a couple things in our Ships Controller before we can even use the form we just created...

Strong Parameters are a nice method to keep us a little bit safer from hacks. We want to make sure the data we're expecting is what we're getting, and ignore everything else sent to us.

Add the following to the end of the file: app/views/controllers/ships_controller.rb:

[...beginning of file abbreviated...]
  def destroy                  
  end

  private
  def ship_params
    params.require(:ship).permit(:name)
  end
end

This makes sure that the parameters we're expecting POSTed to us from our form are the fields we know should be returned. Anything else is ignored.

12. Create logic in our Controller

Hokay, so here's where we fix the mess you created by pushing the shiny new button. Our #create method needs some updating.

Edit file: app/views/controllers/ships_controller.rb, and change the #create method to the following:

  def create
    @ship = Ship.new(ship_params)
    if @ship.save
      flash[:success] = "Starship added!"
      redirect_to ships_url
    else
      flash[:error] = "#{@ship.errors.full_messages.to_sentence}"
      render new
    end
  end

Now, wipe your greasy fingerprint off our button and try it again... is it working? Hmmm, let's make sure we load all Starships onto our Ships#index.

13. Showing all ships in our Controller#index

Yeah yeah, I know... just follow my lead below.

Edit file: app/controllers/ships_controller.rb, let's have the #index method look like:

  def index
    @ships = Ship.all
  end

Edit file: app/views/ships/index.html.erb to be:

[...beginning of file abbreviated...]
<h2>Starship Fleet</h2>
<ul>
  <% @ships.each do |ship| %>
    <li><%= ship.name %></li>
  <% end %>
</ul>

Neat huh? Yeah well... we're not done yet!

14. Show a ship in our Controller#show

Now, we don't have much more to look at besides the Starships name... but let's use our #show method so it doesn't start collecting dust.

Edit file: app/controllers/ships_controller.rb, have the #show method match my example below:

  def show
    @ship = Ship.find(params[:id])
  end

Now, edit app/views/ships/index.html.erb like so:

[...abbreviated...]
<ul>
  <% @ships.each do |ship| %>
    <li><%= link_to ship.name, ship_path(ship) %></li>
  <% end %>
</ul>

And edit app/views/ships/show.html.erb to:

<h1><%= @ship.name %></h1>     
<p>
  Someday, we'll be able to see stats for our little <%= @ship.name %>, but that's not free is it?
  <br/>
  Pay up or shut up!
</p>

Pretty basic stuff here, I'm actually surprised you didn't know this. Whelp... guess that can't be helped much with your lack of experience. Let's keep on going.

15. Update a ship from our Controller#show

Wouldn't it be nice to fix your Starship names typo... I mean, change the name to something cooler? Yeah, let's do just that!

Edit file: app/views/ships/show.html.erb

<h1><%= @ship.name %>&nbsp;<%= link_to "Edit", edit_ship_path(@ship) %></h1>
[...abbrev...]

Update app/controllers/ships_controller.rb, change the #edit method to:

  def edit
    @ship = Ship.find(params[:id])  
  end 

Now, edit app/views/ships/edit.html.erb to:

<h1>Editing: <%= @ship.name %></h1>

<% if @ship.errors.any? %>
  <div class="error_messages">
    <h2>Droids with bad motivators mess up less than you!</h2>
    <ul>
      <% for message in @ship.errors.full_messages %>
        <li><%= message %></li>
      <% end %>
    </ul>
  </div>
<% end %>
<%= form_for @ship do |f| %>   
  <div>
    <%= f.label :name %><br />
    <%= f.text_field :name, placeholder: @ship.name %>
  </div>
  <div>
    <%= f.submit "Update" %><br />  
    <%= link_to "Cancel", ship_path(@ship) %>
  </div>
<% end %>

Now, before you try pushing this new button, how about we finish things up huh?

Edit the #update method in file: app/controllers/ships_controller.rb to:

  def update
    @ship = Ship.find(params[:id])  
    if @ship.update_attributes(ship_params)
      flash[:success] = "Starship updated!"
      redirect_to ships_url    
    else
      flash[:error] = "#{@ship.errors.full_messages.to_sentence}"
      render edit              
    end
  end

Now go ahead an test that puppy out. (and fix your typos while you're at it...)

16. Deleting a ship

HAA! Nice try... I'm pretty sure you don't have a Death Star on hand. You must've thought since we couldn't delete false entries that people would just believe whatever they read on the internet... this isn't 2016 anymore! OF COURSE WE CAN DELETE FALSE ENTRIES!

Edit app/controllers/ships_controller.rb, and get the #destroy method fleshed out:

  def destroy
    @ship = Ship.find(params[:id])
    if @ship.destroy
      flash[:success] = "Starship deleted!"
      redirect_to ships_url
    else
      flash[:error] = "#{@ship.errors.full_messages.to_sentence}"
      render edit
    end
  end

Now update app/views/ships/edit.html.erb with:

[...abbrev...]
  <div>
    <%= f.submit "Update" %><br />  
    <%= link_to "Cancel", ship_path(@ship) %><br />
    <%= link_to "Delete", ship_path(@ship), data: {confirm: "Do you really want to delete #{@ship.name}?"}, method: :delete %>
  </div>
<% end %>

Now go ahead and remove your falsified Death Star...

Coming next time...

Coming next time...

@jypweb
Copy link

jypweb commented Aug 26, 2016

https://gist.github.com/skplunkerin/7185fc7291f4fc51787386f0af0d7e5c#6-creating-a-model-for-ship-data

There's a typo. Udpate should be Update. ^_^

Also, should we mention that we can create the controller/view definition when we first generate the controller?

rails g controller welcome index

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment