所以我是作用域的新手,并不是很了解它们。假设我有两个模型,Project
和Ticket
:
class Project < ActiveRecord::Base
has_many :tickets
end
class Ticket < ActiveRecord::Base
belongs_to :project
end
我习惯这样编写代码来访问门票中的相关数据:
Project.find(1).tickets.each do |ticket|
puts ticket.name
end
我创建了新的作用域:
scope :default, -> { where(default: true) }
现在当我使用Project.default
时,我得到了ActiveRecord::Relation
,不知道如何访问相关的tickets
?
Project.default确实会返回一个ActiveRecord::Relation
,这是一个'待触发'查询。一旦你开始循环等,查询将被触发,这对你来说是透明的。
如果您想从项目中获得门票,首先我建议您将它们包含在查询中,以避免N+1。这样做:
projects = Project.default.includes(:tickets)
然后访问特定项目的门票:
project = projects.first
project.tickets
如果你想让一个方法总是返回一个对象:
class Project < ActiveRecord::Base
has_many :tickets
def self.get_default_with_tickets
Project.where(default: true).includes(:tickets).first
end
end
:
Project.get_default_with_tickets #=> your_project
一定要处理好这些情况:
- 当有多个匹配 时当没有匹配时
作用域基本上就是一个类方法(在未初始化的模型上触发的方法):
class Project < ActiveRecord::Base
has_many :tickets
scope :defaults, -> { where(default: true) }
end
这意味着如果你这样做:
@defaults = Project.defaults
…你会得到所有具有属性default
为true的project
对象
class Project < ActiveRecord::Base
has_many :tickets
def self.defaults
where(default: true)
end
end
误差
你得到一个关系的原因是因为当你使用where
时,你基本上得到了一个数据的"数组"(而不是仅仅一个记录)。如果在数据中输入.each
或者只返回.first
,您将得到一个可以输出的实际对象:
@defaults = Project.defaults
@defaults.each do |project|
project.tickets #-> associated tickets
end
使用all
或first
完成查询。
#get all default projects
Project.default.all
#get the first default project
Project.default.first