通过对象实例调用类方法

时间:2015-01-13 22:43:08

标签: ruby-on-rails ruby railscasts class-method

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调用该方法?

1 个答案:

答案 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已经生效了。