accepts_nested_attributes_for
とのポリモーフィック関係を設定したいのですが。これがコードです:
class Contact <ActiveRecord::Base
has_many :jobs, :as=>:client
end
class Job <ActiveRecord::Base
belongs_to :client, :polymorphic=>:true
accepts_nested_attributes_for :client
end
Job.create(..., :client_attributes=>{...}
にアクセスしようとすると、NameError: uninitialized constant Job::Client
が表示されます
Railsはこの種の動作をサポートしていないため、次の回避策を考え出しました。
class Job <ActiveRecord::Base
belongs_to :client, :polymorphic=>:true, :autosave=>true
accepts_nested_attributes_for :client
def attributes=(attributes = {})
self.client_type = attributes[:client_type]
super
end
def client_attributes=(attributes)
self.client = type.constantize.find_or_initialize_by_id(attributes.delete(:client_id)) if client_type.valid?
end
end
これにより、次のようなフォームを設定できます。
<%= f.select :client_type %>
<%= f.fields_for :client do |client|%>
<%= client.text_field :name %>
<% end %>
正確な解決策ではありませんが、アイデアは重要です。
「ArgumentError:関連付けmodel_nameを作成できません。ポリモーフィックな1対1の関連付けを作成しようとしていますか?」にも問題がありました。
そして、私はこの種の問題のより良い解決策を見つけました。ネイティブメソッドを使用できます。 Rails3内のnested_attributes実装を見てみましょう。
elsif !reject_new_record?(association_name, attributes)
method = "build_#{association_name}"
if respond_to?(method)
send(method, attributes.except(*UNASSIGNABLE_KEYS))
else
raise ArgumentError, "Cannot build association #{association_name}. Are you trying to build a polymorphic one-to-one association?"
end
end
では、実際にここで何をする必要があるのでしょうか。モデル内にbuild _#{association_name}を作成するだけです。私は下部で完全に機能する例を実行しました:
class Job <ActiveRecord::Base
CLIENT_TYPES = %w(Contact)
attr_accessible :client_type, :client_attributes
belongs_to :client, :polymorphic => :true
accepts_nested_attributes_for :client
protected
def build_client(params, assignment_options)
raise "Unknown client_type: #{client_type}" unless CLIENT_TYPES.include?(client_type)
self.client = client_type.constantize.new(params)
end
end
私finallyはこれをRails 4.x. +1します。
STEP 1。はじめに、多態的な関連付けを含む完全なモデルを次に示します。
# app/models/polymorph.rb
class Polymorph < ActiveRecord::Base
belongs_to :associable, polymorphic: true
accepts_nested_attributes_for :associable
def build_associable(params)
self.associable = associable_type.constantize.new(params)
end
end
# For the sake of example:
# app/models/chicken.rb
class Chicken < ActiveRecord::Base
has_many: :polymorphs, as: :associable
end
はい、それは本当に新しいことではありません。ただし、polymorph_type
はどこから来て、その値はどのように設定されるのでしょうか。ポリモーフィックな関連付けが<association_name>_id
および<association_name>_type
列をテーブルに追加するため、これは基礎となるデータベースレコードの一部です。現状では、build_associable
を実行すると、_type
の値はnil
になります。
ステップ2.子タイプを渡して受け入れる
フォームビューでchild_type
を一般的なフォームデータとともに送信し、コントローラーは強力なパラメーターチェックでそれを許可する必要があります。
# app/views/polymorph/_form.html.erb
<%= form_for(@polymorph) do |form| %>
# Pass in the child_type - This one has been turned into a chicken!
<%= form.hidden_field(:polymorph_type, value: 'Chicken' %>
...
# Form values for Chicken
<%= form.fields_for(:chicken) do |chicken_form| %>
<%= chicken_form.text_field(:hunger_level) %>
<%= chicken_form.text_field(:poop_level) %>
...etc...
<% end %>
<% end %>
# app/controllers/polymorph_controllers.erb
...
private
def polymorph_params
params.require(:polymorph).permit(:id, :polymorph_id, :polymorph_type)
end
もちろん、ビューは「関連付け可能」であるさまざまなタイプのモデルを処理する必要がありますが、これは1つを示しています。
これが誰かを助けることを願っています。 (とにかく多形の鶏が必要なのはなぜですか?)
上記の答えは素晴らしいですが、示されている設定では機能しません。それは私にインスピレーションを与え、私は実用的なソリューションを作成することができました:
作成と更新のための作品
class Job <ActiveRecord::Base
belongs_to :client, :polymorphic=>:true
attr_accessible :client_attributes
accepts_nested_attributes_for :client
def attributes=(attributes = {})
self.client_type = attributes[:client_type]
super
end
def client_attributes=(attributes)
some_client = self.client_type.constantize.find_or_initilize_by_id(self.client_id)
some_client.attributes = attributes
self.client = some_client
end
end