Получить псевдоним динамической таблицы в области Rails - PullRequest
0 голосов
/ 06 июня 2018

У меня есть две области, которые используются большинством моих моделей.У них есть сырой SQL, который напрямую ссылается на имя таблицы модели, и это плохо сочетается с Arel:

class ApplicationRecord < ActiveRecord::Base
  valid = lambda do |positive = true|
    if %w[validForBegin validForEnd].all? { |c| base_class.column_names.include?(c) }
      condition = "NOW() BETWEEN #{base_class.table_name}.validForBegin AND #{base_class.table_name}.validForEnd"
      condition = "!(#{condition})" unless positive
      where(condition)
    end
  end

  scope :valid, valid
  scope :invalid, -> { valid(false) }
end

# Sample usage

class Party < ApplicationRecord
  has_one :name,
    -> { valid },
    class_name: 'PartyName',
    foreign_key: :partyId,

  has_many :expired_names,
    -> { invalid },
    class_name: 'PartyName',
    foreign_key: :partyId,
end

Так как моя область действия напрямую связана с table_name модели, я не могу присоединиться кОбе ассоциации:

Party.joins(:name, :expired_names).first

# Produces this sequel statement

SELECT `party`.*
FROM `party`
INNER JOIN `party_name` ON `party_name`.`partyId` = `party`.`id`
AND (NOW() BETWEEN party_name.validForBegin AND party_name.validForEnd)
INNER JOIN `party_name` `expired_names_party` ON `expired_names_party`.`partyId` = `party`.`id`
AND (!(NOW() BETWEEN party_name.validForBegin AND party_name.validForEnd))
ORDER BY `party`.`id` ASC LIMIT 1

Обратите внимание, что оба условия 'И' для объединений относятся к таблице party_name.Второй должен вместо этого ссылаться на expired_names_party, динамически генерируемый псевдоним таблицы.Для более сложных запросов Rails, когда Arel назначает псевдоним для КАЖДОЙ таблицы, оба соединения завершатся неудачно.

Возможно ли, чтобы моя область использовала псевдоним, назначенный ей Arel во время выполнения ?

1 Ответ

0 голосов
/ 11 июня 2018

Я создал этот репозиторий, чтобы проверить вашу ситуацию: https://github.com/wmavis/so_rails_arel

Я считаю, что проблема заключается в том, что вы пытаетесь использовать один и тот же класс для обоих отношений.По умолчанию rails хочет использовать имя класса для таблицы, связанной с этим классом.Поэтому он использует имя таблицы party_name для обоих запросов.

Чтобы обойти эту проблему, я создал класс ExpiredName, который наследуется от PartyName, но говорит рельсам использовать таблицу expired_names: https://github.com/wmavis/so_rails_arel/blob/master/app/models/expired_name.rb

class ExpiredName < PartyName
  self.table_name = 'expired_names'
end

Кажется, это решает проблему в моем коде:

Party.joins(:name, :expired_names).to_sql
 => "SELECT \"parties\".* FROM \"parties\" 
INNER JOIN \"party_names\" 
  ON \"party_names\".\"party_id\" = \"parties\".\"id\" 
INNER JOIN \"expired_names\" 
  ON \"expired_names\".\"party_id\" = \"parties\".\"id\""

Дайте мне знать, если это не работает для вас, и я постараюсь помочь.

...