Контекст
У меня есть пять моделей: Reward, BrandSubscription, Brand, Tier и User.
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)
SQL-запрос, который я хочу получить, следующий: я могу получить все доступные вознаграждения от пользователя. Обратите внимание, что я присоединяюсь к таблице 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
Я считаю, что некоторые Arel могут помочь, но мне бы очень хотелось, чтобы я мог полностью полагаться на ActiveRecord для этого, так как код был бы намного чище.
использованная литература
Я использую следующие ссылки, чтобы попытаться решить эту проблему:
- Дважды присоединиться к одной и той же таблице с условиями
- https://robots.thoughtbot.com/using-arel-to-compose-sql-queries
- http://jpospisil.com/2014/06/16/the-definitive-guide-to-arel-the-sql-manager-for-ruby.html
- https://gist.github.com/mildmojo/3724189
- http://jpospisil.com/2014/06/16/the-definitive-guide-to-arel-the-sql-manager-for-ruby.html
- Запрос ActiveRecord с псевдонимами имен таблиц