我对如何制作这个范围或方法感到困惑。我有以下协会:
模型
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
答案 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)重新加载记录。
让我知道它是怎么回事。