Rails“where”子句用于关联

时间:2013-04-26 20:08:01

标签: ruby-on-rails activerecord

这似乎是一个简单的问题,但这对我来说有点困惑:

class Parent
  has_many children
  ...
end

class Child
  belongs_to parent
end

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

为什么不起作用,我该怎么做:

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

谢谢!

*附录*

更复杂的情况是我根据更复杂的逻辑创建了一个关系,例如

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

*附录#2 *

等等我需要多对多来说明这一点:

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

*附录3 *

感谢所有精彩信息!从上面的例子开始,最后一行是否有更好(或'正确')的方式?

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

3 个答案:

答案 0 :(得分:3)

你可以这样做:

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

关键的父级不起作用,因为它使用它作为列名。

附录:

因此,对于此用例,您应该使用:

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")

首先,您不能使用Class,因为它已经是一个对象。 下一个问题是您将孩子重命名为学生,您可以这样做,但需要在has_many调用上做一些其他选项。

在此处查看加入表:http://guides.rubyonrails.org/active_record_querying.html#joining-tables

和Assoications在这里(你的用例完全符合这个例子): http://guides.rubyonrails.org/association_basics.html#the-has_many-through-association

还要记住rails 3所有where子句只是critera。 Critera用于查找您的匹配项,可以一起添加以缩小搜索结果范围。 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

答案 1 :(得分:3)

.all将ActiveRecord :: Relation对象转换为数组。数组不响应where方法。你应该使用

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

在这种情况下你必须使用_id,因为where会直接将给定的哈希转换为SQL。 SQL不知道parent是什么,它只知道parent_id是什么。话虽如此,最好的方法是

c = p.children

答案 2 :(得分:2)

“Active Record对象不直接指定其属性,而是从与其链接的表定义中推断出它们” - http://api.rubyonrails.org/files/activerecord/README_rdoc.html

此关联由特定数据库列链接,因此您必须使用这些属性来引用关系。

您还可以使用p.children来简化此声明,{{1}}将返回父母子女的数组。