Rails 3.2 - 未定义的方法`where'为#

时间:2013-04-16 16:15:21

标签: ruby-on-rails ruby-on-rails-3 sqlite postgresql

我正在尝试将给定Header的字段与Alarm模型中的其他字段进行比较。正如您在代码中看到的,我在3个不同的步骤中过滤警报。前2个工作完美。但是,最后一个不起作用。 它说:

undefined method `where' for #<Array:...

据我所知.where是一个与数组一起使用的类方法。为什么不在这里工作? 我也尝试了.find_all_by和不同的事情......但是没有用。

@header = Header.find(1)

# Extracts those alarms that are ACTIVE and have something in common with the tittles
@alarmsT = Alarm.activated.where("keyword in (?)", [@header.title_es, @header.title_en, @header.title_en])

# Extracts alarms when Header has at least the same categories as an alarm
@alarmsT = @alarmsT.select do |alarm| 
   @header.category_ids.all?{|c| alarm.category_ids.include? c }
end

// this is the one that does NOT work
# Extract alarms which share the same location as Header.events' town
@alarmsF = [] 
@header.events.each do |e|
    @alarmsF =  @alarmsF + @alarmsT.where("alarms.location LIKE ?", e.town)
end

任何帮助发现我所缺少的东西都非常感激。感谢

2 个答案:

答案 0 :(得分:6)

在第一行中,您成功返回了ActiveRecordRelation

中的@alarmsT个对象
# Extracts those alarms that are ACTIVE and have something in common with the tittles
@alarmsT = Alarm.activated.where("keyword in (?)", [@header.title_es, @header.title_en, @header.title_en])

此时,您可以在.where(...)上应用其他@alarmsT方法,条件或范围,以进一步构建ARel表达式并返回结果。

但是,您可以对此关系运行过滤器,将@alarmsT转换为Array的实例

# Extracts alarms when Header has at least the same categories as an alarm
@alarmsT = @alarmsT.select do |alarm| 
   @header.category_ids.all?{|c| alarm.category_ids.include? c }
end

您无法再建立ARel表达式,因为Array不知道您的ARel的.where(...)方法,或任何Alarm模型的范围或属性。这就是为什么在下面的代码中您收到undefined method 'where' for #<Array:...错误 - 您在.where()的实例上调用Array;一种不存在的方法。

@alarmsF = [] 
@header.events.each do |e|
  @alarmsF =  @alarmsF + @alarmsT.where("alarms.location LIKE ?", e.town)
end

您可以通过不按类别ID进行过滤而使用连接来解决此问题。构建这样的连接(以验证相关表/列中至少存在一个值的子集)在很容易通过谷歌和StackOverflow找到的地方进行了详细记录。

答案 1 :(得分:3)

就像@Deefour说的那样,select使用Array代替ActiveRecord::Relation对象收集数据。

您确定需要LIKE查询吗?通过观察它我猜你可以用一个简单的直接比较。如果我的假设是正确的,您可以重新排列代码的最后部分:

@alarmsF = []
towns_from_events = @header.events.collect(&:town)

@alarmsT.each do |alarmsT|
    @alarmsF << alarmsT if towns_from_events.include?(alarmsT.location)
end