acts_as_relation icon indicating copy to clipboard operation
acts_as_relation copied to clipboard

Nested form splitting child records across multiple rows

Open sdee opened this issue 10 years ago • 2 comments

Every time I create a nested object that uses multiple table inheritance, two different rows is created for the child object.

I have a has_many relationship between my store and products object and using multiple table inheritance to represent books and other types of products. Every product has a cost attribute and belongs to a store.

class Store < ActiveRecord::Base
    has_many :products, :dependent => :destroy
    has_many :books, :through => :products, :source => :as_product, :source_type => "Book"
    accepts_nested_attributes_for :products, :allow_destroy => true, :reject_if => :all_blank
    accepts_nested_attributes_for :books, :allow_destroy => true, :reject_if => :all_blank
end

class Product < ActiveRecord::Base
     acts_as_superclass
     belongs_to :store
end

class Book < ActiveRecord::Base
     belongs_to :store
     acts_as :product, :include => true
end

When I build a store and nested products via a formtastic form, I end up getting these rows:

+----+----------+---------------+-----------------+------+
| id | store_id | as_product_id | as_product_type | cost |
+----+----------+---------------+-----------------+------+
| 45 |     NULL | 29            | Book            |   17 |
| 46 |       39 | 29            | Book            | NULL |
+----+----------+---------------+-----------------+------+

The association and attribute (cost) gets split across two rows. Any ideas?

The params passed through the form looks normal to me:

 Parameters: {"utf8"=>"✓", "authenticity_token"=>"aHmLdcXZxW/BSU0XIbW7PwGWXNJ2cX42NtMkDCEN7GE=", "store"=>{"name"=>"Borders", "books_attributes"=>{"0"=>{"author"=>"Gaiman", "cost"=>"17.0", "_destroy"=>"false"}}}, "commit"=>"Create Store"}

sdee avatar Mar 14 '14 04:03 sdee

Hi, I'm getting the same weird behaviour. Any luck? (Rails 4.1.0/Ruby 2.1.1)

rkamun1 avatar May 17 '14 08:05 rkamun1

So here's what happens in your case. Do you have cost in your product model? If you do, then what happens is that upon creation of a book, it will run one build model to accommodate for the cost,

@book.product.build 

which doesn't recognize the associated model(Store) and the default

@book = @store.book.build
@product = @book.build_product

which recognises the store and not the cost. Remove cost from your product and keep it in your book and you'll be fine. Assuming that you did this to sort by price, for example, you can the build helper methods to help you do this. eg:

@store.products.collect(&:product).sort{|x,y| x.cost <=> y.cost} 

If you find out how to sort as a default scope, please let me know

rkamun1 avatar May 18 '14 08:05 rkamun1