2014-02-18 35 views
2

我有一個用戶和一個付款模型。用戶有很多付款,付款有一個用戶。爲了搞清楚,如果用戶有一個有效的支付,我用這個:如何儘可能高效地編寫Rails模型關係範圍

User.rb

def payment_active? 
    payments.where("? >= made_at and ? <= valid_until", DateTime.now, DateTime.now).any? 
end 

我想定義返回用戶主動支付一個範圍,我想出這個:

User.rb

def self.active_users 
    User.all.select {|u| u.payment_active?} 
end 

會是怎樣寫一個這樣的範圍內適當的,更有效的方式?

回答

2

你可以請執行以下操作:

scope :with_active_payments, ->(datetime = nil) { 
    includes(:payments).where('payments.made_at >= :now AND :now <= payments.valid_until', now: datetime || DateTime.current) 
} 
  • 使用DateTime.current正確使用您當前的時區。
  • 使用.joins(:payments)(而不是包含)可使範圍返回用戶的非uniq的列表
  • 您可以傳遞一個日期時間到這個範圍,而不是現在使用的:User.with_active_payments(DateTime.current - 1.months)
1

您想對payments表使用內連接。這可能會實現:

User.joins(:payments).where('payments.made_at <= ? and payments.valid_until >= ?', DateTime.now, DateTime.now) 

作爲一個範圍,它可能是這樣的:

class User < ActiveRecord::Base 

    scope :active_users, -> { 
    joins(:payments).where('payments.made_at <= ? and payments.valid_until >= ?', DateTime.now, DateTime.now) 
    } 

end 
+0

這不返回uniq用戶列表。使用連接可以在結果數組中複製記錄。改用'.includes(:payments)'。 – MrYoshiji

+0

MyYoshiji有一點。如果您的數據包含進行多次付款的用戶(例如,他們是「雙重活動」),那麼每次符合條件時該用戶將被退回一次。 – GSP

2

至於GSP說ActiveRecord的或使用Mongoid以下查詢:

User.where(:id.in => Payment.where(:made_at <= DateTime.now, :valid_until >= DateTime.now).distinct(:user_id))