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

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

我想通过 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

共收到 4 条回复
9442

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

18898

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

46

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

2650

@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

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