My Rails views and controllers are littered with redirect_to
, link_to
, and form_for
method calls. Sometimes link_to
and redirect_to
are explicit in the paths they're linking (e.g. link_to 'New Person', new_person_path
), but many times the paths are implicit (e.g. link_to 'Show', person
).
I add some single table inheritance (STI) to my model (say Employee < Person
), and all of these methods break for an instance of the subclass (say Employee
); when rails executes link_to @person
, it errors with undefined method employee_path' for #<#<Class:0x000001022bcd40>:0x0000010226d038>
. Rails is looking for a route defined by the class name of the object, which is employee. These employee routes are not defined, and there is no employee controller so the actions aren't defined either.
This question has been asked before:
routes.rb
to map the subclass resources to the parent class (map.resources :employees, :controller => 'people'
). The top answer in that same SO question suggests type-casting every instance object in the codebase using .becomes
routes.rb
, since that only catches routing breakages from link_to
and redirect_to
, but not from form_for
. So he recommends instead adding a method to the parent class to get the subclasses to lie about their class. Sounds good, but his method gave me the error undefined local variable or method `child' for #
.So the answer that seems most elegant and has the most consensus (but it's not all that elegant, nor that much consensus), is the add the resources to your routes.rb
. Except this doesn't work for form_for
. I need some clarity! To distill the choices above, my options are
routes.rb
(and hope I don't need to call form_for on any subclasses)With all these conflicting answers, I need a ruling. It seems to me like there is no good answer. Is this a failing in rails' design? If so, is it a bug that may get fixed? Or if not, then I'm hoping someone can set me straight on this, walk me through the pros and cons of each option (or explain why that's not an option), and which one is the right answer, and why. Or is there a right answer that I'm not finding on the web?
This is the simplest solution I was able to come up with with minimal side effect.
class Person < Contact
def self.model_name
Contact.model_name
end
end
Now url_for @person
will map to contact_path
as expected.
How it works: URL helpers rely on YourModel.model_name
to reflect upon the model and generate (amongst many things) singular/plural route keys. Here Person
is basically saying I'm just like Contact
dude, ask him.