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
Related
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>]
I have two models
# == Schema Information
#
# Table name: answers
#
# id :integer not null, primary key
# content :text
# question_id :integer
# accept :boolean
# created_at :datetime not null
# updated_at :datetime not null
# user_id :integer
#
class Answer < ActiveRecord::Base
attr_accessible :accept, :content, :question_id, :user
belongs_to :question
belongs_to :user
delegate :username, to: :user, allow_nil: true, prefix: 'owner'
end
and Question
# == Schema Information
#
# Table name: questions
#
# id :integer not null, primary key
# title :string(255)
# content :text default(""), not null
# created_at :datetime not null
# updated_at :datetime not null
# user_id :integer
# viewed_count :integer default(0)
#
class Question < ActiveRecord::Base
validates_presence_of :title, :content, :user
attr_accessible :content, :title, :tag_list
acts_as_taggable
belongs_to :user, :counter_cache => true
has_many :answers
delegate :username, to: :user, allow_nil: true, prefix: 'owner'
scope :owner, joins(:user)
scope :without_answer, joins(:answers).
select('questions.id').
group('questions.id').
having('count(answers.id) = 0')
validate :validation_of_tag_list
def self.no_answer
Question.all.select{|question|question.answers.count == 0}
end
The scope without_answer and class method no_answer theoretically should be same. However, I run them in the console as below:
Loading development environment (Rails 3.2.13)
irb(main):001:0> Question.without_answer
Question Load (0.6ms) SELECT questions.id FROM `questions` INNER JOIN `answers` ON `answers`.`question_id` = `questions`.`id` GROUP BY questions.id HAVING count(answers.id) = 0
=> []
irb(main):002:0> Question.no_answer
Question Load (0.6ms) SELECT `questions`.* FROM `questions`
(0.5ms) SELECT COUNT(*) FROM `answers` WHERE `answers`.`question_id` = 1
(0.4ms) SELECT COUNT(*) FROM `answers` WHERE `answers`.`question_id` = 2
(0.4ms) SELECT COUNT(*) FROM `answers` WHERE `answers`.`question_id` = 16
(0.4ms) SELECT COUNT(*) FROM `answers` WHERE `answers`.`question_id` = 17
(0.3ms) SELECT COUNT(*) FROM `answers` WHERE `answers`.`question_id` = 34
=> [#<Question id: 2, title: "Here is the second", content: "here you go\r\n", created_at: "2013-04-20 00:34:15", updated_at: "2013-04-20 00:34:15", user_id: nil, viewed_count: 0>, #<Question id: 16, title: "my question", content: "Here is my question", created_at: "2013-04-21 02:02:47", updated_at: "2013-04-23 02:29:27", user_id: 1, viewed_count: 1>, #<Question id: 17, title: "Hello", content: "me", created_at: "2013-04-23 00:37:56", updated_at: "2013-04-23 00:37:56", user_id: nil, viewed_count: 0>, #<Question id: 34, title: "Question title", content: "question content", created_at: "2013-04-23 04:57:49", updated_at: "2013-04-23 04:57:49", user_id: 42, viewed_count: 0>]
why the scope dose not work as expect?
which way will be better to due with such situation or even better solution?
Your without_answer scope is very close, but needs an outer join like this:
scope :without_answer,
joins('LEFT OUTER JOIN answers ON answers.question_id = questions.id').
select('questions.id').
group('questions.id').
having('count(answers.id) = 0')
Then, you can get the count with length:
Question.without_answer.length
Note: if you want without_answer to be the same as no_answer (i.e. return actual Question objects), you would need to remove the select.
A simpler and faster way to count the unanswered questions is like this:
Question.joins('LEFT OUTER JOIN answers ON answers.question_id = questions.id').
where('answers.id' => nil).count
Also, this will return the same as no_answer as-is, simply use all instead of count.
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
Well my models are User, Exercise and Writing.
class User < ActiveRecord::Base
has_many :exercises, :through => :writings
has_many :writings
end
class Exercise < ActiveRecord::Base
has_many :users, :through => :writings
has_many :writings
end
class Writing < ActiveRecord::Base
belongs_to :user
belongs_to :exercise
attr_accessible :writing_date, :exercise_id
end
my db/schema.rb
ActiveRecord::Schema.define(:version => 20120517142448) do
create_table "exercises", :force => true do |t|
t.string "etitle"
t.text "ebody"
t.decimal "average", :precision => 3, :scale => 1
t.datetime "created_at"
t.datetime "updated_at"
end
create_table "users", :force => true do |t|
t.string "email", :default => "", :null => false
t.datetime "created_at"
t.datetime "updated_at"
t.integer "user_kind", :default => 0
end
create_table "writings", :force => true do |t|
t.integer "user_id"
t.integer "exercise_id"
t.date "writing_date"
t.datetime "created_at"
t.datetime "updated_at"
end
the join table is Writing. I try to show on exercise view (app/view/exercises/index.html.erb) for each exercise_id her writing_date. Each user_id has many exercise_id through Writing table. Each record on Writing table has writing_id, user_id, exercise_id and writing_date. In console for specifically exercise_id I made it like this:
1.9.2p290 :001 > #exercise = Exercise.find_by_id(9)
=> #<Exercise id: 9, etitle: "PLS51-2012-E01", ebody: "q", average: #<BigDecimal:53eeba8,'0.1E2',9(18)>, created_at: "2012-05-20 14:31:07", updated_at: "2012-05-20 14:34:27", askisi_file_name: nil, askisi_content_type: nil, askisi_file_size: nil, askisi_updated_at: nil>
1.9.2p290 :002 > #exercise.writings
=> [#<Writing id: 6, user_id: 1, exercise_id: 9, writing_date: "2012-06-29", created_at: "2012-05-20 14:36:45", updated_at: "2012-05-20 14:36:45">, #<Writing id: 12, user_id: 7, exercise_id: 9, writing_date: "2012-06-20", created_at: "2012-05-20 14:40:12", updated_at: "2012-05-20 14:40:12">, #<Writing id: 13, user_id: 7, exercise_id: 9, writing_date: "2012-05-02", created_at: "2012-05-20 15:41:54", updated_at: "2012-05-20 15:41:54">]
1.9.2p290 :003 > #exercise.writings.order("writing_date ASC")
=> [#<Writing id: 13, user_id: 7, exercise_id: 9, writing_date: "2012-05-02", created_at: "2012-05-20 15:41:54", updated_at: "2012-05-20 15:41:54">, #<Writing id: 12, user_id: 7, exercise_id: 9, writing_date: "2012-06-20", created_at: "2012-05-20 14:40:12", updated_at: "2012-05-20 14:40:12">, #<Writing id: 6, user_id: 1, exercise_id: 9, writing_date: "2012-06-29", created_at: "2012-05-20 14:36:45", updated_at: "2012-05-20 14:36:45">]
1.9.2p290 :004 > #exercise.writings.order("writing_date ASC").last
=> #<Writing id: 6, user_id: 1, exercise_id: 9, writing_date: "2012-06-29", created_at: "2012-05-20 14:36:45", updated_at: "2012-05-20 14:36:45">
Do I need scope?
Thanks in advance!
Finaly the solution for my problem that can help someone with the same situation is simple. File app/view/exercises/index.html.erb
Code:
<%= exercise.writings.last.try(:writing_date) %>
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.