Railscast#4使用此示例代码:
class Task < ActiveRecord::Base
belongs_to :project
def self.find_incomplete
find_all_by_complete(:false, :order => "created_at DESC")
end
end
class ProjectsController < ApplicationController
def show
@project = Project.find(params[:id])
@tasks = @project.tasks.find_incomplete
end
end
使用@project.tasks.find_incomplete
,只查找属于该特定Project
个实例的不完整订单。
我希望这个电话等同于Task.find_incomplete
,但事实并非如此。怎么可能? Rails(或Ruby)现在如何为Task
实例中的那些特定Project
调用该方法?
答案 0 :(得分:2)
这是有效的,因为ActiveRecord关系的范围是合并的。并不是find_incomplete
正在各个任务实例上运行。
@project.tasks
为该项目实例创建一个ActiveRecord任务范围,然后在调用find_incomplete
方法时该范围仍然有效。
请查看此处的文档:http://guides.rubyonrails.org/active_record_querying.html#scopes
您的find_incomplete
方法的工作方式与文档中self.published
示例的工作方式相同。
考虑将运行的基础SQL查询:
@project.tasks
会创建where
条件,例如SELECT * FROM projects WHERE project_id = <project_id>
find_all_by_complete
合并为and
complete = 0
条件
我认为可能有用的另一个难题是@project.tasks
不仅仅是Task
个对象的简单数组,尽管如果你键入{{1}它会被转换为在Rails控制台中。 project.tasks
实际上是一个Active Record关系对象(或者更确切地说是一个代理)
这有很多原因和好处,但主要的2是它允许链接,它允许基础查询仅在需要时才按需运行。
该关系具有一系列规则,用于如何委托方法调用,其中之一是在关联对象的类上调用类方法。 (关系知道它与project.tasks
)的关系
所以当你写Tasks
仍然等于tasks.find_incomplete
时你是正确的,除了通过Task.find_incomplete
调用find_incomplete
时范围缩小到project.tasks
已经生效了。