Rails 为 module 使用 ActiveSupport::Concern 并 include 后,怎样马上使用 include 后的方法?

bindiry · 2016年10月31日 · 最后由 blueplanet 回复于 2016年11月01日 · 2201 次阅读

我想通过 ActiveSupport::Concern 将一个 module 里的实例方法引入到 module 中,但发现在 include 后,不能马上使用这个方法。

代码如下:

# writable.rb
module Writable
  extend ActiveSupport::Concern

  included do
    attr_reader :write_worker
  end

  def set_options(worker)
    @worker = worker
  end
end
# user.rb

class User < ApplicationRecord
  include Writable
  set_options("UserWorker") # 这里因为每个model需要传入不同的参数,所在需要单独在每个被include的model中调用
end

这时候我去 new 这个类的时候会出错,找不到 set_options 方法

# console
user = User.new
# => undefined method `set_options' for #<Class:0x007f909bec0508>

如果我把这个方法放在 after_initialize 里,就可以正常,但感觉很啰嗦

# user.rb
class User < ApplicationRecord
  include Writable
  after_initialize do
    set_options(xxxx)
  end
end

请问有没有办法在不使用 after_initialize 的情况下让代码晚优雅简练地达到目的?


之前搞错了概念,用如下方式就可以在实例方法里取类成员属性,不用加 after_initialize 了。

module Workable
  def self.included(base)
    base.extend ClassMethods
    #include InstanceMethods
    base.send(:include, InstanceMethods)
  end

  module ClassMethods
    attr_reader :worker
    def set_options(worker: nil)
      @worker = worker
    end
  end

  module InstanceMethods
    def get_options
      puts "worker: #{self.class.worker}"
    end
  end

end

class Test
  include Workable
  set_options(worker: 'worker1')
end

class Test2
  include Workable
  set_options(worker: 'worker2')
end

Test.new.get_options # => worker1
Test2.new.get_options # => worker2

文档 include 后是实例方法,extend 才是类方法。用那个库可以看 class_methods 部分

概念没理清。。。 你在 User 里调用的set_options方法是类方法 (class_method), 而你在writable里把set_options定义成实例方法 (instance_method) 因此,after_initialize里可以用,因为这里面是实例的功能范围 (scope)

#1 楼 @flowerwrong #2 楼 @flemon1986 谢谢回复,明白了,看来只能在 after_initialize 里调用了。

@bindiry 1 楼的回答是正确的方法。 如果你想定义类方法,把你的方法定义在ClassMethods这个 module 里面就可以了。

module Writable
  extend ActiveSupport::Concern

  included do
    attr_reader :write_worker
  end

  module ClassMethods
    def set_options(worker)
      @worker = worker
    end
  end
end

bindiry 关闭了讨论。 11月01日 08:15
需要 登录 后方可回复, 如果你还没有账号请 注册新账号