0

私のアプリには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()開発モードでキャッシングが行われる方法のために、呼び出しがあります。それは機能しますが、それは本当に醜いです-私がそれをしている理由の説明については、この質問を参照してください。

これを行うためのより良い/より信頼できる方法はありますか?

4

1 に答える 1

0

John Gibbがコメントで述べたように、あなたの主な問題はセキュリティです。承認されたホワイトリストでクラスをフィルタリングする必要があります。

あなたがコメントで与えた解決策も完璧ではありません。最初にMeteredServiceのインスタンスが作成され、次に別のクラスの名前でテキストプロパティを変更するだけです。使用しているインスタンスは引き続き基本クラスです。たとえば、降順のクラスでいくつかの検証を定義する場合、これはいくつかの問題につながる可能性があります。

このようなことをします:

AVAILABLE_CLASSES = {"PGEResidential" => PGEResidential,
                     "SCEResidential" => SCEResidential } # You may automatize this

def create
  #....
  class_name = params["metered_service"].delete("class")
  if c = AVAILABLE_CLASSES[class_name]
    @metered_service = c.new(params[:met...
  else
    handle_error_somehow
  end
  ...
于 2011-05-25T07:13:45.697 に答える