用belongs_to多态来接受belongs_nested_attributes_for

我想build立一个与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:无法build立关联模型名称”的问题,您是否尝试build立多态一对一关联?

我发现了一个更好的解决这类问题的方法。 你可以使用本地方法。 让我们看看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 

上面的答案很好,但不能与所示的设置一起工作。 它激发了我,我能够创造一个工作解决scheme:

适用于创build和更新

 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 

终于得到这个与Rails 4.x的工作。 这是基于德米特里/斯科特的答案,所以+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从哪里来,它的值是如何设置的呢? 它是基础数据库logging的一部分,因为多态关联将<association_name>_id<association_name>_type列添加到表中。 就目前来看,当build_associable执行时, _type的值是nil

步骤2.传入并接受子types

让你的表单视图发送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 

当然,您的视图将需要处理“可关联”的不同types的模型,但这只是一个例子。

希望这可以帮助那里的人。 (为什么你需要多形鸡?)

只是想出了轨道不支持这种行为,所以我想出了以下解决方法:

 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 

这让我设置我的forms是这样的:

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

不是确切的解决scheme,但这个想法很重要。

Interesting Posts