My app has an STI model:
# file: app/models/metered_service.rb
class MeteredService < ActiveRecord::Base
...
end
# file: app/models/metered_services/pge_residential.rb
class PGEResidential < MeteredService
...
end
# file: app/models/metered_services/sce_residential.rb
class SCEResidential < MeteredService
...
end
and a schema that support STI:
# file: db/schema.rb
create_table "metered_services", :force => true do |t|
t.integer "premise_id"
t.string "type"
end
MeteredService is a nested resource (though that's not really relevant to this question):
# file: config/routes.rb
resources :premises do
resources :metered_services
end
So here's the deal: To create a MeteredService, the user chooses one of its many sub-classes in a pulldown list. The form returns the class name to the MeteredServicesController#create in params['metered_services']['class']
as a string. Now we need to create the proper subclass.
The approach I'm taking works - sort of - but I'm wondering if this is the best way:
def create
@premise = Premise.find(params[:premise_id])
MeteredService.descendants() # see note
class_name = params["metered_service"].delete("class")
@metered_service = Object.const_get(class_name).new(params[:metered_service].merge({:premise_id => @premise.id}))
if @metered_service.save
... standard endgame
end
end
What I'm doing is stripping the class name out of params['metered_service']
so I can use the remaining parameters to create the metered service. And the class_name is resolved to a class (via Object.const_get
) so I can call the .new method on it.
The MeteredServices.descendants()
call is there because of the way caching is done in development mode. It works, but it's really ugly - see this question for an explanation of why I'm doing it.
Is there a better / more reliable way to do this?