kru*_*hah 5 ruby ruby-on-rails include extend
我想创建一个模块,它为从活动记录库继承的类提供一些常用方法.
以下是我们可以实现的双向方式.
1)
module Commentable
def self.extended(base)
base.class_eval do
include InstanceMethods
extend ClassMethods
end
end
module ClassMethods
def test_commentable_classmethod
puts 'test class method'
end
end
module InstanceMethods
def test_commentable_instance_method
puts 'test instance method'
end
end
end
ActiveRecord::Base.extend(Commentable)
Run Code Online (Sandbox Code Playgroud)
2)
module Commentable
def self.included(base)
base.extend(ClassMethods)
end
module ClassMethods
def test_commentable_classmethod
puts 'test class method'
end
end
def test_commentable_instance_method
puts 'test instance methods'
end
end
ActiveRecord::Base.send(:include, Commentable)
Run Code Online (Sandbox Code Playgroud)
哪一个是处理这个的首选方式?
和
什么时候用?
从Rails 5开始,推荐的方法是创建一个模块并将其包含在需要它的模型中,或者在所有模型继承的ApplicationRecord中包含它.(您可以在旧版本的Rails中从头开始轻松实现此模式.)
# app/models/concerns/my_module.rb
module MyModule
extend ActiveSupport::Concern
module ClassMethods
def has_some_new_fancy_feature(options = {})
...
end
end
end
# app/models/application_record.rb
class ApplicationRecord < ActiveRecord::Base
self.abstract_class = true
include MyModule
end
Run Code Online (Sandbox Code Playgroud)
模块是多重继承的一种形式,有时会增加不必要的复杂性.检查装饰器,服务或其他类型的对象是否更有意义.并非所有东西都需要一个花哨的宏,为你的模型添加50个回调.如果你做得太多,你会恨你的生活.
如果你想要猴子补丁(不要这样做),这是我的老答案:
# config/initializers/activerecord_extensions.rb
ActiveRecord::Base.send(:include, MyModule)
Run Code Online (Sandbox Code Playgroud)
或者没有猴子修补(见Mori的回应):
# app/models/base_model.rb
class BaseModel < ActiveRecord::Base
self.abstract_class = true
include MyModule
end
Run Code Online (Sandbox Code Playgroud)
编辑:在一个大型项目的几个月后,我已经意识到让每个模型都继承自新的基础模型类更好,正如Mori解释的那样.将模块直接包含在ActiveRecord :: Base中的问题是这会干扰依赖ActiveRecord的第三方代码.最好不要在没必要的情况下进行猴子补丁.在这种情况下,从长远来看,创建新的基类最终会变得更简单.
另一种方法是通过继承ActiveRecord::Base,然后让模型从该基类继承来创建自己的基类.这样做的好处是可以清楚地表明您的模型没有在vanilla ActiveRecord上运行:
class MyBase < ActiveRecord::Base
self.abstract_class = true
def self.a_class_method
end
def an_instance_method
end
end
class Foo < MyBase
end
Foo.a_class_method
Foo.new.an_instance_method
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
464 次 |
| 最近记录: |