Как динамически сравнить объединенную таблицу с источником

Контекст

У меня есть пять моделей: 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 для этого, так как код был бы намного чище.

Рекомендации

Я использую следующие ссылки, чтобы попытаться решить эту проблему:

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
Другие вопросы по тегам