Ruby on Rails,包括带参数的模块

use*_*832 11 ruby ruby-on-rails

在包含ruby模块时有没有办法使用参数?我有一个模块Assetable,它包含在许多类中.我希望能够动态生成attr_accessor.

module Assetable
  extend ActiveSupport::Concern

  included do 
    (argument).times do |i| 
      attr_accessor "asset_#{i}".to_sym
      attr_accessible "asset_#{i}".to_sym
    end
  end
end 
Run Code Online (Sandbox Code Playgroud)

kin*_*pyo 21

有一个技巧:创建一个继承自模块的类,以便您可以将任何参数传递给模块,如类.

class Assetable < Module
  def initialize(num)
    @num = num
  end

  def included(base)
    num = @num

    base.class_eval do
      num.times do |i|
        attr_accessor "asset_#{i}"
      end
    end
  end
end

class A
  include Assetable.new(3)
end

a = A.new
a.asset_0 = 123
a.asset_0 # => 123
Run Code Online (Sandbox Code Playgroud)

详细信息请访问http://kinopyo.com/en/blog/ruby-include-module-with-arguments,希望您会发现它很有用.

  • 该死的,儿子!不错的解决方案。 (2认同)

Gab*_*ira 15

包含模块时无法传递参数.接下来最好的事情是定义一个类方法,让您在之后创建所需的内容:

module Assetable
  extend ActiveSupport::Concern
  module ClassMethods
    def total_assets(number)
      number.times do |i|
        attr_accessor "asset_#{i}"
        attr_accessible "asset_#{i}"
      end
    end
  end
end

class C
  include Assetable
  total_assets 3
end

o = C.new
o.asset_2 = "Some value."
o.asset_2  #=> "Some value."
Run Code Online (Sandbox Code Playgroud)

included在关注范围内覆盖方法时也要小心,因为它也被使用ActiveSupport::Concern.您应该super在overriden方法中调用以确保正确初始化.


ino*_*tus 6

您可以在不污染全局命名空间的情况下生成和包含匿名模块:

module Assetable
  def self.[](argument)
    Module.new do
      extend ActiveSupport::Concern

      included do 
        (argument).times do |i| 
          attr_accessor :"asset_#{i}"
          attr_accessible :"asset_#{i}"
        end
      end
    end
  end
end

class Foo
  include Assetable[5]
end
Run Code Online (Sandbox Code Playgroud)


Jör*_*tag 5

您不能将参数传递给模块.实际上,除了发送消息之外,您无法将参数传递给任何内容.

所以,你必须使用发送消息:

module Kernel
  private def Assetable(num)
    @__assetable_cache__ ||= []
    @__assetable_cache__[num] ||= Module.new do
      num.times do |i|
        attr_accessor   :"asset_#{i}"
        attr_accessible :"asset_#{i}"
      end
    end
  end
end

class Foo
  include Assetable 3
end
Run Code Online (Sandbox Code Playgroud)

注意:我根本不明白为什么你需要ActiveSupport::Concern这里,但很容易重新添加.