Rails 3关注型号模块

时间:2012-07-17 01:05:59

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

首先,我正在关注Rails关注的实践(好主意!):https://gist.github.com/1014971

我收到了一个错误:

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

DO 在/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

3 个答案:

答案 0 :(得分: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

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

答案 1 :(得分: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-backed name属性,如下所示。 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

答案 2 :(得分:2)

作为AndyV points out,正确的解决方案是:

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,这更详细,更不明确。

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