programing

belongs_to 다형성과 함께 accepts_nested_attributes_for

copyandpastes 2021. 1. 14. 23:34
반응형

belongs_to 다형성과 함께 accepts_nested_attributes_for


나는 다형성 관계를 설정하고 싶습니다 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


또한 "ArgumentError : Cannot build association model_name. 다형성 일대일 연결을 구축하려고합니까?"라는 문제가있었습니다.

그리고 저는 이런 종류의 문제에 대한 더 나은 해결책을 찾았습니다. 기본 방법을 사용할 수 있습니다. 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

나는 마침내 레일 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

물론, 당신의 뷰는 '연관 가능'한 다양한 유형의 모델을 처리해야하지만 이것은 하나를 보여줍니다.

이것이 누군가를 돕기를 바랍니다. (왜 다형성 닭이 필요한가요?)


The above answer is great but not working with the setup shown. It inspired me and i was able to create a working solution:

works for creating and updating

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

Just figured out that rails does not supports this kind of behavior so I came up with the following workaround:

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

This gives me to set up my form like this:

<%= f.select :client_type %>
<%= f.fields_for :client do |client|%>
  <%= client.text_field :name %>
<% end %>

Not the exact solution but the idea is important.

ReferenceURL : https://stackoverflow.com/questions/3969025/accepts-nested-attributes-for-with-belongs-to-polymorphic

반응형