April 15, 2009
6 Comments
The Rails Way
These days I am trying to accomplish one of my 2009 New Year’s resolutions: Learn Ruby on Rails and be able to prototype, code and design one functional web application (you know, I’m in exams time…)
I have already worked with Ruby on Rails before, but only from the designer’s point of view: being able to implement my designs without the application to crash. Anyway the workflow with RoR, the philosophy behind and its singularities definitely definitely hooked me. Furthermore I must say to my own shame that I have only coded in C programming language in order to pass my practical lessons at the University.
To gain an insight into what I am talking about let’s face a real problem with which I had to deal while I am building this application.
Users must be able to register in the application, that will create a visit card for them with their data. One of the RoR conventions is the MVC architecture pattern that ensures the DRYness of your code (that’s a bunch of acronyms!). This is the piece of code from the Controller that was in charge of that (I am taking for granted some knowledge about these terms; if not, go Google them as I did before because they are really easy to understand):
/app/controllers/users_controller.rb
class UsersController < ApplicationController
def create
@user = User.new(params[:user])
@card = Card.new
@card.user_id = @user.id
@card.title = "Visit card of #{@user.login}"
if @user.save && @card.save
flash[:notice] = "Account registered!"
redirect_back_or_default account_url
else
render :action => :new
end
end
end
In RoR, there are always some mantras that one must follow in order to program good pieces of code, this way we will end up with an application that has everything in its right place and works properly. One of these mantras is Skinny Controller Fat Model, which says that many of our business logic must be in the Model instead of the Controller. So taking a look at our code we know we are not doing it well.
We can move some of the code from the Controller to the Model making use of the callback after_create. There is a good documentation about that and other people with much more talent than I have already written about this.
/app/controllers/users_controller.rb
class UsersController < ApplicationController
def create
@user = User.new(params[:user])
if @user.save
flash[:notice] = "Account registered!"
redirect_back_or_default account_url
else
render :action => :new
end
end
end
/app/models/user.rb
class User < ActiveRecord::Base
has_one :card
after_create :create_card
protected
def create_card
Card.create :user_id => id, :title => "Visit card of #{login}"
end
end
But there’s even a better solution because having card creation code in the user controller doesn’t make much sense. Here is where observers come, “a great way to reduce the clutter that normally comes when the model class is burdened with functionality that doesn‘t pertain to the core responsibility of the class” as once again the documentation says. There’s also a very good article about this in Spanish. So we have to move the card creation to an user Observer, that handles it everytime an user is registered.
/app/models/user.rb
class User < ActiveRecord::Base has_one :card end
/app/controllers/user_observer.rb
class UserObserver < ActiveRecord::Observer
def after_create(user)
Card.create :user_id => user.id, :title => "Visit card of #{user.login}"
end
end
This is “the rails way”, Skinny Model Skinny Controller.
Finally I want to give thanks to the ror-es mailing list I signed up recently. I had the luck to work with some of the better rails developers in my past projects and now I have discovered that not only they were great but also the vast majority behind Ruby on Rails community is awesome. Thank you guys.
Update: I was using the restful_authentication plugin in order to manage the users authentication in the app, but as the comments say this is not the best solution. I have updated the code in order to handle this with the authlogic plugin, which is much better.
Category: Ones and Zeros
Tagged: piwid, rails, ruby, ruby on rails

In my humble opinion, it would be a good idea to get to grips with ruby before writing too much Rails. Your code shows clear signs of strong type language habits (are you sure you want to be so defensive on your create method?). The gap between C and Ruby it’s quite big, so don’t be fooled thinking it will happen overnight.
Another thing related to codding, and with everything else, is love. In this, case love for the awesome community Ruby and Rails have. Don’t be afraid to show your love for the people who really guide you to the process your article is talking about (not me BTW), like the folks on the ror-es list, instead of linking the same articles from Obie, Jamis, etc that everybody has already read or is going to do so anyway.
Hi loki, first of all I will add that link as soon as I end writting this comment. Take for granted my intention is not leave their credit behind and I have also thanked them so much in the mailing list. I just skipped it, sorry
About getting to grips with ruby I am reading the “Agile Web Development with Rails” and every document I think is worth to spend some minutes to read (some examples http://delicious.com/matallo/rails) but I will be so grateful if somebody more experienced could give me advise about some resources to help my rails learning. No way I think I will wake up one morning knowing rails!
Anyway, most of the code comes with the restful_authentication plugin, but I think I will have to refactor it a bit and adapt it for my needs.
Thanks for your wisdom.
hi,
I think there is one point where you could refactor your code a little bit. You are using this piece of code to check everything went ok while recording the user:
success = @user && @user.save
if success && @user.errors.empty?
why not just use the #save method? It has no sense to check if the @user variable is a nil or not because it will *never* be because you have instantiated it just one line above.
Eventually, when the #save method returns a true value, it means that everything went fine and there are no errors, so it’s a little bit redundant to check if the errors list is empty or not:
if @user.save
...
It makes a lot of sense. I didn’t modified t because it came with the restful_authentication plugin and I thought if I changed something the user authentication wouln’t work. Anyway I will refactor it, thanks for the advise.
I think The Ruby Programming Language is a “must read”. Everybody will tell you to have the The Rails Way so I will point you to something completely different, but as valuable as anything else. called The Pragmatic Programmer.
For the authentication process in your Rails apps, all the cool kids are switching to authlogic because of the better and more understandable code base.
I have not wisdom but I’m damn hot. You can’t have it all. ^_^
[...] really felt like taking part in such an event while commiting (nice word, huh?) one of my new year’s resolutions, so I proposed this to Felipe Talavera one of my partners in the startup we cofounded almost a year [...]