Resourceful Girl

For a while, we’ve been building out Rails applications “the ol’ fashioned” way — that is to say, creating our migrations by hand, with something like:
rails g migration CreateDogs name:string --no-test-framework
And then perhaps adding to that migration with:
rails g migration AddOwnerToDogs owner:belongs_to --no-test-framework
Rails is smart enough to know that because of the “Add” naming convention, it will assume that you’re adding a column to the table.
We’ve also been creating the model and controller by hand:
#..app/models/dog.rb
class Dog << ActiveRecord::Base
end#..app/controllers/dogs_controller.rbclass DogsController < ApplicationController def index
@dogs = Dog.all
render 'index'
end def show
@dog = Dog.find(params[:id])
render 'show'
end def new
@dog = Dog.new
render 'new'
endend
On top of this, we’ve had to create a dogs
folder in view
corresponding to each model (e.g. Dogs, Owners, etc.), while also defining the routes themselves in “config/routes.rb”:
#../config/routes.rbRails.application.routes.draw do get ‘/dogs’, to: ‘dogs#index’ get ‘/dogs/:id’, to: ‘dogs#show’ get '/dogs/new', to: 'dogs#new'end
This is laborious. As programmers, if it’s one thing to be sure of, it’s that someone, somewhere, has probably had the same qualms as you, and devised a way to make their job easier. This makes our job easier (if they shared!).
rails g resource Dog name:string owner:belongs_to --no-test-framework
This single line will do everything for us (plus a little extra!). We just need to understand exactly what this does, and we’ll be set to start writing code in seconds!
This will do the following, based on the name Dog:
- Create a migration file:
#../db/migrate/20160113001427_create_dogs.rbclass CreatePosts < ActiveRecord::Migration
def change
create_table :dogs do |d|
t.string :name
t.belongs_to :owner
t.timestamps null: false
end
end
end
2. Create the model & controller:
#../app/controllers/dogs_controller.rb
class DogsController < ApplicationController
end
Notice that rails g resource
will also add any associations if you defined them in the same line (e.g. owner:belongs_to
as shown above):
#../app/models/dog.rb
class Dog < ActiveRecord::Base
belongs_to :owner
end
3. Create the dogs
folder within the views
folder, and defines the route:
#../config/routes.rbRails.application.routes.draw do resources :dogsend
There isn’t much difference in the code generated ‘by hand’, and the code generated with rails g resource
. But that’s the beauty of it — given a single name, i.e. Dog, rails knows how to create the base foundation for the files you want to make anyways!
The main difference between what we’ve conventionally done, is in the resources :dogs
.
This bit says that we’re probably also trying to create the 7 CRUD action/paths for /dogs.
Since we already have our controller defined as above, we technically don’t need to define any sort of controller actions, like we did previously:
#..app/controllers/dogs_controller.rbclass DogsController < ApplicationController def index
@dogs = Dog.all
render 'index'
end def show
@dog = Dog.find(params[:id])
render 'show'
end def new
@dog = Dog.new
render 'new'
endend
The line we have, resources :dogs
, assumes that we already want the controller actions “index”, “show”, “new”, “create”, “edit”, “update”, and “delete”.
We technically don’t need to even define them in the controller.
If you deleted the def index
action from DogsController, but still at least had a view that read:
#..app/views/dogs/index.html.erb<h1>Hello!</h1>
And navigated to http://localhost:3000/dogs, you’d be welcomed with a big Hello!
Why is this? Because Rails just knows. It does know you.
… But also, because saying resources :dogs
will auto-magically define those 7 methods within the controller action, THUS allowing the 7 paths to be used:
#index# GET /dogs
#show# GET /dogs/:id
#new# GET /dogs/new
#create# POST /dogs
#edit# GET /dogs/:id/edit
#update# PATCH /dogs/:id
#detroy# DESTROY /dogs/:id
The only reason we define them within controller ourselves, is because we’re also usually passing values, such as the need to display a particular Dog object by saying:
def show
@dog = Dog.find(params[:id])
end
Our view also needs that object — we’re not just trying to say “Hello!” to someone.
If we were trying to make some more complex assocations, we could do something like :
rails g resource Dog name owner:belongs_to toys:has_many --no-test-frameworkrails g resource Owner name dogs:has_many --no-test-frameworkrails g resource Toy name dog:belongs_to --no-test-framework
In addition to everything we’ve talked about, within our models, the associations will also be defined:
class Dog
belongs_to :owner
has_many :toys
end
And voila! You’re ready to start coding within your pre-designated files and folders!
Using this generator will create a little extra fluff for us, but we needn’t worry about that for now. Just as long as you use the appropriate generators and understand their capabilities, you’ll be creating projects even faster than before.
Take care.