我有2个模型,Category
和LineItemTypes
两者已经存在很多,现在需要将它们联系起来。每个类别都有许多LineItemType。
我在accepts_nested_attributes_for :line_item_types
Category
我尝试在表单上使用hidden_field
来创建现有关联LineItemTypes
的列表:
- form_for @category do |form|
%ul#categorised
- form.fields_for :line_item_types do |line_item_types|
-categorised.each do |l|
%li
=l.description
=line_item_types.hidden_field :category_id
=form.submit
如果我在该列表中添加项目,则会收到错误消息,指出无法找到该类别的LineItemType。我认为accepts_nested_attributes_for会添加关联,如果它不存在。或者仅用于“创建”新记录和修改现有关系,而不是创建新关系。
a.update_attributes({:line_item_types_attributes => [{:id => 2767}, {:id => LineItemType.find(2).id}]})
ActiveRecord::RecordNotFound: Couldn't find LineItemType with ID=2 for Category with ID=1
任何想法,而不必写一些东西来遍历结果形式参数并创建关联?或者更简单的方法来实现这个目标?
答案 0 :(得分:2)
我得出的结论是,accept_nested_attributes_for的工作方式有点像url_for ...... ID的存在使得它假设关系存在。渲染accepts_nested_attributes_for不适合我想做的事。
我使用之前的过滤器解决了这个问题:
def find_line_item_types
params[:category][:line_item_types] = LineItemType.find(params[:category][:line_item_types].collect { |a| a[0].to_i }) if params[:category] and params[:category][:line_item_types]
end
答案 1 :(得分:0)
不能在没有在line_item_types属性中指定category_id的情况下从Category实例创建line_item_types!
你应该检查你的has_many和belongs_to声明中是否有:inverse_of选项。
# in Category
has_many :line_item_types, :inverse_of => :category
# In LineItemType
belongs_to :category, :inverse_of => :line_item_types
告诉我这是否有帮助。
答案 2 :(得分:0)
好吧,我遇到了同样的问题,所以我搜索了源码并修补了accepts_nested_attributes_for
以允许这种行为...
https://gist.github.com/2223565
它看起来很多,但实际上我只修改了几行:
module ActiveRecord::NestedAttributes::ClassMethods
def accepts_nested_attributes_for(*attr_names)
# ...
#options.assert_valid_keys(:allow_destroy, :reject_if, :limit, :update_only)
options.assert_valid_keys(:allow_destroy, :reject_if, :limit, :update_only, :allow_existing)
# ...
end
end
和...
module ActiveRecord::NestedAttributes
def assign_nested_attributes_for_collection_association(association_name, attributes_collection, assignment_opts = {})
# ...
#existing_records = if association.loaded?
# association.target
#else
# attribute_ids = attributes_collection.map {|a| a['id'] || a[:id] }.compact
# attribute_ids.empty? ? [] : association.scoped.where(association.klass.primary_key => attribute_ids)
#end
existing_records = if options[:allow_existing] or not association.loaded?
attribute_ids = attributes_collection.map {|a| a['id'] || a[:id] }.compact
scope = options[:allow_existing] ? association.target_scope : association.scoped
scope.where(association.klass.primary_key => attribute_ids)
else
association.target
end
# ...
end
end