创建一个方法或范围来显示更低的价格?

时间:2012-04-11 03:46:33

标签: ruby-on-rails ruby ruby-on-rails-3

我对如何制作这个范围或方法感到困惑。我有以下协会:

模型

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属于同一Product的{​​{1}}的较低价格,同时将其自身与订阅Subscription进行比较字段,看它是否更低。

我这样做了吗?需要修复什么?


修改

price

3 个答案:

答案 0 :(得分:1)

首先,您应该将UserProduct表命名为更有意义。除了作为链接表之外,我不知道它的语义是什么。

订阅产品或UserProduct也存在一些困惑。我看到了多态关联,但我怀疑存在一些混淆。

我注意到Subscription有一个product_id,因此告诉我Subscription属于Product,而不是或者除了属于subscribable之外。

所以,首先你可能需要清理你的设计。

然而,假设我可以凭信心确定你想要的东西,你想要的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中,我们希望select在表的类上,所以让我们将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
...

答案 1 :(得分: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

答案 2 :(得分: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)重新加载记录。

让我知道它是怎么回事。