Rails 3 - 某些集合上的未定义方法

Kom*_*mbo 2 arrays activerecord ruby-on-rails ruby-on-rails-3

我有一个为我的模型Link编写的搜索方法.

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

Link.search(params[:search])
current_user.links.search(params[:search])
current_account.links.search(params[:search])
Run Code Online (Sandbox Code Playgroud)

以下不起作用:

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

并返回此错误:

 undefined method `search' for #<Array:0x00000006919ac8>
Run Code Online (Sandbox Code Playgroud)

我在控制台中做了一些测试,看看我的课程是否错误:

links = user.votes.map {|vote| vote.voteable}
links.class
 => Array 
links.first.class
 => Link
Run Code Online (Sandbox Code Playgroud)

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

user.links.class
 => Array
user.links.first.class
 => Link
Run Code Online (Sandbox Code Playgroud)

我想也许错误来自于我在数组上调用搜索而不是链接.但在之前的例子中,我也在一个数组上调用它.

我使用vote_fu处理投票,从而投票/投票.

Pan*_*kos 8

您定义的搜索功能或范围是在Link对象上定义的,可用于链接关系,但它没有在简单数组上定义,这是从第一个收集示例返回的内容.这是一个简单的区别:

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>
Run Code Online (Sandbox Code Playgroud)

在第一个示例中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 Relation 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
Run Code Online (Sandbox Code Playgroud)

当你打电话时,.collect你是隐式调用.all,这打破了范围链.在这方面,以下两个命令是等效的:

@links = current_user.votes.collect {|vote| vote.voteable}
@links = current_user.votes.all.collect {|vote| vote.voteable}
Run Code Online (Sandbox Code Playgroud)