根据其他模型创建动态范围

时间:2018-08-03 11:58:21

标签: ruby-on-rails

在Rails(5.0)应用程序中,我具有以下内容

class Batch < ApplicationRecord
  belongs_to :zone, optional: false
end

class Zone < ApplicationRecord
  scope :lines, -> { where(kind: 'line') }
end

现在,我需要在Batch中为每个Zone定义一行的范围。类似于下面的代码。

  Zone.lines.map(&:name).each do |name|
    scope "manufactured_on_#{name}".to_sym, -> { joins(:zone).where("zones.name = '#{name}'") }
  end

问题在于,上面的代码在应用启动时进行评估,并在那时创建范围。如果添加类型为Zone的新line,则不会创建范围。

有没有办法解决这个问题?

3 个答案:

答案 0 :(得分:3)

您可以将区域名称作为范围参数传递

scope :manufactured_on, -> (name) { joins(:zone).where(zones: { name: name } ) }

答案 1 :(得分:0)

您可以查看文档并搜索method_missing

但这对我来说似乎不是一个好方法。

相反,请通过以下方式定义范围:

class Batch < ApplicationRecord
  scope :manufactured_on, ->(line) { joins(:zone).where("zones.name = '#{name}'") }
end

然后只需使用

Batch.manufactured_on(zone.name)

答案 2 :(得分:0)

如果您确实需要动态作用域名称,可以使用method_missing,如下所示:

\t

现在,您可以正常调用此作用域了:

class Batch < ApplicationRecord
  belongs_to :zone, optional: false

  def self.method_missing(name, *args)
    method_name = name.to_s

    if method_name.start_with?('manufactured_on_')
      zone_name = method_name.split('manufactured_on_')[1]
      joins(:zone).where(zones: { name: zone_name } )
    else
      super
    end
  end

  def self.respond_to_missing?(name, include_private = false)
    name.to_s.start_with?('manufactured_on_') || super
  end
end