Ruby on rails 如何将模块包含到类中,以使模块覆盖该类?

Ruby on rails 如何将模块包含到类中,以使模块覆盖该类?,ruby-on-rails,ruby,Ruby On Rails,Ruby,有没有一种方法可以将模块包含到类中,从而使模块的 方法重写类的方法?例如: module UpcasedName def name @name.upcase end end class User attr_accessor :name include UpcasedName end u = User.new u.name = 'john' puts u.name # outputs 'john', not 'JOHN' 在上面的例子中,u.name是“john”,而

有没有一种方法可以将模块包含到类中,从而使模块的 方法重写类的方法?例如:

module UpcasedName
  def name
    @name.upcase
  end
end

class User
  attr_accessor :name
  include UpcasedName
end

u = User.new
u.name = 'john'
puts u.name # outputs 'john', not 'JOHN'
在上面的例子中,u.name是“john”,而不是“john”。我知道如果我 扩展用户对象,而不是将模块包含到类中 行得通

module UpcasedName
  def name
    @name.upcase
  end
end

class User
  attr_accessor :name
end

u = User.new
u.name = 'john'
u.extend UpcasedName
puts u.name # outputs 'JOHN'

但是,我想在类级别而不是对象级别包含模块。

现在有几种方法可以做到这一点。第一个也是最基本的方法是使用ActiveSupport中的alias_method_chain

require 'activesupport'

module UpcasedName
  def self.included( base )
    base.alias_method_chain :name, :upcase
  end

  def name_with_upcase
    @name.upcase
  end
end

class User
  attr_accessor :name
  include UpcasedName
end

u = User.new
u.name = 'john'
puts u.name
您发布的方法实际上与Bruce Williams发布的方法类似:


如果你真的对此很坚决,你可以遵循Yehuda Katz在这里发布的方法:

Include类似于从另一个类继承,在这个意义上,你将模块包含到其中的类的方法优先于包含的方法。您甚至可以在类中调用super来访问模块中的方法:

class User
  attr_accessor :name
  def name
    super
  end
  include UpcasedName
end

u = User.new
u.name = 'john'
puts u.name # outputs 'JOHN'

这里有一篇关于它的文章:

根据ucron的回答,在没有activesupport的情况下可以这样做,如下所示:

module UpcasedName
  def self.included(base)
    base.send :alias_method, :name_without_feature, :name
    base.send :alias_method, :name, :name_with_upcase
  end

  def name_with_upcase
    @name.upcase
  end
end

class User
  attr_accessor :name
  include UpcasedName
end

u = User.new
u.name = 'john'
puts u.name

这里的问题是
attr\u accessor
创建了一个User.name方法来覆盖UpcasedName.name方法,因此一种解决方案是使用
attr\u writer

module UpcasedName
  def name
    @name.upcase
  end
end

class User
  attr_writer :name
  include UpcasedName
end

u = User.new
u.name = 'john'
puts u.name # outputs 'JOHN'

它可能并不总是一个选项,但我认为最好是将类的方法移动到它自己的模块中,并将该模块混合回类中。我觉得这更干净


谢谢您的参考。但是,base.alias\u method\u chain:name,:upcase需要更改为base.alias\u method\u chain:name,:name\u with\u upcase