在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
,则不会创建范围。
有没有办法解决这个问题?
答案 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