在Rails范围

时间:2018-06-06 17:38:26

标签: ruby-on-rails associations

我有两个范围,我的大多数模型共享。它们具有直接引用模型表名的原始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

请注意,&#39; AND&#39;联接的条件是指表party_name。第二个应该是指动态生成的表别名expired_names_party。对于更复杂的Rails查询,其中Arel为每个表分配别名,两个连接都将失败。

我的作用域是否可以在执行时使用Arel分配给它的别名

1 个答案:

答案 0 :(得分:1)

我创建了这个回购来帮助测试你的情况: https://github.com/wmavis/so_rails_arel

我认为问题在于你正在尝试为两种关系使用相同的类。默认情况下,rails希望使用与该类关联的表的类名。因此,它使用表名party_name进行查询。

为了解决这个问题,我创建了一个继承自ExpiredName的{​​{1}}类,但告诉rails使用PartyName表: https://github.com/wmavis/so_rails_arel/blob/master/app/models/expired_name.rb

expired_names

这似乎解决了我的代码中的问题:

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

如果它对您不起作用,请告诉我,我会尽力帮助。