I have 2 models, Car and Person. Each person can have many cars. I have loaded some data through from seed.rb but when I try Car.find_by(owner_id: 1) in the console, I see just one car. When I am expecting 2 cars because I assigned 2 cars to one particular Person. Why am I just seeing one car?
car.rb (model)
class Car < ActiveRecord::Base
belongs_to :owner, class_name: "Person", foreign_key: "owner_id"
has_many :place_rents
validates :owner, presence: true
validates :registration_number, presence: true
validates :model, presence: true
end
person.rb
class Person < ActiveRecord::Base
has_many :cars, foreign_key: "owner_id"
has_many :parkings, foreign_key: "owner_id"
validates :first_name, presence: true
end
seed.rb
people = Person.create([{first_name: "Emmanuel", last_name: "Hayford"}, {first_name: "Steve", last_name: "Jobs"},
{first_name: "James", last_name: "Bond"}, {first_name: "Michael", last_name: "Jordan"}])
addresses = Address.create([{street: "Limanowskiego", city: "Kraków", zip_code: "98-734"}, {street: "Zeromskiego",
city: "Wrocław", zip_code: "45-622"}, {street: "Chopin", city: "Gdańsk", zip_code: "98-734"},
{street: "Putin", city: "Opole", zip_code: "90-938"}])
cars = Car.create([{owner: Person.first, model: "BMW", registration_number: "UJ8483"}, {owner: Person.second, model: "Lambo", registration_number: "JH4857"},
{owner: Person.second, model: "Jaguar", registration_number: "DW3455"}, { owner: Person.second, model: "Ferrari", registration_number: "KP8734"},
{owner: Person.first,model: "Bugatti Veyron", registration_number: "ZK9837"}])
parkings = Parking.create([{kind: "indoor", hour_price: 45.50, day_price: 200, places: 5, owner: Person.first, address_id: Address.first},
{kind: "outdoor", hour_price: 20.50, day_price: 150.00, places: 10, owner: Person.second, address_id: Address.second},
{kind: "street", hour_price: 270.50, day_price: 89.45, places: 7, owner: Person.second, address_id: Address.second},
{kind: "private", hour_price: 40.50, day_price: 30.45, places: 2, owner: Person.find(2), address_id: Address.find(2)},])
place_rents = PlaceRent.create([{parking: Parking.first, car: Car.first, start_date: Time.now, end_date: Time.now + 3.days, price: 30}])
2.1.4 :023 > Car.all
Car Load (0.5ms) SELECT "cars".* FROM "cars"
=> #<ActiveRecord::Relation [#<Car id: 1, registration_number: "UJ8483", model: "BMW", owner_id: 1, created_at: "2014-11-10 00:10:26", updated_at: "2014-11-10 00:10:26">, #<Car id: 2, registration_number: "JH4857", model: "Lambo", owner_id: 2, created_at: "2014-11-10 00:10:26", updated_at: "2014-11-10 00:10:26">, #<Car id: 3, registration_number: "DW3455", model: "Jaguar", owner_id: 2, created_at: "2014-11-10 00:10:26", updated_at: "2014-11-10 00:10:26">, #<Car id: 4, registration_number: "KP8734", model: "Ferrari", owner_id: 2, created_at: "2014-11-10 00:10:26", updated_at: "2014-11-10 00:10:26">, #<Car id: 5, registration_number: "ZK9837", model: "Bugatti Veyron", owner_id: 1, created_at: "2014-11-10 00:10:26", updated_at: "2014-11-10 00:10:26">]>
2.1.4 :024 > Car.find_by(owner_id: 1)
Car Load (0.6ms) SELECT "cars".* FROM "cars" WHERE "cars"."owner_id" = 1 LIMIT 1
=> #<Car id: 1, registration_number: "UJ8483", model: "BMW", owner_id: 1, created_at: "2014-11-10 00:10:26", updated_at: "2014-11-10 00:10:26">
2.1.4 :025 >
You misunderstand how find_by works:
find_by(*args)
Finds the first record matching the specified conditions.
find_by only gets one record from the database, hence the LIMIT 1 in the SQL it generates. If you want to find several things, then use where:
Car.where(owner_id: 1)
or, since you have the associations set up, use Person#cars:
person = Person.find(1)
cars = person.cars
Car.find_by_owner_id(1) is the same as Car.where(owner_id: 1).first so basically it returns one record rather than an array of record. Car.where(owner_id: 1) will get you your two records.
Related
I am trying to implement a three level deep association using self referencing.
Cat1
Sub1
SubSub1
SubSub2
Sub2
Cat2
Sub1
Cat3
Sub1
Sub2
SubSub1
I am able to get the child category of a category by this relation:
class Category < ActiveRecord::Base
has_many :sub_categories, class_name: "Category", foreign_key: :parent_id
end
This is fine when i have only two level deep category. For three level deep association using self referencing i tried using this relation, but failed to get the desired output.
class Category < ActiveRecord::Base
belongs_to :parent_category, class_name: "Category"
has_many :sub_categories, class_name: "Category", foreign_key: :parent_id
end
here is what i get using this association.query fired on Category.find(3).parent_category is wrong.
2.0.0-p648 :012 > Category.find(2)
Category Load (1.2ms) SELECT `categories`.* FROM `categories` WHERE `categories`.`id` = 2 LIMIT 1
=> #<Category id: 2, title: "Suit", description: "sffdsfsxcx ssdfvvs", seo_name: "sfsdf", parent_id: nil, hoe_page: nil, status: true, sequence: "1", banner_image_file_name: nil, banner_image_content_type: nil, banner_image_file_size: nil, banner_image_updated_at: nil, image_file_name: nil, image_content_type: nil, image_file_size: nil, image_updated_at: nil, home_description: "adhkadaa", home_page: true, long_description: "sdfsddfffssssde", created_at: "2018-04-09 07:42:55", updated_at: "2018-04-09 07:42:55">
2.0.0-p648 :013 > Category.find(3)
Category Load (1.1ms) SELECT `categories`.* FROM `categories` WHERE `categories`.`id` = 3 LIMIT 1
=> #<Category id: 3, title: "a", description: "aaa", seo_name: "a", parent_id: 2, hoe_page: nil, status: true, sequence: "1", banner_image_file_name: nil, banner_image_content_type: nil, banner_image_file_size: nil, banner_image_updated_at: nil, image_file_name: nil, image_content_type: nil, image_file_size: nil, image_updated_at: nil, home_description: "aaa", home_page: true, long_description: "aaa", created_at: "2018-04-09 09:44:11", updated_at: "2018-04-09 09:44:11">
2.0.0-p648 :014 > Category.find(3).parent_category
Category Load (1.1ms) SELECT `categories`.* FROM `categories` WHERE `categories`.`id` = 3 LIMIT 1
=> nil
Please help me here by making me understand what would be the perfect association for my purpose. Please dont give me gem name like "Ancestry" or "awesome_nested_set", I need pure rails associations.
Try this:
belongs_to :parent_category, foreign_key: :parent_id, class_name: 'Category'
has_many :sub_categories, foreign_key: :parent_id, class_name: 'Category'
I have two models post and topic which has a one to many relation
#Post.rb
class Post < ApplicationRecord
belongs_to :topic
validates :topic_id, presence: true
validates :title, presence: true
validates :body, presence: true
end
if i have an array of posts by calling Post.all for example
#<ActiveRecord::Relation [#<Post id: 1, title: "Rails Code", body: "class TopicsController < ApplicationController\r\n ...", created_at: "2018-05-22 09:34:15", updated_at: "2018-05-22 09:34:15", topic_id: "2">,
#<Post id: 2, title: "Post with tags", body: "qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq...", created_at: "2018-05-22 11:48:54", updated_at: "2018-05-22 11:48:54", topic_id: "2">,
#<Post id: 3, title: "12hello world12", body: "12312sdfsdfsdsdsdsd31231231231231", created_at: "2018-05-23 12:54:02", updated_at: "2018-05-23 12:54:02", topic_id: "2">,
#<Post id: 4, title: "12hello world12", body: "12312sdfsdfsdsdsdsd31231231231231", created_at: "2018-05-23 12:54:09", updated_at: "2018-05-23 12:54:09", topic_id: "1">,
#<Post id: 5, title: "12hellsdssdo world12", body: "12312sdfsdfsdsdsdsd31231231231231", created_at: "2018-05-23 12:54:15", updated_at: "2018-05-23 12:54:15", topic_id: "1">]>
is there a way i could group them by their topic_id so i could display them topic by topic
example
Topic - 1
post 1 post2 post 3
Topic -2
post4 post5
Use this:
Post.all.group_by(&:topic_id).each do |topic_id, posts|
...
end
Found the answer.
You can do it using ruby's Enumerable#group_by:
post.group_by{|post| post.topic_id}
I have an application which allows lawyers and law students to answer legal questions. Their answers can be voted up. Beside each answer on the views/question/show.html.erb, the application indicates whether an answer has been voted up and by who (a lawyer, or a law student). However, it's behaving very oddly. Currently, on a test question, if a lawyer votes up an answer, the application is not showing the upvote, but if a student votes up an answer, then both the student's and the lawyer's vote will be displayed, but both are displayed as student votes.
This is the code in the show action of the Questions controller that retrieves all the answers for a question, and then queries for the type of votes each answer has.
def show
#question = Question.find(params[:id])
#answers = #question.answers
#answers.each do |a|
#lawyervotes = AnswerVote.where({:answer_id => a.id, :lawyervote => true}).reload
puts #lawyervotes.inspect
puts "lawyervotes"
#studentvotes = AnswerVote.where({:answer_id => a.id, :studentvote => true}).reload
#uservotes = AnswerVote.where({:answer_id => a.id, :lawyervote => nil, :studentvote => nil}).reload
end
end
If I look in the console for the puts statements, it shows that #lawyervotes contains one result, but then it's suddenly an empty array. Currently, there are two answers for this question, which is why the puts statement is run twice, but I don't know why it's empty on the second time through
[#<AnswerVote id: 34, value: 3, answer_id: 54, user_id: 37, created_at: "2013-05-08 18:29:34", updated_at: "2013-05-08 18:29:34", lawyervote: true, studentvote: nil>]
lawyervotes
[]
lawyervotes
Note, the reason why I put reload on the end of each query was to avoid an ActiveRecord::AssociationTypeMismatch error I was getting, which according to another SO answer I found can happen when you query with 'where.' I found another SO answer that said putting 'reload' on the end of a where query can help avoid that error.
Can you explain why this odd behavior might be happening with my lawyervotes and student votes and possibly tell me how to rewrite the show action to avoid it. Thank you in advance.
Update
This is the console record showing that question 62 has two answers, each with one answer_vote. One of the answer votes was by a lawyer (lawyer = true) while one was by a student (student = true), however, they're both showing up as student votes in my application, even after trying dmitry's solution.
>> q = Question.find_by_id(62)
Question Load (0.2ms) SELECT "questions".* FROM "questions" WHERE "questions"."id" = 62 LIMIT 1
=> #<Question id: 62, details: "I have a terminal illness but don't have time to go...", question: "What happens if I die without a will?", user_id: 35, accepted_answer_id: nil, created_at: "2013-05-08 18:19:48", updated_at: "2013-05-08 18:19:48", city: "Toronto", province: nil, province_id: 6>
>> q.answers
Answer Load (0.2ms) SELECT "answers".* FROM "answers" WHERE "answers"."question_id" = 62
=> [#<Answer id: 54, content: "There is legislation that determines the rules of i...", accepted: nil, user_id: 50, question_id: 62, created_at: "2013-05-08 18:20:41", updated_at: "2013-05-08 18:20:41">, #<Answer id: 55, content: "Ontario has statutory provisions that detail who in...", accepted: nil, user_id: 37, question_id: 62, created_at: "2013-05-08 18:22:53", updated_at: "2013-05-08 18:22:53">]
>> a54 = Answer.find_by_id(54)
Answer Load (0.3ms) SELECT "answers".* FROM "answers" WHERE "answers"."id" = 54 LIMIT 1
=> #<Answer id: 54, content: "There is legislation that determines the rules of i...", accepted: nil, user_id: 50, question_id: 62, created_at: "2013-05-08 18:20:41", updated_at: "2013-05-08 18:20:41">
>> a54.answer_votes
AnswerVote Load (0.2ms) SELECT "answer_votes".* FROM "answer_votes" WHERE "answer_votes"."answer_id" = 54
=> [#<AnswerVote id: 34, value: 3, answer_id: 54, user_id: 37, created_at: "2013-05-08 18:29:34", updated_at: "2013-05-08 18:29:34", lawyervote: true, studentvote: nil>]
>> a55 = Answer.find_by_id(55)
Answer Load (0.3ms) SELECT "answers".* FROM "answers" WHERE "answers"."id" = 55 LIMIT 1
=> #<Answer id: 55, content: "Ontario has statutory provisions that detail who in...", accepted: nil, user_id: 37, question_id: 62, created_at: "2013-05-08 18:22:53", updated_at: "2013-05-08 18:22:53">
>> a55.answer_votes
AnswerVote Load (0.3ms) SELECT "answer_votes".* FROM "answer_votes" WHERE "answer_votes"."answer_id" = 55
=> [#<AnswerVote id: 35, value: 3, answer_id: 55, user_id: 50, created_at: "2013-05-08 18:37:32", updated_at: "2013-05-08 18:37:32", lawyervote: nil, studentvote: true>]
Update
I put this code in the loop
puts AnswerVote.where({:answer_id => a.id}).reload.inspect
puts "inspectinganswervote"
and got this result
[#<AnswerVote id: 34, value: 3, answer_id: 54, user_id: 37, created_at: "2013-05-08 18:29:34", updated_at: "2013-05-08 18:29:34", lawyervote: true, studentvote: nil>]
inspectinganswervote
[#<AnswerVote id: 35, value: 3, answer_id: 55, user_id: 50, created_at: "2013-05-08 18:37:32", updated_at: "2013-05-08 18:37:32", lawyervote: nil, studentvote: true>]
inspectinganswervote
Update
Answer.rb
class Answer < ActiveRecord::Base
attr_accessible :accepted, :content, :question_id, :user_id
has_many :comments
belongs_to :question
belongs_to :user
has_many :answer_votes
has_and_belongs_to_many :watchers, :join_table => "answer_watchers", :class_name => "User"
has_reputation :votes, source: :user, aggregated_by: :sum
has_reputation :lawyervotes, source: :user, aggregated_by: :sum
has_reputation :studentvotes, source: :user, aggregated_by: :sum
has_reputation :best, source: :user, aggregated_by: :sum
#
def add_to_watchers(user)
self.watchers << user unless self.watchers.include?(user)
end
after_create :creator_watches_me
private
def creator_watches_me
self.watchers << user unless self.watchers.include?(user)
end
end
AnswerVote.rb
class AnswerVote < ActiveRecord::Base
attr_accessible :answer_id, :user_id, :value, :answer, :lawyervote, :studentvote
belongs_to :answer
belongs_to :user
validates_uniqueness_of :answer_id, scope: :user_id
validates_inclusion_of :value, in: [1,-1,10,-10, 3]
validate :ensure_not_author
scope :lawyers, where(lawyervote: true)
scope :students, where(studentvote: true)
def ensure_not_author
errors.add :user_id, "is the author of the answer" if answer.user_id == user_id
end
end
One of the problems -- you rewrite your #lawyervotes array during the next iteration. One of the ways out would be to append it instead (using something like:
#lawyervotes = []
#answers.each do |a|
#lawyervotes <<= AnswerVote.where({:answer_id => a.id, :lawyervote => true}).reload
...
end
But it is super-terrible, non-Rails style. As I mentioned above, you do not need this iteration through #answers, you simply write:
UPDATED
#lawyervotes = #question.answers.map {|a| a.answer_votes.lawyers}.reject!(&:empty?).flatten
#studentvotes = #question.answers.map {|a| a.answer_votes.students}.reject!(&:empty?).flatten
And in you AnswerVotes model:
scope :lawyers, where(lawyervote: true)
scope :students, where(studentvote: true)
You are getting the lawyervotes array as empty for second answer as the second answer has only one AnswerVote with laywervote = nil and studentvote = true :) So the vote is present in the #studentvotes variable.
If you inspect your #studentvotes as well, you will see your second vote printed in the second iteration of the loop.
In my model I have :
#models/friend.rb
scope :approved_friend, where(:approved => true)
And the Rails console outputs :
User.find(2).friends
=> [#<Friend id: 18, user_id: 2, approved: true, created_at: "2013-04-23 09:18:59", updated_at: "2013-04-23 09:18:59", friend_id: 1>]
User.find(2).friends.approved_friend
=> []
Notice that approved is true in the output ...
Where it gets crazy is here :
User.find(1).friends.approved_friend
=> [#<Friend id: 19, user_id: 1, approved: true, created_at: "2013-04-23 09:19:36", updated_at: "2013-04-23 09:19:36", friend_id: 2>]
Am-I missing something ?
EDIT :
On one hand you have this query :
SELECT "friends".* FROM "friends" WHERE "friends"."user_id" = 2
=> [#<Friend id: 18, user_id: 2, approved: true, created_at: "2013-04-23 09:18:59", updated_at: "2013-04-23 09:18:59", friend_id: 1>]
On the other hand, you've got this (query through scope) :
SELECT "friends".* FROM "friends" WHERE "friends"."user_id" = 2 AND "friends"."approved" = 't'
=> []
Since the :status field is in the Friend model, you might have to change the scope to this
scope :approved_friend, where('friends.approved' => true).includes(:friend)
I have a pair of classes:
class Collection < ActiveRecord::Base
has_many :items, autosave: true
end
class Item < ActiveRecord::Base
belongs_to :collection
end
From the docs:
When :autosave is true all children is saved, no matter whether they are new records:
But when I update an Item and save its parent Collection, the Item's upated attributes don't get saved:
> c = Collection.first
=> #<Collection id: 1, name: "collection", created_at: "2012-07-23 00:00:10", updated_at: "2012-07-23 00:00:10">
> i = c.items.first
=> #<Item id: 1, collection_id: 1, name: "item1", created_at: "2012-07-23 00:00:25", updated_at: "2012-07-23 00:00:25">
> i.name = 'new name'
=> "new name"
> c.save
=> true
> Collection.first.items
=> [#<Item id: 1, collection_id: 1, name: "item1", created_at: "2012-07-23 00:00:25", updated_at: "2012-07-23 00:00:25">]
So, what am I missing?
I'm using Rails 3.2.5 and Ruby 1.9.2.
So I've done some digging about in the source of ActiveRecord. We can get hold of c's autosave assocations:
> c.class.reflect_on_all_autosave_associations
=> [#<ActiveRecord::Reflection::AssociationReflection:0x007fece57b3bd8 #macro=:has_many, #name=:items, #options={:autosave=>true, :extend=>[]}, #active_record=Collection(id: integer, name: string, created_at: datetime, updated_at: datetime), #plural_name="items", #collection=true, #class_name="Item", #klass=Item(id: integer, collection_id: integer, name: string, created_at: datetime, updated_at: datetime), #foreign_key="collection_id", #active_record_primary_key="id", #type=nil>]
I think this illustrates that the association has been set up for autosaving.
We can then get the instance of the association corresponding to c:
> a = c.send :association_instance_get, :items
=> #<ActiveRecord::Associations::HasManyAssociation:0x007fece738e920 #target=[#<Item id: 1, collection_id: 1, name: "item1", created_at: "2012-07-23 00:00:25", updated_at: "2012-07-23 00:00:25">], #reflection=#<ActiveRecord::Reflection::AssociationReflection:0x007fece57b3bd8 #macro=:has_many, #name=:items, #options={:autosave=>true, :extend=>[]}, #active_record=Collection(id: integer, name: string, created_at: datetime, updated_at: datetime), #plural_name="items", #collection=true, #class_name="Item", #klass=Item(id: integer, collection_id: integer, name: string, created_at: datetime, updated_at: datetime), #foreign_key="collection_id", #active_record_primary_key="id", #type=nil>, #owner=#<Collection id: 1, name: "collection", created_at: "2012-07-23 00:00:10", updated_at: "2012-07-23 00:00:10">, #updated=false, #loaded=true, #association_scope=[#<Item id: 1, collection_id: 1, name: "item1", created_at: "2012-07-23 00:00:25", updated_at: "2012-07-23 00:00:25">], #proxy=[#<Item id: 1, collection_id: 1, name: "item1", created_at: "2012-07-23 00:00:25", updated_at: "2012-07-23 00:00:25">], #stale_state=nil>
We can then find the actual objects that are associated via this association:
> a.target
=> [#<Item id: 1, collection_id: 1, name: "item1", created_at: "2012-07-23 00:00:25", updated_at: "2012-07-23 00:00:25">]
The object found here does not have update that I'd made earlier.
The problem here is the line
i = c.items.first
This line pulls the correct item from the database, but doesn't attach it to the collection c. It is a distinct ruby object from the object
i = c.items[0]
If you replace the first line with the second your example will work.