Как динамически сравнить объединенную таблицу с источником
Контекст
У меня есть пять моделей: 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 с псевдонимами имен таблиц
1 ответ
Вы можете построить запрос самостоятельно, вместо того чтобы полагаться на сложные ассоциации 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