The blog of Rahoul Baruah from 3hv Ltd

What's going on?

My name is Rahoul Baruah (aka Baz) and I'm a software developer in Leeds (England).

This is a log of things I've discovered while writing software in Ruby on Rails. In other words, geek stuff.

However, I've decided to put this blog on ice - I would ask you to check out my business blog here (or subscribe here).

23 April, 2007

Can you use the same controller in two places at once?

I'm currently wrestling with a problem. My application has Attendees that either belong to PrivateCourses or Bookings. It uses a polymorphic association for this: has_many :attendees, :as => :attendable.

However, in both cases the UI is pretty much identical. So I figured I could set up routes like so:


map.resources :private_courses do | private_course |
private_course.resources :attendees, :name_prefix => 'private_course_'
end
map.resources :bookings do | booking |
booking.resources :attendees, :name_prefix => 'booking_'
end
map.resources :attendees


This gives me three options: either reference the attendee in the context of a PrivateCourse private_course_attendees_path(@private_course), in the context of a Booking booking_attendee_path(@booking) or all on its own attendee_path(@attendee). I was thinking I could examine the supplied parameters to figure out what the Attendable should be:


if !params[:booking_id].blank?
@attendable = Booking.find params[:booking_id]
elsif !params[:private_course_id].blank?
@attendable = PrivateCourse.find params[:private_course_id]
end
if @attendable.blank?
@attendee = Attendee.find params[:id]
else
@attendee = @attendable.attendees.find params[:id]
end


Looks good so far.

But it turns out my view code is turning into a conditional nightmare. Take the "new" form:


if @attendee.attendable.is_a?(PrivateCourse)
form_for :attendee, :url => private_course_new_attendee_path(@attendee.attendable) do | form |
...
end
else
form_for :attendee, :url => booking_new_attendee_path(@attendee.attendable) do | form |
...
end
end


Of course, not only is this ugly but there needs to be code in the controller to set up the new Attendee's Attendable. In which case I should just make the controller look like this:


@attendee = @attendable.attendees.build
if @attendable.is_a?(PrivateCourse)
render :action => 'new_attendee_for_private_course'
else
render :action => 'new_attendee_for_booking'
end


Yet as I went through this, I kept thinking that every single action needs the same conditional logic - actual form definitions aside, there is actually nothing that is shared between the two conditions.

So, my answer, barring a flash of inspiration, is "No, you cannot use the same controller in two places at once".

Now I need to rework my body of code to have two controllers - PrivateCourseAttendees and BookingAttendees that both make use of a set of shared partials, probably in an Attendees folder.

2 comments:

Ian said...

We've been wresting with similar issues.

Check out resources_controller at http://plugins.ardes.com

Baz said...

Cheers Ian,

That looks useful (although it could do with an overview page!)

eXTReMe Tracker