# Rails partial inheritance hack

I have a STI table and want to be able to render a collection using

render @collection


with every elements of the collection using their own partial or, if they don't have one, the parent partial. You know, partial inheritance.

So I added to my parent model :

def to_partial_path
self.class._to_partial_path
end

protected

# a little hack to get partial inheritance in views, check if the partial exist, if not
# return the parent's one. Provide class level cache, be sure to restart your app when
def self._to_partial_path
@_to_partial_path ||= begin
element = ActiveSupport::Inflector.underscore(ActiveSupport::Inflector.demodulize(self))
collection = ActiveSupport::Inflector.tableize(self)
if File.exists?(Rails.root.join('app', 'views', collection, "_#{element}.html.erb")) ||
self.superclass == ActiveRecord::Base

"#{collection}/#{element}"
else
self.superclass._to_partial_path
end
end
end


The original code is here.

This seems to work great so far but I want to have some opinions.

Should I have gone another way?

Are there any "gotchas" I might encounter doing it this way?

Any way to refactor this?

edit: No problem whatsoever, it's working great for now. I'm looking for a way to achieve something similar with form (ie render form in new and edit views render the child _form partial if their is one, the parent one otherwise).

Another approach would be to sub-class the Renderer and make it responsible for retrieving the base classes' to_partial_path.
• How would you let Rails know that it should use the PartialRenderer subclass? Is their a hook for that (I haven't found one)? May 7, 2014 at 22:36