Alex Rivera | Logout

STI, one controller

Asked 2011-03-09T13:54:06.940
60

I'm new to rails and I'm kind of stuck with this design problem, that might be easy to solve, but I don't get anywhere: I have two different kinds of advertisements: highlights and bargains. Both of them have the same attributes: title, description and one image (with paperclip). They also have the same kind of actions to apply on them: index, new, edit, create, update and destroy.

I set a STI like this:

Ad Model: ad.rb

class Ad < ActiveRecord::Base
end

Bargain Model: bargain.rb

class Bargain < Ad
end

Highlight Model: highlight.rb

class Highlight < Ad
end

The problem is that I'd like to have only one controller (AdsController) that executes the actions I said on bargains or highlights depending on the URL, say www.foo.com/bargains[/...] or www.foo.com/highlights[/...].

For example:

  • GET www.foo.com/highlights => a list of all the ads that are highlights.
  • GET www.foo.com/highlights/new => form to create a new highlight etc...

How can i do that?

Thanks!

Edit
Report

1 Answer

65

fl00r has a good solution, however I would make one adjustment.

This may or may not be required in your case. It depends on what behavior is changing in your STI models, especially validations & lifecycle hooks.

Add a private method to your controller to convert your type param to the actual class constant you want to use:

def ad_type
  params[:type].constantize
end

The above is insecure, however. Add a whitelist of types:

def ad_types
  [MyType, MyType2]
end

def ad_type
  params[:type].constantize if params[:type].in? ad_types
end

More on the rails constantize method here: http://api.rubyonrails.org/classes/ActiveSupport/Inflector.html#method-i-constantize

Then in the controller actions you can do:

def new
  ad_type.new
end

def create
  ad_type.new(params)
  # ...
end

def index
  ad_type.all
end

And now you are using the actual class with the correct behavior instead of the parent class with the attribute type set.

answered 2011-03-10T03:07:07.300

Your Answer