59

とのポリモーフィックな関係を設定したいと思い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

4

4 に答える 4

63

「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
于 2011-08-08T22:29:31.333 に答える
22

最終的にRails 4.xで動作するようになりました。これは Dmitry/ScotterC の回答に基づいているため、+1 します。

ステップ 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です。

STEP 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 つを示しています。

これが誰かを助けることを願っています。(とにかく多形ニワトリが必要なのはなぜですか?)

于 2015-10-02T20:29:47.463 に答える
8

上記の答えは素晴らしいですが、示されているセットアップでは機能しません。それは私にインスピレーションを与え、実用的なソリューションを作成することができました:

作成と更新のために機能します

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
于 2011-08-04T10:04:54.050 に答える
5

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 %>

正確な解決策ではありませんが、アイデアは重要です。

于 2010-10-20T07:51:18.113 に答える