Looking towards Rails 1.2 with CRUD
A couple of months ago, I was shown the article that DHH(David Heinemeier Hannson) wrote after he gave his presentation at RailsConf 2006. I looked at it then and kind of shrugged it off, mainly because I really didn't know what the presentation was really about.
Tonight I found video of that presentation and I got excited about CRUD(Create, Read, Update, Delete). It pointed out that I've been making some controllers a little bloated. I have coupled much functionality into one controller; when looking back, I clearly could have separated out some functionality.
Learning to love has_many :through
even more with CRUD
One of the points about this is that the coupling often happens when you have models that are joined by a table, like in a HABTM(has_many_and_belongs_to) relationship. The table that joins the two other tables as an amorphous name, whose role changes depending on which side of the join table you are looking. has_many :through
fixes this ambiguity as it gives a name to a new model, and thus a new domain to think about creating clean uses of CRUD. An example will make this much clearer.
The non-CRUD way
class Author < ActiveRecord::Base
has_and_belongs_to_many :books
end
class Book < ActiveRecord::Base
has_and_belongs_to_many :authors
end
Let's say I have a AuthorController
and we want to add books to an author, or remove a book from an author, we could write the following.
class AuthorController < ApplicationController
def add_book
end
def remove_book
end
end
This doesn't seem that harmless, but what if we wanted to add authors to a book?
class BookController < ApplicationController
def add_author
end
def remove_author
end
end
This does not follow the ways of DRY(Don't Repeat Yourself), because depending on which side of the coin you are looking at, you have two different ways to accomplish pretty much the same thing.
Enter has_many :through
DHH points out that if we can identify the link between Authors and Books, there will be a new a less ambiguous and more elegant way to think about this issue. The link to identify here is Authorship. Now let's change our models some.
class Author < ActiveRecord::Base
has_many :authorships
has_many :books, :through => :authorships
end
class Authorship < ActiveRecord::Base
belongs_to :author
belongs_to :book
end
class Book < ActiveRecord::Base
has_many :authorships
has_many :authors, :through => :authorships
end
Because the link has been identified, a controller can be created with the ideals of CRUD put right into place.
class AuthorshipController < ApplicationController
def create
#Authorship.create(:author_id => params[:author_id], :book => params[:book_id])
end
def destroy
end
end
Everything is right with the world again
POST, GET, PUT, DELETE
The other big thing that was mentioned was mapping CRUD functionality to HTTP(hypertext transfer protocol) method definitions: POST, GET, PUT, and DELETE respectively. The HTTP method acts as the verb for what the controller should do. Here is the basic outline, the comments are how things fit into the lovely world the the HTTP methods as verbs:
class SomethingController < ApplicationController
# POST /something
def create
end
# GET /something/1
def show
end
# PUT /something/1
def update
end
# DELETE /people/1
def destroy
end
end
Since browsers don't use PUT or DELETE, Rails has a hack for this; it's going to send hidden fields with the actions so that the mappings know how to handle everything. Those methods aren't the only ones that are apart of the CRUD; there are other ones that are common to most controllers:
class SomethingController < ApplicationController
# GET /something
def index
end
# GET /something;new
def new
end
# GET /something/1;edit
def edit
end
end
index
is responsible for listing all of the somethings, while new
and edit
are how users first start their journey to creating or updating something.
Clarity in this layout isn't the other reason to use this. The other reason Rails is going to be embracing REST(Representational State Transfer) ideals into the way Rails will route your URLs. More on this later when I dive deeper into it.
Because of this presentation, I'm thinking about how I'm doing my controllers. I usually don't have this type of setup, but I am definitely going to start using it. From now on, I will not be afraid do use the command script/generate controller Something index new create show edit update destroy
and start to think about controllers from a CRUD perspective rather than creating more monolithic controllers, and to be ready for when Rails 1.2 comes in full effect.
Comments
comments powered by Disqus