PJD Barna
PJD Barna

Reputation: 111

Trouble with accepts_nested_attributes_for in Rails 5.0.0.beta3, -api option

I am using Rails 5.0.0.beta3, building an API-only app using the -app option on rails new, and I am having trouble with accepts_nested_attributes_for.

In my app, a create (or a new, then a save!) of an object with nested attributes fails, with a message that the parent parent object must exist.

To test, I made a new app and used just the test case with members and posts in the ANAF documentation:

class Member < ApplicationRecord  
  has_many :posts  
  accepts_nested_attributes_for :posts  
end  

and

class Post < ApplicationRecord
 belongs_to :member
end

(These class definitions were generated by the Rails scaffold generator, so the inherit from ApplicationRecord, rather than ActiveRecord::Base, but per this post, that is not significant.)

With those classed defined, and matching migrations created and run, I launch a Rails console and follow the steps in the doc:

params = { member: {
name: 'joe', posts_attributes: [
    { title: 'Kari, the awesome Ruby documentation browser!' },
    { title: 'The egalitarian assumption of the modern citizen' },
    { title: '', _destroy: '1' } # this will be ignored
]}}  

{:member=>{:name=>"joe", :posts_attributes=>[{:title=>"Kari, the awesome Ruby documentation browser!"}, {:title=>"The egalitarian assumption of the modern citizen"}, {:title=>"", :_destroy=>"1"}]}}

And then:

>> member = Member.create(params[:member])
 (0.2ms)  BEGIN
 (0.4ms)  ROLLBACK
#<Member id: nil, name: "joe", created_at: nil, updated_at: nil>

No joy!

When I split the create into new, then save!, I get the same result, with a somewhat clearer error:

>> member = Member.new(params[:member])  
#<Member id: nil, name: "joe", created_at: nil, updated_at: nil>

member.save!
(15.0ms) BEGIN ActiveRecord::RecordInvalid: Validation failed: Posts member must exist
from /Users/pauldavis/.rvm/gems/ruby-2.2.4/bundler/gems/rails-b785064958f9/activerecord/lib/active_record/validations.rb:78:in raise_validation_error'
from /Users/pauldavis/.rvm/gems/ruby-2.2.4/bundler/gems/rails-b785064958f9/activerecord/lib/active_record/validations.rb:50:in
save!' from /Users/pauldavis/.rvm/gems/ruby-2.2.4/bundler/gems/rails-b785064958f9/activerecord/lib/active_record/attribute_methods/dirty.rb:30:in save!' from /Users/pauldavis/.rvm/gems/ruby-2.2.4/bundler/gems/rails-b785064958f9/activerecord/lib/active_record/transactions.rb:324:inblock in save!' from /Users/pauldavis/.rvm/gems/ruby-2.2.4/bundler/gems/rails-b785064958f9/activerecord/lib/active_record/transactions.rb:395:in block in with_transaction_returning_status' from /Users/pauldavis/.rvm/gems/ruby-2.2.4/bundler/gems/rails-b785064958f9/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb:233:inblock in transaction' from /Users/pauldavis/.rvm/gems/ruby-2.2.4/bundler/gems/rails-b785064958f9/activerecord/lib/active_record/connection_adapters/abstract/transaction.rb:189:in within_new_transaction' from /Users/pauldavis/.rvm/gems/ruby-2.2.4/bundler/gems/rails-b785064958f9/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb:233:intransaction' from /Users/pauldavis/.rvm/gems/ruby-2.2.4/bundler/gems/rails-b785064958f9/activerecord/lib/active_record/transactions.rb:211:in transaction' from /Users/pauldavis/.rvm/gems/ruby-2.2.4/bundler/gems/rails-b785064958f9/activerecord/lib/active_record/transactions.rb:392:inwith_transaction_returning_status' from /Users/pauldavis/.rvm/gems/ruby-2.2.4/bundler/gems/rails-b785064958f9/activerecord/lib/active_record/transactions.rb:324:in save!' from /Users/pauldavis/.rvm/gems/ruby-2.2.4/bundler/gems/rails-b785064958f9/activerecord/lib/active_record/suppressor.rb:45:insave!' from (irb):14 from /Users/pauldavis/.rvm/gems/ruby-2.2.4/bundler/gems/rails-b785064958f9/railties/lib/rails/commands/console.rb:65:in start' from /Users/pauldavis/.rvm/gems/ruby-2.2.4 /bundler/gems/rails-b785064958f9/railties/lib/rails/commands/console_helper.rb:9:instart' (0.2ms) ROLLBACK from /Users/pauldavis/.rvm/gems/ruby-2.2.4/bundler/gems/rails-b785064958f9/railties/lib/rails/commands/commands_tasks.rb:78:in console' from /Users/pauldavis/.rvm/gems/ruby-2.2.4/bundler/gems/rails-b785064958f9/railties/lib/rails/commands/commands_tasks.rb:49:inrun_command!' from /Users/pauldavis/.rvm/gems/ruby-2.2.4/bundler/gems/rails-b785064958f9/railties/lib/rails/command.rb:20:in run' from /Users/pauldavis/.rvm/gems/ruby-2.2.4/bundler/gems/rails-b785064958f9/railties/lib/rails/commands.rb:18:in' from /Users/pauldavis/Documents/Projects/Active/Rails/curious/doko/m.0/test_anaf/bin/rails:9:in require' from /Users/pauldavis/Documents/Projects/Active/Rails/curious/doko/m.0/test_anaf/bin/rails:9:in' from -e:1:in load' from -e:1:in'

Any thoughts on why this sample code in the documentation is be working? Could something be wrong in my environment? Does the -api option break something in ActiveRecord? BTW, I am using PostgreSQL

Thanks!

Upvotes: 11

Views: 4632

Answers (5)

Jonathan Allard
Jonathan Allard

Reputation: 19269

This is a regression reported as rails#25198. As was pointed out, you may use inverse_of as a workaround.

It is planned to be fixed in 5.0.1.

Upvotes: 5

Henrique Jensen
Henrique Jensen

Reputation: 419

I had the same problem and I found the solution in https://github.com/rails/rails/issues/18233

Just add

class Post < ApplicationRecord
belongs_to :member, required: false
end

It seems a problem with accepts_nested_attributes_for in Rails 5, so you need add required: false to your child models.

Upvotes: 3

Edward
Edward

Reputation: 3499

I found that adding the inverse_of options to the associations allowed accepts_nested_attributes to work. Nice than monkey patching, still allows the association to be validated

Upvotes: 1

ikad_
ikad_

Reputation: 109

I also encountered the same problem.
It seems specification has been changed from Rails 5.
By putting the option, and the previous and the same operation.

belongs_to should default to required: true #18233

class Post < ApplicationRecord
  belongs_to :member, optional: true
end

It is my clumsy may speak English, but ...

Upvotes: 10

Ilya Bodrov-Krukowski
Ilya Bodrov-Krukowski

Reputation: 581

I am experiencing problems with accepts_nested_attributes_for as well in my Rails 5 beta 3 app and seems like it is buggy. Ideally, a bug report should be submitted, but we didn't have time to do it properly. We have the following setup:

accepts_nested_attributes_for :attachments, allow_destroy: true

Eventually, we had to monkey-patch the method inside the model like this:

  def attachments_attributes=(attributes)
    attributes.reject! do |_attachment|  
      if _attachment = Attachment.find(_attachment['id'])
        if _attachment.drop_id.nil?
          attachments << _attachment
          next true
        end
      end
      next false
    end
    # assign_nested_attributes_for_collection_association(:attachments, attributes)
  end

The only thing is that the last (commented-out line) with assign_nested_attributes_for_collection_association has some issues, but hopefully this will provide you an idea how this can be fixed.

Upvotes: 0

Related Questions