私のアプリにはSTIモデルがあります:
# 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
およびSTIをサポートするスキーマ:
# file: db/schema.rb
create_table "metered_services", :force => true do |t|
t.integer "premise_id"
t.string "type"
end
MeteredServiceはネストされたリソースです(ただし、この質問にはあまり関係ありません)。
# file: config/routes.rb
resources :premises do
resources :metered_services
end
これが取引です。MeteredServiceを作成するには、ユーザーはプルダウンリストで多くのサブクラスの1つを選択します。このフォームは、クラス名を文字列としてMeteredServicesController#createに返しparams['metered_services']['class']
ます。次に、適切なサブクラスを作成する必要があります。
私が取っているアプローチはうまくいきます-ある種-しかし、これが最善の方法であるかどうか疑問に思っています:
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
私が行っているのは、クラス名を削除してparams['metered_service']
、残りのパラメーターを使用して従量制サービスを作成できるようにすることです。そして、class_nameは(を介してObject.const_get
)クラスに解決されるので、そのクラスで.newメソッドを呼び出すことができます。
MeteredServices.descendants()
開発モードでキャッシングが行われる方法のために、呼び出しがあります。それは機能しますが、それは本当に醜いです-私がそれをしている理由の説明については、この質問を参照してください。
これを行うためのより良い/より信頼できる方法はありますか?