2012-04-11 28 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 
...