2013-04-26 15 views
4

其分解到最低例如:上重用範圍如過濾器`includes`急切裝載

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 

但因爲我不能重複上Addressactive_by_date範圍,條件和訂單,現在在兩個地方存在。我想幹這個,所以和第一個版本一樣,只有在Address模型中才有「按日期激活地址」的概念。理想情況下,在我看來,我可以打電話@users.each { |user| user.addresses.active_by_date }而不發出任何疑問。這是可能的ActiveRecord下,如果是這樣,我會怎麼去呢?

+0

幾天前我偶然發現了這個問題。我最終重寫了該協會的訪問者,但很想看看還有哪些其他解決方案。 – AlexBrand 2013-04-26 17:48:25

+0

我不知道它甚至有可能重寫關聯方法,並且仍然具有「包含」功能,但我只是對它進行了測試,顯然是這樣。這是我的書中的一個改進,但它也增加了'用戶'模型中特定於「熱門加載」的「東西」的數量。像你一樣,我希望有更好的解決方案。 =) – Grantovich 2013-04-26 20:27:33

回答

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那會怎樣呢?

+0

'active_by_date'然後需要在'User'和'Address'上定義,重新引入條件/順序重複的問題。 – Grantovich 2013-06-27 16:00:06

+0

你可以通過模塊化的方式解決它,關注。只需將公共代碼輸出到單獨的模塊即可! – 2013-06-28 10:00:25

+0

如果想要重用範圍是很常見的 - 你會有許多小問題都只與一個模型有關。無論如何,我意識到這種方法不起作用的另一個原因:它只返回具有活動地址的用戶。我想返回_all_用戶,並且如果他們有任何請求,則熱切加載他們的活動地址。 – Grantovich 2013-07-09 20:35:31