Reputation: 111
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:inraise_validation_error'
save!' from /Users/pauldavis/.rvm/gems/ruby-2.2.4/bundler/gems/rails-b785064958f9/activerecord/lib/active_record/attribute_methods/dirty.rb:30:in
from /Users/pauldavis/.rvm/gems/ruby-2.2.4/bundler/gems/rails-b785064958f9/activerecord/lib/active_record/validations.rb:50:insave!' from /Users/pauldavis/.rvm/gems/ruby-2.2.4/bundler/gems/rails-b785064958f9/activerecord/lib/active_record/transactions.rb:324:in
block in save!' from /Users/pauldavis/.rvm/gems/ruby-2.2.4/bundler/gems/rails-b785064958f9/activerecord/lib/active_record/transactions.rb:395:inblock 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:in
block 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:inwithin_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:in
transaction' from /Users/pauldavis/.rvm/gems/ruby-2.2.4/bundler/gems/rails-b785064958f9/activerecord/lib/active_record/transactions.rb:211:intransaction' from /Users/pauldavis/.rvm/gems/ruby-2.2.4/bundler/gems/rails-b785064958f9/activerecord/lib/active_record/transactions.rb:392:in
with_transaction_returning_status' from /Users/pauldavis/.rvm/gems/ruby-2.2.4/bundler/gems/rails-b785064958f9/activerecord/lib/active_record/transactions.rb:324:insave!' from /Users/pauldavis/.rvm/gems/ruby-2.2.4/bundler/gems/rails-b785064958f9/activerecord/lib/active_record/suppressor.rb:45:in
save!' from (irb):14 from /Users/pauldavis/.rvm/gems/ruby-2.2.4/bundler/gems/rails-b785064958f9/railties/lib/rails/commands/console.rb:65:instart' from /Users/pauldavis/.rvm/gems/ruby-2.2.4 /bundler/gems/rails-b785064958f9/railties/lib/rails/commands/console_helper.rb:9:in
start' (0.2ms) ROLLBACK from /Users/pauldavis/.rvm/gems/ruby-2.2.4/bundler/gems/rails-b785064958f9/railties/lib/rails/commands/commands_tasks.rb:78:inconsole' from /Users/pauldavis/.rvm/gems/ruby-2.2.4/bundler/gems/rails-b785064958f9/railties/lib/rails/commands/commands_tasks.rb:49:in
run_command!' from /Users/pauldavis/.rvm/gems/ruby-2.2.4/bundler/gems/rails-b785064958f9/railties/lib/rails/command.rb:20:inrun' 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:inrequire' from /Users/pauldavis/Documents/Projects/Active/Rails/curious/doko/m.0/test_anaf/bin/rails:9:in
' from -e:1:inload' 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
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
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
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
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
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