Reputation: 65
I am just experiment with Rails 5, and came upon the accepts_nested_attributes_for. But I cannot get it to work. What am I doing wrong?
Here are my Models:
Here are the SQL Table Definitions
Model Code
class Person < ApplicationRecord
has_many :activities
accepts_nested_attributes_for :activities
end
class Activity < ApplicationRecord
belongs_to :person
end
Reading the API Docs (accepts_nested_attributes_for)
I created a params hash, and try to submit it to the Person Class.
params = {person: {name: 'Joe', activities_attributes: [{description: "Hiking"}]} }
When I try to Run this particular code, instead of creating a new person record named "Joe", and new association record under activities for "Hiking", it simple fails.
>> params = {person: {name: 'Joe', activities_attributes: [{description: "Hiking"}]} }
{:person=>{:name=>"Joe", :activities_attributes=>[{:description=>"Hiking"}]}}
>> Person.create(params[:person])
(12.6ms) BEGIN
(0.6ms) ROLLBACK
#<Person id: nil, name: "Joe", age: nil, adult: nil, created_at: nil, updated_at: nil>
But doing it one step at a time seems to work fine:
>> Person.create(:name => "Joe")
(6.3ms) BEGIN
SQL (31.6ms) INSERT INTO "people" ("name", "created_at", "updated_at") VALUES ($1, $2, $3) RETURNING "id" [["name", "Joe"], ["created_at", 2016-07-13 19:30:35 UTC], ["updated_at", 2016-07-13 19:30:35 UTC]]
>> a = Person.first
Person Load (9.1ms) SELECT "people".* FROM "people" ORDER BY "people"."id" ASC LIMIT $1 [["LIMIT", 1]]
#<Person id: 35, name: "Joe", age: nil, adult: nil, created_at: "2016-07-13 19:30:35", updated_at: "2016-07-13 19:30:35">
>> a.activities_attributes = [{:name => "Hiking"}]
[{:name=>"Hiking"}]
>> a.save
(0.2ms) BEGIN
Person Load (0.6ms) SELECT "people".* FROM "people" WHERE "people"."id" = $1 LIMIT $2 [["id", 35], ["LIMIT", 1]]
SQL (13.0ms) INSERT INTO "activities" ("person_id", "name", "created_at", "updated_at") VALUES ($1, $2, $3, $4) RETURNING "id" [["person_id", 35], ["name", "Hiking"], ["created_at", 2016-07-13 19:31:02 UTC], ["updated_at", 2016-07-13 19:31:02 UTC]]
(6.8ms) COMMIT
true
>> a
#<Person id: 35, name: "Joe", age: nil, adult: nil, created_at: "2016-07-13 19:30:35", updated_at: "2016-07-13 19:30:35">
>> a.activities
Activity Load (12.4ms) SELECT "activities".* FROM "activities" WHERE "activities"."person_id" = $1 [["person_id", 35]]
#<ActiveRecord::Associations::CollectionProxy [#<Activity id: 7, person_id: 35, name: "Hiking", created_at: "2016-07-13 19:31:02", updated_at: "2016-07-13 19:31:02", description: nil>]>
People Table
testing_development=# \d+ people;
Table "public.people"
Column | Type | Modifiers | Storage | Stats target | Description
------------+-----------------------------+-----------------------------------------------------+----------+--------------+-------------
id | integer | not null default nextval('people_id_seq'::regclass) | plain | |
name | character varying | | extended | |
age | integer | | plain | |
adult | boolean | | plain | |
created_at | timestamp without time zone | not null | plain | |
updated_at | timestamp without time zone | not null | plain | |
Indexes:
"people_pkey" PRIMARY KEY, btree (id)
Activity Table
testing_development=# \d+ activities;
Table "public.activities"
Column | Type | Modifiers | Storage | Stats target | Description
-------------+-----------------------------+---------------------------------------------------------+----------+--------------+-------------
id | integer | not null default nextval('activities_id_seq'::regclass) | plain | |
person_id | integer | | plain | |
name | text | | extended | |
created_at | timestamp without time zone | not null | plain | |
updated_at | timestamp without time zone | not null | plain | |
description | text | | extended | |
Indexes:
"activities_pkey" PRIMARY KEY, btree (id)
"index_activities_on_person_id" btree (person_id)
Upvotes: 4
Views: 3034
Reputation: 8630
Using optional: true
isn't really the right solution - it's a workaround. There is a bug in accepts_nested_attributes_for
in Rails 5 versions prior to 5.1.1. See https://github.com/rails/rails/issues/25198 and Trouble with accepts_nested_attributes_for in Rails 5.0.0.beta3, -api option.
The solution is to use the inverse_of:
option or, better yet, upgrade to Rails 5.1.1.
Upvotes: 0
Reputation: 65
I got it to work, but not sure if this is an error with Rails 5, or just a change in how things are done.
How I got it to work was to see if this problem was isolated to rails 5. I created a Rails 4.2 app, with the same exact code, and it worked.
Once I got it to work, then I looked at the posts online to see if I could find why this was occuring in rails. These are the resources that helped me:
Trouble with accepts_nested_attributes_for in Rails 5.0.0.beta3, -api option
class Post < ApplicationRecord
belongs_to :member, optional: true
end
I added that line, and it worked like a charm.
>> params = {person: {name: "Testing", activities_attributes: [{name: "Testing"}]}}
{:person=>{:name=>"Testing", :activities_attributes=>[{:name=>"Testing"}]}}
>> Person.create(params[:person])
(0.1ms) BEGIN
SQL (6.5ms) INSERT INTO "people" ("name", "created_at", "updated_at") VALUES ($1, $2, $3) RETURNING "id" [["name", "Testing"], ["created_at", 2016-07-13 21:30:45 UTC], ["updated_at", 2016-07-13 21:30:45 UTC]]
SQL (12.5ms) INSERT INTO "activities" ("person_id", "name", "created_at", "updated_at") VALUES ($1, $2, $3, $4) RETURNING "id" [["person_id", 37], ["name", "Testing"], ["created_at", 2016-07-13 21:30:45 UTC], ["updated_at", 2016-07-13 21:30:45 UTC]]
(2.9ms) COMMIT
#<Person id: 37, name: "Testing", age: nil, adult: nil, created_at: "2016-07-13 21:30:45", updated_at: "2016-07-13 21:30:45">
This page shows on what changed in Rails 5 to have this behavior.
http://blog.bigbinary.com/2016/02/15/rails-5-makes-belong-to-association-required-by-default.html
Upvotes: 2