Today, I was building a controller action that was polymorphically finding and associating an object. I could have used a simple dumb solution, such as this:

app/controllers/watches_controller.rb
 1 class WatchesController < ApplicationController
 2   def create
 3     @watch = Watch.build(:watcher => current_person)
 4     @watch.subject = case
 5                      when params[:person_id]
 6                        Person.find(params[:person_id])
 7                      when params[:event_id]
 8                        Event.find(params[:event_id])
 9                      else
10                        raise ArgumentError, "Don't know how to handle other keys... #{params.keys.inspect}"
11                      end
12     @watch.save!
13     flash[:notice] = "You're watching #{@watch.subject.name}"
14     redirect_to root_url
15   end
16 end

That sucked. Really bad. Why did I have to have a case/switch statement in my controller? Why not use a simpler alternative? I could have gone the full polymorphic route too:

app/controllers/watches_controller.rb
 1 class WatchesController < ApplicationController
 2   def create
 3     @watch = Watch.build(:watcher => current_person)
 4 
 5     # For illustration purposes, this is fine, but INSECURE!!!
 6     @watch.subject_type = params[:subject_type]
 7     @watch.subject_id   = params[:subject_id]
 8     @watch.save!
 9 
10     flash[:notice] = "You're watching #{@watch.subject.name}"
11     redirect_to root_url
12   end
13 end

Then, I remembered that my controller was already a ResourceController implementation. I opened up the code and used this instead:

app/controllers/watches_controller.rb
1 class WatchesController < ResourceController::Base
2   belongs_to :person, :event
3 
4   create.before do
5     @watch.watcher = current_person
6     @watch.subject = parent_object
7   end
8 end

I needed to add a bit of infrastructure (some routes and has_many declarations in my models), but those were benefits (I know I’ll need them later anyway). My controller code is simpler, and the intention is clearer, I think.

In the same vein, are you following #standup on Twitter?

Search

Your Host

A picture of me

I am François Beausoleil, a Ruby on Rails and Scala developer. During the day, I work on Seevibes, a platform to measure social interactions related to TV shows. At night, I am interested many things. Read my biography.

Top Tags

Books I read and recommend

Links

Projects I work on

Projects I worked on