2012-04-11 46 views
2

我很困惑我應該如何制定這個範圍或方法。我有以下的關聯:創建方法或範圍以顯示較低的價格?

模型

class User 
    has_many :prices 
    has_many :products, :through => :prices 
    has_many :subscriptions, :foreign_key => :subscriber_id 
end 

class Product 
    has_many :prices 
    has_many :users, :through => :prices 
end 

class Price 
    # Table columns => :product_id, :cost, :user_id 
    belongs_to :user 
    belongs_to :product 
    belongs_to :store 
    has_many :subscriptions, :as => :subscribable 
end 

class Subscription 
    # Table columns => :product_id, :cost, :subscriber_id, :subscribable_id 
    # :subscribable_type 
    belongs_to :subscriber, :class_name => "User" 
    belongs_to :subscribable, :polymorphic => true 
    validates_uniqueness_of :subscribable_id, :scope => 
         [ :subscriber_id, :subscribable_type] 
end 

所以方法應該是這樣的:

class Price 

def self.lower_price 
    if self.product_id == self.subscription.product_id 
    if self.cost < self.subscription.cost 
    end 
    end 
end 

end 

什麼這種方法是假設做的是隻顯示UserProducts較低的價格屬於與Subscription相同Product,同時將其自身與訂閱price字段進行比較以查看其是否更低。

我正在做這個對嗎?什麼需要解決?


編輯

class Price < ActiveRecord::Base 
    scope :for_product, lambda { |product_id| where(:product_id => product_id) } 
    scope :cheaper, lambda { |cost| where(["prices.cost < :cost", { :cost => cost } ]) } 
end 

class Subscription < ActiveRecord::Base 

    def cheaper_prices 
    Price.for_product(product_id).cheaper(cost) 
    end 
end 

PrivatePagesController: 

def watch 
@prices = Price.cheaper_prices.paginate(:page => params[:page], :per_page => 20).order('purchase_date DESC') 
end 

This gives me the error: 

NoMethodError in PrivatePagesController#watch 

undefined method `cheaper_prices' for #<Class:0x6f99210> 

回答

1

我想,你是一個網站,用戶輸入他們發現價格和訂閱找到更便宜的價格。我會將UserProduct實體重命名爲Price。

訂閱者是訂閱產品還是訂閱價格是不明確的。如果你清除它,它可能會簡化多態關聯。假設他們訂購具有給定價格的產品。那麼你想要以下內容:

class Price 
    # Table columns => :product_id, :price, :user_id 
    belongs_to :finder, :class_name => "User" 
    belongs_to :product 
    belongs_to :store 

    scope for_product, lambda { |product_id| where(:product_id => product_id) 
    scope cheaper, lambda { |price| where([ "prices.price < :price", {:price => price} ] } 
end 

class Subscription 
    # Table columns => :product_id, :price, :subscriber_id 
    belongs_to :subscriber, :class_name => "User" 
    belongs_to :product 
    validates_uniqueness_of :subscribable_id, :scope => 
         [ :subscriber_id, :subscribable_type] 

    def cheaper 
    Price.for_product(product_id).cheaper(price) 
    end 
end 
+0

我也很困惑如何去做這件事。我必須複製'UserProduct'(或'Price')屬性,以便知道如何檢查便宜的價格。由於'Subscription'和'Price'具有相同的字段,我想我可以比較這兩個模型。所以'訂閱'將與所有的「價格」進行比較。 – LearningRoR 2012-04-12 14:58:42

+0

另外,你對我的網站是正確的。用戶必須輸入新的價格。我改變了模型爲'價格',所以它從現在開始,並在未來。謝謝。 – LearningRoR 2012-04-12 15:00:20

+0

是的。起初我沒有注意到認購實體有價格字段。我假設你的用戶界面的某個地方,你會得到訂閱。我的另一種方法是讓價格模型有辦法返回更便宜的價格。基本上,通過本答案中給出的範圍,任何可以提供產品ID和價格的對象都可以使用範圍。 – 2012-04-12 17:40:48

0

,如果你可以認爲每一個你有產品,有認購比這應該爲你工作

scope :lower_priced_user_products, self.joins("join subscriptions on subscriptions.product_id = user_products.product_id").where("user_products.product_id < subscriptions.product_id") 

這將返回一個只讀記錄。如果你想讀/寫訪問,那麼你應該使用UserProduct.find(rec.id)重新加載記錄。

讓我知道它是怎麼回事。

1

首先,您應該將UserProduct表命名爲更有意義。除了作爲鏈接表,我無法分辨它的語義。

訂閱產品或用戶產品也存在一些混淆。我看到了多態關聯,但我懷疑存在一些混淆。

我注意訂閱有一個product_id,這樣告訴我訂閱屬於產品,而不是或者除了屬於可訂閱的。

所以,首先你可能需要清理你的設計。

但是,假設我可以把你的條件對信仰它,你想要什麼,你想在SQL什麼是

SELECT cheaper.* 
FROM user_products 
    INNER JOIN subscriptions ON subscribable_type = 'UserProduct' 
          AND subscriptions.subscribable_id = user_products.id 
    INNER JOIN user_products cheaper ON cheaper.product_id = subscriptions.product_id 
WHERE cheaper.price < user_products.price 

這將會給你所有的價格便宜,你會總髮現的報告。對於給定user_products記錄的所有較便宜的價格,您需要包含一個條件,即它適用於給定的id。

接下來,使在ActiveRecord的這項工作,我們希望選擇要在桌子上的課,讓我們改造的SQL

SELECT user_products.* 
FROM user_products 
    INNER JOIN subscriptions ON user_products.product_id = subscriptions.product_id 
    INNER JOIN user_products target ON subscribable_type = 'UserProduct' 
          AND subscriptions.subscribable_id = target.id 
WHERE user_products.price < target.price 
    AND target.id = ? 

現在,我們已準備好進行ActiveRecord的電話。

我不知道ActiveRecord是否可以從關聯中形成連接。我知道Rails 2.3 API需要一個字符串。因此,適用範圍是:

class UserProduct 
    ... 

    #defines UserProduct.cheaper(user_product_id) 
    scope :cheaper, lambda do |user_product_id| 
    join(%Q{INNER JOIN subscriptions 
      ON user_products.product_id = subscriptions.product_id 
      INNER JOIN user_products target 
      ON subscribable_type = 'UserProduct' 
      AND subscriptions.subscribable_id = target.id}). 
    where("cheaper.price < user_products.price"). 
    where(["target.id = :target_id", { :target_id => user_product_id } ]) 
    end 

    #defines user_product.cheaper 
    def cheaper 
    UserProduct.cheaper(id) 
    end 
...