将范围重用为`includes` eager-loading的过滤器

时间:2013-04-26 16:07:45

标签: ruby-on-rails activerecord ruby-on-rails-3.2

将其分解为最小的例子:

class User < ActiveRecord::Base
  has_many :profiles
  has_many :addresses, through: :profiles
end

class Profile < ActiveRecord::Base
  belongs_to :user
  has_many :addresses
end

class Address < ActiveRecord::Base
  belongs_to :profile

  def self.active_by_date
    where(is_active: true).order('updated_at DESC')
  end
end

class UsersController < ApplicationController
  def index
    @users = User.includes(profiles: :addresses)
  end
end

假设在上面的控制器操作中,我想为每个用户的配置文件急切加载按日期排序的活动地址。我能做到这一点:

class User < ActiveRecord::Base
  has_many :profiles
  has_many :addresses, through: :profiles
  has_many :active_addresses_by_date, through: :profiles,
    source: :addresses, class_name: Address,
    conditions: ['address.is_active = ?', true],
    order: 'address.updated_at DESC'
end

class UsersController < ApplicationController
  def index
    @users = User.includes(profiles: :active_addresses_by_date)
  end
end

但由于我无法在active_by_date上重用Address范围,因此条件和顺序现在存在于两个地方。我想干这个,以便像在第一个版本中那样,“按日期激活地址”的概念仅存在于Address模型中。理想情况下,在视图中,我可以在不触发任何查询的情况下调用@users.each { |user| user.addresses.active_by_date }。这是否可以在ActiveRecord下进行,如果是这样,我将如何进行呢?

1 个答案:

答案 0 :(得分:0)

也许我不理解某些内容,但如果您将active_by_date更改为

,就会发生这种情况
  def self.active_by_date
    where("addresses.is_active = ?", true).order('addresses.updated_at DESC')
  end

然后才能调用User.includes(profiles: :addresses).active_by_date