我有五种模式:奖励,品牌订阅,品牌,级别和用户。
Brand
有很多Tiers
。BrandSubscription
属于Tier
和User
。Reward
属于Tier
。Tier
有一个名为order
的属性。如果BrandSubscription
具有更高级别的等级,它也将具有所有较低等级。BrandSubscription
可以查看其Rewards
中的所有Tiers
,在这种情况下,Tier
所属的Tiers
及其所有has_many :rewards
BrandSubscription
我的问题在于上面列表的最后一项。我试图获得品牌订阅的所有奖励。
理想的方式是through: :tier
实体上的Tier
,即has_many :rewards
。在order
我可以has_many :rewards
。此方法的问题在于奖励不限于当前层,但必须包括来自较低Tier
层的所有奖励。
为实现这一目标,我将范围放在class Tier < ActiveRecord::Base
belongs_to :brand
has_many :rewards
has_many :with_lower_tiers, lambda {
where(this_table[:order].gteq(that_table[:order]))
}, through: :brand, source: :tiers
has_many :achievable_rewards, through: :with_lower_tiers, source: rewards
end
模型的this_table
上:
that_table
此处的问题是class Tier < ActiveRecord::Base
belongs_to :brand
has_many :rewards
has_many :with_lower_tiers, lambda { |tier|
where(current_scope.table[:order].lteq(tier.order))
}, through: :brand, source: :tiers
has_many :achievable_rewards, through: :with_lower_tiers, source: rewards
end
和tier
。我需要在这里进行某种联接,所以我可以在表格之间进行比较。我可以做的一种方法是:
BrandSubscription
这里我使用了层所有者对象并获得了它的顺序。这里的问题是我不能真正依赖BrandSubscription.joins(:with_lower_tiers)
论证。跟随查询已经中断,因为作为参数传递给范围函数的是&#34;所有者&#34;查询的实体,在本例中为tiers
:
SELECT DISTINCT rewards.*
FROM tiers
INNER JOIN brand_subscriptions ON tiers.id = brand_subscriptions.tier_id
INNER JOIN tiers tiers_reward ON tiers_reward.brand_id = tiers.brand_id
INNER JOIN rewards ON tiers_reward.id = rewards.tier_id
WHERE tiers_reward.order <= tiers.order
AND brand_subscriptions.user_id = 1234
我想得到的SQL查询如下,我可以从用户那里获得所有可用的奖励。请注意,我两次加入{{1}}表,这正是我遇到麻烦的地方:
{{1}}
我相信一些Arel可能会有所帮助,但如果我完全依赖ActiveRecord,我真的很乐意,因为代码会更清晰。
我使用以下链接尝试解决此问题:
答案 0 :(得分:0)
您可以自己构建查询,而不是依赖复杂的has_many-through关联
class Reward < ActiveRecord::Base
belongs_to :tier
end
class Brand < ActiveRecord::Base
has_many :tiers
end
class Tier < ActiveRecord::Base
belongs_to :brand
has_many :rewards
# has_many :lower_tiers, ->(tier){ where('tiers.order < ?', tier.order) }, through: :brand, source: :tiers
def lower_tiers
Tier.where('brand_id = ? AND order < ?', brand_id, order)
end
def achievable_rewards
Rewards.where('tier_id IN (?) OR tier_id = ?', lower_tiers.select(:id), id)
end
end
class BrandSubscription < ActiveRecord::Base
belongs_to :user
belongs_to :tier
def rewards
tier ? tier.achievable_rewards : Reward.none
end
end