6

首先,我正在遵循此处针对 Rails 问题的做法(好主意!):https ://gist.github.com/1014971

我收到一个错误:

undefined method `search' for #<Class:0x5c25ea0>
app/controllers/accessories_controller.rb:6:in `index'

我确实在/config/application.rb中加载了我的 /app/models/concerns/ 目录。所以“关注”模块正在被加载。只是想指出这一点。

这是我的代码:

/app/models/concerns/searchable.rb

module Searchable
  extend ActiveSupport::Concern

  # Add a "search" scope to the models
  def self.search (search)
    if search
      where('name LIKE ?', "%#{search}%")
    else
      scoped
    end
  end
end

/app/models/accessory.rb

class Accessory < ActiveRecord::Base
  include Searchable

  ...
end

/app/controllers/accessories_controller.rb

class AccessoriesController < ApplicationController

  def index
    @accessories  = Accessory.search(params[:search])

    ...
  end

end
4

3 回答 3

9

好吧,再玩一会,我就知道出了什么问题!

当您想从模块中直接修改模型时(关注),您需要将功能包装在包含的块中。

我已将我的关注模块更改为以下内容:

    module Searchable
        extend ActiveSupport::Concern

        included do
            # Add a "search" scope to the models
            def self.search (search)
                if search
                    where('name LIKE ?', "%#{search}%")
                else
                    scoped
                end
            end
        end

    end

这就对了!希望这会帮助其他有同样问题的人!

于 2012-07-17T01:34:10.333 回答
8

这是一个不错的解决方案,但并不是最好的解决方案。当您在其上构建模块时,ActiveSupport::Concern您可以在您的关注点中包装一个调用ClassMethods的模块,并且任何包含您关注点的模块都将自动使用该ClassMethods模块进行扩展。

那么,更好的解决方案是:

module Searchable
  extend ActiveSupport::Concern

  module ClassMethods
    def search(search)
      if search
        where('name LIKE ?', "%#{search}%")
      else
        scoped
      end
    end
  end
end

那(IMO)更清楚地表达了您的意图:将类级方法放入类中。

虽然您的方法有效,included但当您需要在调用类上调用方法时,最好使用该方法。例如,您可以坚持让您的Searchable对象具有 db-backedname属性,如下所示。该included方法是将presence验证器添加到调用类中,并且您用于扩展该类的方法是明确分开的。

module Searchable
  extend ActiveSupport::Concern

  def self.included(base)
    base.send :validates_presence_of, :name
  end

  module ClassMethods
    def search(search)
      if search
        where('name LIKE ?', "%#{search}%")
      else
        scoped
      end
    end
  end
end
于 2013-04-12T13:58:32.550 回答
2

正如AndyV 指出的那样,正确的解决方案是:

module Searchable
  extend ActiveSupport::Concern

  module ClassMethods
    def search(search)
      if search
        where('name LIKE ?', "%#{search}%")
      else
        scoped
      end
    end
  end
end

并且不像您在解决方案中所做的那样self.search在块中定义,这更冗长且不那么明确。included

但我不同意 AndyV 在self.included. 如果你使用ActiveSupport::Concern,那是有included块语法糖,所以你应该使用它。我只依赖于self.included我调用的方法的顺序或我定义的方法的重要性。

于 2013-05-04T21:29:52.187 回答