Ruby on rails 创建方法或范围以显示较低的价格?

Ruby on rails 创建方法或范围以显示较低的价格?,ruby-on-rails,ruby,ruby-on-rails-3,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 c

我不知道该如何定义这个范围或方法。我有以下协会:

模型

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

如果你可以假设你拥有的每一个产品都有订阅,那么这应该适合你

  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.findrec.id重新加载记录


让我知道它是如何运行的。

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

对于订阅产品或用户产品,也存在一些混淆。我看到了多态关联,但我怀疑有一些混淆

我注意到Subscription有一个product_id,所以它告诉我Subscription属于product,而不是Subscriptable,或者除此之外,还属于Subscriptable

因此,首先您可能需要清理您的设计

然而,假设我可以相信这是您想要的,您在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
这将给你一个报告,所有较便宜的价格,你会发现整体。对于给定用户产品记录的所有较便宜的价格,您需要包括一个条件,即它是针对给定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是否可以从关联中形成联接。我知道Rails2.3API需要一个字符串。因此,范围将是:

 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
...

我想你正在创建一个网站,用户可以输入他们找到的价格,然后订阅以找到更便宜的价格。我将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

我也不知道该怎么做。我必须复制UserProduct或Price属性,这样它才知道如何检查更便宜的价格。由于订阅和价格有相同的字段,我想我可以比较这两种型号。因此,订阅将与所有价格进行比较。此外,您对我的网站的看法是正确的。用户必须输入新的价格。我把模型改成了价格模型,所以从现在到将来都是如此。谢谢,是的。起初,我没有注意到订阅实体有一个价格字段。我假设在用户界面的某个地方,您将获得订阅。我的另一个方法是让价格模型有方法返回更便宜的价格。基本上,对于这个答案中给出的作用域,任何能够提供产品id和价格的对象都可以使用作用域。我不明白为什么这会给我一个未定义的方法错误。我将模型改为Price,属性改为:cost,用户订阅价格。我编辑了我的答案以反映这些变化。按照我在答案中描述的方式,它是订阅对象的一种方法。因此,您需要订阅对象,然后调用它。调用更便宜的代码是什么样子的?
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