【问题标题】:What is the best way to specify global and per-class configuration for a Gem that extends ActiveRecord models in Ruby on Rails?为在 Ruby on Rails 中扩展 ActiveRecord 模型的 Gem 指定全局和每类配置的最佳方法是什么?
【发布时间】:2015-02-20 16:28:14
【问题描述】:

我有一个可以为 ActiveRecord 模型添加特定功能的 gem。我希望这个功能的一些参数是可修改的,无论是在全局级别,还是在将我的 gem 添加到每个模型时,以防某些模型需要不同的设置。

我正在这样做:

module Mygem
  @@config = nil

  def self.config(options={})
    defaults = {some_key: default_value}
    @@config ||= defaults
    @@config = @@config.merge(options)
    @@config
  end

  module ClassMethods
    def has_something_my_gem_adds(options={}) # method you call to add this functionality to your model
       options = Mygem.config.merge(options)

       # add functionality to the model

      define_method(:my_gem_options) { options } # I don't think this is the best way to store this, but I didn't find a better one.
    end

    def does_something
      if self.my_gem_options[:some_key]
      end
    end 
  end
end

我对创建“my_gem_options”方法不是很满意,但是我还没有找到一种很好的方法来存储该模型的配置信息,这样它们就可以用于所有我的 gem 中的方法。

最好的方法是什么?

此外,我也不知道为我的 gem 存储“全局”配置的最佳方式是什么,我将其存储在模块本身的 @@config 中。有没有更好的办法?

【问题讨论】:

    标签: ruby-on-rails configuration gem


    【解决方案1】:

    如果您想避免动态使用define_method,也许更简洁的版本是:

    module Foo
      DEFAULTS = {name: "foo"}
    
      def self.configure(options = {})
        @config = DEFAULTS.merge(options)
      end
    
      def self.config
        @config
      end
    
      configure({})
    
      def self.included(model)
        model.send(:extend, ClassMethods)
      end
    
      module ClassMethods
        def foo(options)
          @foo_config = Foo.config.merge(options)
        end
    
        def foo_config
          @foo_config
        end
      end
    
      def name
        self.class.foo_config.fetch(:name)
      end
    end
    
    class Bar
      include Foo
    
      foo(name: "bar")
    end
    
    puts Bar.new.name
    
    # => "bar"
    

    如果您想避免将配置存储在模型本身中(这可能是个好主意,但您会丢失一些语义,例如继承),那么您可以在主模块中使用哈希:

    module Foo
      DEFAULTS = {name: "foo"}
    
      def self.configure(options = {})
        @config = DEFAULTS.merge(options)
      end
    
      def self.config
        @config
      end
    
      def self.model_config
        @model_config ||= {}
      end
    
      configure({})
    
      def self.included(model)
        model.send(:extend, ClassMethods)
      end
    
      module ClassMethods
        def foo(options)
          Foo.model_config[self] = Foo.config.merge(options)
        end
      end
    
      def name
        Foo.model_config[self.class].fetch(:name)
      end
    end
    
    class Bar
      include Foo
    
      foo(name: "bar")
    end
    
    puts Bar.new.name
    
    # => "bar"
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-05-06
      • 2011-12-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-11-14
      • 2010-12-08
      相关资源
      最近更新 更多