如何根据名称自动在类中包含模块(如帮助器包含在视图中)

时间:2011-11-04 15:58:25

标签: ruby-on-rails

在我的应用程序中,我不得不与某些第三方软件接口,希望有一天能够更换。因此,我没有保留所有代码来映射我的模型数据和模型本身中第三方软件所需的表单,我为每个模型创建了一个mapper模块,隔离了代码在某个时候很容易删除的地方。

所以我有以下内容:

app/
  models/
    people.rb
  mappers/
    people_mapper.rb

理想情况下,我希望自动在模型类中包含匹配名称的模块,就像帮助程序自动包含在同名视图中一样。自动包含帮助程序的方式/位置,这也是我添加自己的代码的最佳位置吗?

1 个答案:

答案 0 :(得分:0)

你可以尝试这样的事情:

module Mapper::Core

  def self.included( base )
    base.extend( ClassMethods )
  end

  module ClassMethods

    # model class method to include matching module
    # this will throw an error if matching class constant name does not exist
    def has_mapping
      @mapper_class = Kernel.const_get( "Mapper::#{self}Mapper" )
      include @mapper_class
    end

    # an accessor to the matching class mapper may come in handy
    def mapper_class
      @mapper_class
    end

  end
end     

然后requireinclude初始化程序中ActiveRecord::Base中的模块(确保您的Mapper模块需要“mappers”文件夹中的所有文件,或者使用config.autoload_paths)。

如果您根本不想使用has_mapping类方法,可以尝试覆盖ActiveRecord::Base的{​​{1}}回调,但它可能会变得危险:

self.inherited

我没有尝试任何此类操作,因此谨慎行事

编辑:

我写这篇文章的时候累了。有一种更简单的方法可以自动包含匹配模块:

  def self.included( base )
    base.extend( ClassMethods )
    base.instance_eval <<-EOF
      alias :old_inherited :inherited
      def self.inherited( subclass )
        subclass.has_mapping
        old_inherited( subclass )
      end
    EOF
  end

用以下内容初始化:

module Mapper::Core
  def self.included( base )
    begin
      mapper_class = Kernel.const_get( "Mapper::#{base.name}Mapper" )
      base.instance_eval( "include #{mapper_class}" ) 
    rescue 
      Logger.info "No matching Mapper Class found for #{base.name}"
    end
  end
end

所有继承类现在都将ActiveRecord::base.instance_eval( 'include Mapper::Core' ) ,这将触发包含匹配类。