Question

I have 2 models, Category and LineItemTypes

There are already plenty existing of both, it is now a requirement for them to be associated. Being many LineItemTypes for every Category.

I have added accepts_nested_attributes_for :line_item_types on Category

I've tried using a hidden_field on a form to create a list of existing associated 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

If I add an item to that list, I get errors saying that a LineItemType for that Category can't be found. I thought accepts_nested_attributes_for would add the association if it doesn't exist. Or is it only for 'creating' new records and modifying existing relationships, not creating new relationships.

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

Any ideas without having to write something to traverse the resulting form params and create the associations? Or an even easier way to achieving this?

Was it helpful?

Solution

I've come to the conclusion that accepts_nested_attributes_for works kinda like url_for... Where the presence of ID makes it assume the relationship exists. Rendering accepts_nested_attributes_for not suitable for what I want to do.

I've worked around this with a before filter:

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

OTHER TIPS

no you should be able to create line_item_types from a Category instance without specifying the category_id in the line_item_types attributes!

You should check that you got the :inverse_of option in your has_many and belongs_to declarations.

# in Category
has_many :line_item_types, :inverse_of => :category

# In LineItemType
belongs_to :category, :inverse_of => :line_item_types

Tell me if that helps.

Well, I had the same issue, so I searched into the source and monkey patched accepts_nested_attributes_for to allow this behavior...

https://gist.github.com/2223565

It looks like a lot, but I actually just modified a few lines:

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

And...

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
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top