Unable to create record via nested attributes Rails API - sql

I'm currently trying to create an Order instance. There is an association of the model Order with Items. The association is as follows. Order has many Items. I try following the documentation https://api.rubyonrails.org/classes/ActiveRecord/NestedAttributes/ClassMethods.html
class Order < ApplicationRecord
has_many :items
accepts_nested_attributes_for :items
end
class OrdersController < ApplicationController
##
private
def order_params
params.require(:order).permit(:description,
items_attributes: [:id, :quantity])
end
end
From the following post, it shows that the id has to be pass in the params. Rails 5 Api create new object from json with nested resource
params = {order: {description: "this is a test"}, items_attributes: [{id: 3, quantity: 3, description: 'within order -> item'}]}
=> {:order=>{:description=>"this is a test"}, :items_attributes=>[{:id=>3, :quantity=>3, :description=>"within order -> item"}]}
[7] pry(main)> order_test = Order.create!(params[:order])
(0.4ms) BEGIN
Order Create (62.9ms) INSERT INTO "orders" ("description", "created_at", "updated_at") VALUES ($1, $2, $3) RETURNING "id" [["description", "this is a test"], ["created_at", "2019-05-30 23:31:39.409528"], ["updated_at", "2019-05-30 23:31:39.409528"]]
(4.6ms) COMMIT
=> #<Order:0x00007ff91556e4b8 id: 14, description: "this is a test", created_at: Thu, 30 May 2019 23:31:39 UTC +00:00, updated_at: Thu, 30 May 2019 23:31:39 UTC +00:00>
I create an order however when I check for the items it returns an empty array.
=> #<Order:0x00007ff9142da590 id: 14, description: "this is a test", created_at: Thu, 30 May 2019 23:31:39 UTC +00:00, updated_at: Thu, 30 May 2019 23:31:39 UTC +00:00>
[11] pry(main)> Order.last.items
Order Load (0.4ms) SELECT "orders".* FROM "orders" ORDER BY "orders"."id" DESC LIMIT $1 [["LIMIT", 1]]
Item Load (0.3ms) SELECT "items".* FROM "items" WHERE "items"."order_id" = $1 [["order_id", 14]]
=> []
Here is the table for items:
class CreateItems < ActiveRecord::Migration[5.2]
def change
create_table :items do |t|
t.references :order, foreign_key: true
t.integer :quantity
t.string :description
t.timestamps
end
end
end
What is wrong?

The mistake was in the order the parameters were being passed.
{:order=>{:id=>22, :description=>"this is a test", :items_attributes=>[{:order_id=>22, :quantity=>3, :description=>"within order -> item"}]}}
This solved it:
order = Order.create!(params[:order])
<Order:0x00007ff918039ee0 id: 22, description: "this is a test", created_at: Fri, 31 May 2019 01:39:23 UTC +00:00, updated_at: Fri, 31 May 2019 01:39:23 UTC +00:00>
[39] pry(main)> order.items
Item Load (114.8ms) SELECT "items".* FROM "items" WHERE "items"."order_id" = $1 [["order_id", 22]]
=> [#<Item:0x00007ff9180394b8
id: 4,
order_id: 22,
quantity: 3,
description: "within order -> item",
created_at: Fri, 31 May 2019 01:39:23 UTC +00:00,
updated_at: Fri, 31 May 2019 01:39:23 UTC +00:00>]

Related

Has many through association with works from console not from controller.

I have a problem with a has_many through association.
Somehow u.groups.create!(:name => "test group", :school => "the school") makes a correct insert with the trace:
(0.1ms) begin transaction SQL (4.5ms) INSERT INTO "groups"
("created_at", "findeble", "name", "school", "updated_at") VALUES (?,
?, ?, ?, ?) [["created_at", Tue, 01 Oct 2013 08:13:36 UTC +00:00],
["findeble", false], ["name", "test group"], ["school", "the school"],
["updated_at", Tue, 01 Oct 2013 08:13:36 UTC +00:00]] SQL (0.3ms)
INSERT INTO "usergroups" ("created_at", "group_id", "updated_at",
"user_id") VALUES (?, ?, ?, ?) [["created_at", Tue, 01 Oct 2013
08:13:36 UTC +00:00], ["group_id", 7], ["updated_at", Tue, 01 Oct 2013
08:13:36 UTC +00:00], ["user_id", 1]] (0.5ms) commit transaction
=> #
But when I try via the groups_controller
# GET /groups/new
# GET /groups/new.json
def new
#group = current_user.groups.new
respond_to do |format|
format.html # new.html.erb
format.json { render json: #group }
end
end
def create
#group = current_user.groups.new(params[:group])
respond_to do |format|
if #group.save
format.html { redirect_to #group, notice: 'Group was successfully created.' }
format.json { render json: #group, status: :created, location: #group }
else
format.html { render action: "new" }
format.json { render json: #group.errors, status: :unprocessable_entity }
end
end
end
This creates the trace:
Started POST "/groups" for 127.0.0.1 at 2013-10-01 10:20:15 +0200
Processing by GroupsController#create as HTML Parameters:
{"utf8"=>"✓",
"authenticity_token"=>"frETQoB5Mu2gLnIBG644i09XDOHFsEBTGEvrEQmfgPA=",
"group"=>{"name"=>"Test group2", "school"=>"Another school",
"findeble"=>"1"}, "commit"=>"Create Group"} User Load (0.2ms)
SELECT "users".* FROM "users" WHERE "users"."id" = 1 LIMIT 1
(0.1ms) begin transaction SQL (0.8ms) INSERT INTO "groups"
("created_at", "findeble", "name", "school", "updated_at") VALUES (?,
?, ?, ?, ?) [["created_at", Tue, 01 Oct 2013 08:20:15 UTC +00:00],
["findeble", true], ["name", "Test group2"], ["school", "Another
school"], ["updated_at", Tue, 01 Oct 2013 08:20:15 UTC +00:00]]
(6.1ms) commit transaction
This only creates a new group record and not a record in the joined table. I cant understand what makes this difference.
You need to use build method:
current_user.groups.build(params[:group])
lol007 is right or you can also do it like that
In new action
#group = current_user.groups.build
And in create action
#group = current_user.groups.create(params[:group])

Rails 3: Delete association duplicates from the database

I've got these models:
class Relationship < ActiveRecord::Base
belongs_to :student
belongs_to :guardian
end
class Student < ActiveRecord::Base
has_many :relationships
has_many :guardians, through: :relationships
end
class Guardian < ActiveRecord::Base
has_many :relationships
has_many :students, through: :relationships
end
I don't want any guardian to be related many times with one student. This can be prevented with a validation, but let's say it's too late and there are case where this is happening. For example, where g is a guardian:
g.relationships
[
[0] #<Relationship:0x0000000bc33650> {
:id => 40321,
:relationship_type_id => 2,
:student_id => 41700,
:guardian_id => 45820,
:created_at => Tue, 23 Apr 2013 17:44:29 UTC +00:00,
:updated_at => Tue, 23 Apr 2013 17:44:29 UTC +00:00,
},
[1] #<Relationship:0x0000000bc32e80> {
:id => 40923,
:relationship_type_id => 2,
:student_id => 41700,
:guardian_id => 45820,
:created_at => Tue, 23 Apr 2013 18:58:46 UTC +00:00,
:updated_at => Tue, 23 Apr 2013 18:58:46 UTC +00:00,
}
]
As you can see, these two relationships share the same student_id. I want to find out if there's a way I can delete from the database the duplicated relationships. I've tried the following lines of code to no avail:
g.relationships.uniq!(&:student_id)
g.update_attributes(relatioships: g.relationships.uniq!(&:student_id))
How can I solve this problem. Thanks!
subquery = Relationship.select("student_id, guardian_id").
group(:student_id, :guardian_id).
having("count(*) > 1").to_sql
groups = Relationship.joins("JOIN (#{subquery}) sub ON relationships.student_id = sub.student_id AND relationships.guardian_id = sub.guardian_id").
group_by{|r| [r.student_id, r.guardian_id] }
groups.values.each do |duplicates|
duplicates.drop(1).each(&:destroy)
end

Validation is passing when it should fail - Michael Hartl's RoR, 6.2.2

I am trying to add validation to my User model, but instead of failing, the data keeps passing. For name, I have no entry. See below:
1.9.3p286 :012 > user = User.new(name: "", email: "fail#fail.com")
=> #<User id: nil, name: "", email: "fail#fail.com", created_at: nil, updated_at: nil>
1.9.3p286 :013 > user.save
(0.1ms) SAVEPOINT active_record_1
SQL (1.5ms) INSERT INTO "users" ("created_at", "email", "name", "updated_at") VALUES (?, ?, ?, ?) [["created_at", Sun, 23 Dec 2012 18:52:00 UTC +00:00], ["email", "fail#fail.com"], ["name", ""], ["updated_at", Sun, 23 Dec 2012 18:52:00 UTC +00:00]]
(0.1ms) RELEASE SAVEPOINT active_record_1
=> true
Here is what I have in app/models/user.rb:
class User < ActiveRecord::Base
attr_accessible(:name, :email)
validates(:name, presence: true)
end
This is supposed to fail. Any suggestions? Thank you!
It should work, I think u didn't reload a console after adding a validation

belongs_to / has_many not behaving as expected in Rails console

models:
class Person < ActiveRecord::Base
attr_accessible :email, :first, :last, :uuid, :books
has_many :books
end
class Book < ActiveRecord::Base
belongs_to :person
attr_accessor :blurb, :published, :title, :person
attr_accessible :person
end
I created a Person using the Rails 3.2.8 console like this:
person = Person.create!( {:first => "John", :last => "Doe"} )
and then created a Book
book = Book.create!( {:title => "Ruby for Dummies"} )
I then try to associate them like this:
person.books << book
When I query the person for books, I get an array with the book I created, but when I query the book for the person it belongs to, I get nil. I expected to get the person, given that all information was persisted (I see the SQL commands and I checked the database and the data is correct, i.e. the row in the book table points back to the person id it should.)
What am I missing?
thanks
Edit- Schema:
CREATE TABLE `persons` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`first` VARCHAR(255) NULL DEFAULT NULL COLLATE 'utf8_unicode_ci',
`last` VARCHAR(255) NULL DEFAULT NULL COLLATE 'utf8_unicode_ci',
`uuid` VARCHAR(255) NULL DEFAULT NULL COLLATE 'utf8_unicode_ci',
`email` VARCHAR(255) NULL DEFAULT NULL COLLATE 'utf8_unicode_ci',
`created_at` DATETIME NOT NULL,
`updated_at` DATETIME NOT NULL,
PRIMARY KEY (`id`)
)
COLLATE='utf8_unicode_ci'
ENGINE=InnoDB
AUTO_INCREMENT=2;
CREATE TABLE `books` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`title` VARCHAR(255) NULL DEFAULT NULL COLLATE 'utf8_unicode_ci',
`blurb` TEXT NULL COLLATE 'utf8_unicode_ci',
`published` TINYINT(1) NULL DEFAULT NULL,
`person_id` INT(11) NULL DEFAULT NULL,
`created_at` DATETIME NOT NULL,
`updated_at` DATETIME NOT NULL,
PRIMARY KEY (`id`)
)
COLLATE='utf8_unicode_ci'
ENGINE=InnoDB
AUTO_INCREMENT=3;
Assuming your migrations are correct, there is nothing wrong with your code which should produce the following results:
1.9.3p194 :001 > person = Person.create!( {:first => "John", :last => "Doe"} )
(0.1ms) begin transaction
SQL (145.9ms) INSERT INTO "people" ("book_id", "created_at", "email", "first", "last", "updated_at", "uuid") VALUES (?, ?, ?, ?, ?, ?, ?) [["book_id", nil], ["created_at", Mon, 03 Sep 2012 21:35:53 UTC +00:00], ["email", nil], ["first", "John"], ["last", "Doe"], ["updated_at", Mon, 03 Sep 2012 21:35:53 UTC +00:00], ["uuid", nil]]
(43.5ms) commit transaction
=> #<Person id: 1, email: nil, first: "John", last: "Doe", uuid: nil, book_id: nil, created_at: "2012-09-03 21:35:53", updated_at: "2012-09-03 21:35:53">
1.9.3p194 :005 > book = Book.create!( {:title => "Ruby for Dummies"} )
(0.1ms) begin transaction
SQL (1.4ms) INSERT INTO "books" ("blurb", "created_at", "person_id", "published", "title", "updated_at") VALUES (?, ?, ?, ?, ?, ?) [["blurb", nil], ["created_at", Mon, 03 Sep 2012 21:36:25 UTC +00:00], ["person_id", nil], ["published", nil], ["title", nil], ["updated_at", Mon, 03 Sep 2012 21:36:25 UTC +00:00]]
(4.4ms) commit transaction
=> #<Book id: 1, blurb: nil, published: nil, title: nil, person_id: nil, created_at: "2012-09-03 21:36:25", updated_at: "2012-09-03 21:36:25">
1.9.3p194 :006 > person.books << book
(0.1ms) begin transaction
(0.3ms) UPDATE "books" SET "person_id" = 1, "updated_at" = '2012-09-03 21:36:39.566387' WHERE "books"."id" = 1
(4.4ms) commit transaction
Book Load (0.3ms) SELECT "books".* FROM "books" WHERE "books"."person_id" = 1
=> [#<Book id: 1, blurb: nil, published: nil, title: nil, person_id: 1, created_at: "2012-09-03 21:36:25", updated_at: "2012-09-03 21:36:39">]
1.9.3p194 :007 > Book.all
Book Load (0.5ms) SELECT "books".* FROM "books"
=> [#<Book id: 1, blurb: nil, published: nil, title: nil, person_id: 1, created_at: "2012-09-03 21:36:25", updated_at: "2012-09-03 21:36:39">]
The problem is with your Book model, try the following:
class Book < ActiveRecord::Base
attr_accessible :person, :title, :person
belongs_to :person
end
Before:
1.9.3p194 :002 > Book.last
Book Load (0.1ms) SELECT "books".* FROM "books" ORDER BY "books"."id" DESC LIMIT 1
=> #<Book id: 4, blurb: nil, published: nil, title: nil, person_id: 1, created_at: "2012-09-03 21:55:33", updated_at: "2012-09-03 21:55:33">
1.9.3p194 :003 > Book.last.person
Book Load (0.2ms) SELECT "books".* FROM "books" ORDER BY "books"."id" DESC LIMIT 1
=> nil
After:
1.9.3p194 :001 > Book.last
Book Load (0.4ms) SELECT "books".* FROM "books" ORDER BY "books"."id" DESC LIMIT 1
=> #<Book id: 4, blurb: nil, published: nil, title: nil, person_id: 1, created_at: "2012-09-03 21:55:33", updated_at: "2012-09-03 21:55:33">
1.9.3p194 :002 > Book.last.person
Book Load (1.0ms) SELECT "books".* FROM "books" ORDER BY "books"."id" DESC LIMIT 1
Person Load (0.1ms) SELECT "people".* FROM "people" WHERE "people"."id" = 1 LIMIT 1
=> #<Person id: 1, email: nil, first: "John", last: "Doe", uuid: nil, created_at: "2012-09-03 21:48:02", updated_at: "2012-09-03 21:48:02">
Have you tried doing something like the following? If so, what does book.person give you?
person = Person.create!( {:first => "John", :last => "Doe"} )
book = Book.create!( {:title => "Ruby for Dummies"} )
book.person_id = person.id
person.books
book.person

creating with a belongs_to has_many association

I'm getting the error unknown attribute: user_id durring execution of #user.posts.create in my specs
User Class
class User < ActiveRecord::Base
# new columns need to be added here to be writable through mass assignment
attr_accessible :username, :email, :password, :password_confirmation
has_many :posts, :dependent => :destroy
end
Post Class
class Post < ActiveRecord::Base
attr_accessible :title, :body
belongs_to :user
end
DB Schema
ActiveRecord::Schema.define(:version => 20111214045425) do
create_table "posts", :force => true do |t|
t.string "title"
t.string "body"
t.integer "user_id"
t.datetime "created_at"
t.datetime "updated_at"
end
create_table "users", :force => true do |t|
t.string "username"
t.string "email"
t.string "password_hash"
t.string "password_salt"
t.datetime "created_at"
t.datetime "updated_at"
end
end
Any help? I've followed every guide I can find for using ActiveRecord. All I want to do is create a Post with an associated User.
You can use
#user = User.find(1)
#post = #user.posts.build(posts_attributes_as_hash)
#post.save
Or even
post = Post.new(posts_attributes)
#user = User.find(1)
#user.posts << post
Edit
To use create directly:
#user = User.find(1)
#post = #user.posts.create(posts_attributes_as_hash)
For more information have a look at has_many-association-reference especially at section called 4.3.1 Methods Added by has_many
New Edit:
I created a new project with your code and in rails console I tried the following commands
User.create(:username => "UserNamedTest", :email => "usernamedtest#somewhere.com")
SQL (13.6ms) INSERT INTO "users" ("created_at", "email", "password_hash", "password_salt", "updated_at", "username") VALUES (?, ?, ?, ?, ?, ?) [["created_at", Wed, 14 Dec 2011 09:02:46 UTC +00:00], ["email", "usernamedtest#somewhere.com"], ["password_hash", nil], ["password_salt", nil], ["updated_at", Wed, 14 Dec 2011 01:03:26 UTC +00:00], ["username", "UserNamedTest"]]
=> #<User id: 2, username: "UserNamedTest", email: "usernamedtest#somewhere.com", password_hash: nil, password_salt: nil, created_at: "2011-12-14 09:02:46", updated_at: "2011-12-14 09:02:46">
user = User.find_by_username("UserNamedTest")
User Load (0.2ms) SELECT "users".* FROM "users" WHERE "users"."username" = 'UserNamedTest' LIMIT 1
=> #<User id: 2, username: "UserNamedTest", email: "usernamedtest#somewhere.com", password_hash: nil, password_salt: nil, created_at: "2011-12-14 09:02:46", updated_at: "2011-12-14 09:02:46">
new_post = user.posts.create(:title => "just a test", :body =>"body of article test")
SQL (0.5ms) INSERT INTO "posts" ("body", "created_at", "title", "updated_at", "user_id") VALUES (?, ?, ?, ?, ?) [["body", "body of article test"], ["created_at", Wed, 14 Dec 2011 09:03:59 UTC +00:00], ["title", "just a test"], ["updated_at", Wed, 14 Dec 2011 09:03:59 UTC +00:00], ["user_id", 2]]
=> #<Post id: 2, title: "just a test", body: "body of article test", user_id: 2, created_at: "2011-12-14 09:03:59", updated_at: "2011-12-14 09:03:59">
irb(main):022:0> new_post.inspect
=> "#<Post id: 2, title: \"just a test\", body: \"body of article test\", user_id: 2, created_at: \"2011-12-14 09:03:59\", updated_at: \"2011-12-14 09:03:59\">"
From what I see the code is ok, the post get created with no errors
Discovered the issue after a dump of the test.sqlite3 schema. user_id was not defined as a column in the db. Blowing out the database and running rake spec migrates the database and fixes everything.