【问题标题】:Rails 3 - Undefined method on certain collectionsRails 3 - 某些集合上的未定义方法
【发布时间】:2011-03-11 21:32:19
【问题描述】:

我为我的模型 Link 编写了一个搜索方法。

在实施投票​​之前,我已经能够毫无错误地调用此方法。例如,这些都有效:

Link.search(params[:search])
current_user.links.search(params[:search])
current_account.links.search(params[:search])

以下不起作用:

@links = current_user.votes.collect {|vote| vote.voteable}
@favorites = @links.search(params[:search])

并返回此错误:

 undefined method `search' for #<Array:0x00000006919ac8>

我已经在控制台中进行了一些测试,看看我的班级是否有误:

links = user.votes.map {|vote| vote.voteable}
links.class
 => Array 
links.first.class
 => Link

这应该与我的工作示例没有什么不同:

user.links.class
 => Array
user.links.first.class
 => Link

我认为错误可能是我在数组上调用搜索而不是链接造成的。但在前面的示例中,我也在数组上调用它。

我正在使用 vote_fu 来处理投票,因此投票/可投票。

【问题讨论】:

    标签: ruby-on-rails arrays ruby-on-rails-3 activerecord


    【解决方案1】:

    您定义的搜索函数或范围是在 Link 对象上定义的,并且可以在 Link 关系中使用,但它不是在简单数组上定义的,这是从第一个 collect 示例返回的内容。这是一个简单的区别:

    class User
      scope :search, lambda{ |name| where(name: name) }
    end
    
    User.search('Kombo').all # Returns an array of the SQL result run against the DB
    User.all.search('Kombo') # NoMethodError: undefined method `search' for #<Array:0x000001079b15b0>
    

    在您的第一个示例Link.search(params[:search]) 中,您正在执行与User.search.all 等效的操作,并且 User 是一个作用域 ActiveRecord 关系/对象,这意味着它可以继续与其他作用域组合,例如 where、limit 和 group .在第二个示例@links = current_user.votes.collect {|vote| vote.voteable} 中,collect 作用于这样的关系并返回一个简单的数组,这些作用域函数不能再作用于该数组。第二个例子就像在做User.all.search

    这很令人困惑,因为这两个示例最终都会解析为数组,但不同之处在于在解析为数组之前以及您实际调用搜索函数时发生了什么。要解决这个问题,您必须实际调用 ActiveRecord 对象(如 Link)或 ActiveRecord 关系(如current_user.links)上的搜索范围或函数,但您无法在结果上调用它。澄清一下:

    Link.search(params[:search]) # will work
    Link.all.search(params[:search]) # will not work
    
    current_user.links.search(params[:search]) # will work
    current_user.links.all.search(params[:search]) # will not work
    
    current_account.links.search(params[:search]) # will work
    current_account.links.all.search(params[:search]) # will not work
    

    当您调用 .collect 时,您会隐式调用 .all,这会破坏作用域链。以下两个命令在这方面是等价的:

    @links = current_user.votes.collect {|vote| vote.voteable}
    @links = current_user.votes.all.collect {|vote| vote.voteable}
    

    【讨论】:

    • 说得有道理,潘。我非常感谢今天下午的帮助。我想可能是这种情况,但是当我使用 .class 产生相同的响应时,我对控制台中的测试感到困惑。我真的很感激,我认为有了这些知识,我就能让这件事发挥作用:)。对您有很好的理解。
    • 对于任何发现此问题并需要完整答案的人。我按照潘所说的,从投票中找到了一个集合,并使用 links.search 找到了另一个集合。然后我将两个数组相交。
    • 这似乎并不完全正确,因为我正在查看一个代码库,他们在其中调用类似于Link.all.search(params[:search]) 的东西。并且在运行作用域方法之前的类型是 Array 类型。关于它如何工作的任何想法?我不得不从 Rails 中提取部分代码库,并使用已定义范围的模型中的一些功能。我知道它应该是一个 ActiveRecord::Relation 但这不是类型。
    猜你喜欢
    • 2011-04-22
    • 2012-02-26
    • 1970-01-01
    • 2015-05-06
    • 2011-12-02
    • 2011-11-28
    • 2016-06-17
    • 2012-01-19
    • 2011-10-19
    相关资源
    最近更新 更多