对ActiveSupport :: Concern的担忧

时间:2012-10-26 22:29:05

标签: ruby-on-rails

我需要为现有模型添加一组通用方法。我找到了这个教程:

http://chris-schmitz.com/extending-activemodel-via-activesupportconcern/

在我看来是我的目标(我希望有一个模块可以添加到模型中来添加一些方法 - 一种混合)。

现在即使我从教程中做了普通的复制粘贴,我也会对以下错误感到震惊(没有进一步的解释):

undefined method `key?' for nil:NilClass

以下是我的模型:

class Folder < ActiveRecord::Base  
  attr_accessible :name, :parent_id  

  has_default

  validates :name, presence: true
end

我删除 has_default 的那一刻一切都恢复正常

1 个答案:

答案 0 :(得分:5)

再次检查您的代码......

模块结构可能看起来像这样(取自我的一个肯定有效的项目):

# lib/taggable.rb

require 'active_support/concern'

module Taggable
  extend ActiveSupport::Concern

  module ClassMethods
    def taggable
      include TaggableMethods # includes the instance methods specified in the TaggableMethods module
      # class methods, validations and other class stuff...
    end
  end

  module TaggableMethods
    # instance methods...
  end
end

缺少的是你应该告诉Rails从lib目录加载模块:

# config/application.rb

module AppName
  class Application < Rails::Application
    # Custom directories with classes and modules you want to be autoloadable.
    # config.autoload_paths += %W(#{config.root}/extras)
    config.autoload_paths += %W(#{config.root}/lib)

    # rest ommited...

现在应该包括模块。

# model.rb

class Model
  taggable

end

这就是基本插件的工作原理。您的问题中提到的教程的作者只为从ActiveRecord::Base继承的模型编写了一个插件,因为他正在使用其特定的方法(例如update_column)。

如果您的模块不依赖于ActiveRecord方法,则无需对其进行扩展(该模块也可能由Mongoid模型使用)。但这肯定是 NOT 正确的方式:

class ActiveRecord::Base
  include HasDefault
end

如果你真的需要扩展ActiveRecord,请这样做:

ActiveRecord::Base.extend ModuleName

当然,还有很多其他方法可以根据您的需要编写插件,并采用各种方式gems作为一个很好的灵感。