Rails “where” clause for associations

孤街醉人 提交于 2019-12-09 18:33:42

问题


This seems like a simple question but it's a little puzzle to me:

class Parent
  has_many children
  ...
end

class Child
  belongs_to parent
end

p = Parent.find(111)
c = Child.all.where(parent: p)

Why doesn't that work, and how come I have to do:

c = Child.all.where(parent_id: p.id)

Thanks!

* Addendum *

A more complicated case has me creating a Relation based on more complicated logic, e.g.

c = Child.where(age: 32, city: "boston")
c.where(parent: p) # wouldn't work

* Addendum #2 *

Wait I need to have a many to many to illustrate this:

class Teacher
   has_many :students, through: ClassRoom
   has_many :classes
end

class ClassRoom
  belongs_to :teacher
  belongs_to :child
end

class Child 
  has_many :classes
  has_many :teachers, through: ClassRoom
end
t = Teacher.first
c = Child.where(age: 5, city: "boston")

c.where(teacher: t) # wouldn't work
c.where(teacher_id: t.id) # would work but is a little ugly

* Addendum 3 *

Thanks for all the great info! Is there a better (or 'correct') way to do the last line form the above example?

c.where(teacher_id: t.id) # would work but is a little ugly

回答1:


You can do:

p = Parent.find(111)
all_children = p.children

The key parent doesn't work because it using that as the column name.

Addendum:

So for this use case you should use:

class ClassRoom < ActiveRecord::Base
  belongs_to :teacher
  belongs_to :child
end

class Teacher < ActiveRecord::Base
  has_many :children, through: ClassRoom
  has_many :class_rooms
end

class Child < ActiveRecord::Base
  has_many :class_rooms
  has_many :teachers, through: ClassRoom
end

t = Teacher.first
teachers_children_from_boston_and_32 = t.children.where(age: 32, city: "boston")

Firstly you can't use Class because it is an object already. The next problem was that you renamed children to students, which you can do but then need to do some other options on the has_many call.

Check out joining tables here: http://guides.rubyonrails.org/active_record_querying.html#joining-tables

And Assoications here (your use case matches this example perfectly): http://guides.rubyonrails.org/association_basics.html#the-has_many-through-association

Also remember with rails 3 all where clauses are just critera. Critera is used to find your matches and can be added together to narrow your results. IE

where_clause_one = Teacher.where(age: 50)
where_clause_two = Teacher.where(city: "San Francisco")
merged_where_clauses = where_clause_one.merge(where_clause_two)
merged_where_clauses.each do |teacher|
  # teachers that are both 50 and from san francisco
  ...
end



回答2:


.all converts an ActiveRecord::Relation object to an array. Arrays do not respond to the where method. You should use

c = Child.where(parent_id: p.id).all

You have to use _id in this case because where will directly translate the given hash into SQL. SQL does not know what parent is, it only knows what parent_id is. That being said, the best way to do this would be

c = p.children



回答3:


"Active Record objects don’t specify their attributes directly, but rather infer them from the table definition with which they’re linked" - http://api.rubyonrails.org/files/activerecord/README_rdoc.html

This association is linked by particular database columns, so you have to use those attributes to refer to the relationship.

You can also simplify this statement by using p.children which will return an array of the parents children.



来源:https://stackoverflow.com/questions/16244411/rails-where-clause-for-associations

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!