Answers:
有几种方法:
有关更多详细信息,请阅读ActiveSupport :: Concern文档。
active_record_extension.rb
在lib
目录中创建一个名为的文件。
require 'active_support/concern'
module ActiveRecordExtension
extend ActiveSupport::Concern
# add your instance methods here
def foo
"foo"
end
# add your static(class) methods here
class_methods do
#E.g: Order.top_ten
def top_ten
limit(10)
end
end
end
# include the extension
ActiveRecord::Base.send(:include, ActiveRecordExtension)
在config/initializers
名为的目录中创建一个文件,extensions.rb
并将以下行添加到该文件中:
require "active_record_extension"
请参阅Toby的答案。
在config/initializers
名为的目录中创建一个文件active_record_monkey_patch.rb
。
class ActiveRecord::Base
#instance method, E.g: Order.new.foo
def foo
"foo"
end
#class method, E.g: Order.top_ten
def self.top_ten
limit(10)
end
end
Jamie Zawinski关于正则表达式的著名报价可以重新用于说明与猴子修补相关的问题。
有些人在遇到问题时会想:“我知道,我将使用猴子修补程序。” 现在他们有两个问题。
猴子修补既简单又快速。但是,节省的时间和精力总是在将来的某个时候提取出来的。有复利。这些天来,我限制了猴子修补程序,以便在Rails控制台中快速创建解决方案的原型。
require
在末尾添加文件environment.rb
。我已经在回答中添加了这一额外步骤。
ImprovedActiveRecord
并从中继承,而在使用时module
,您将更新相关类的定义。我曾经使用继承(由于多年的Java / C ++经验)。这些天我主要使用模块。
Refinements
,该功能解决了猴子修补的大多数问题(yehudakatz.com/2010/11/30/ruby-2-0-refinements-in-practice)。有时有一个功能只是强迫您诱惑命运。有时候你会的。
您可以只扩展类并仅使用继承。
class AbstractModel < ActiveRecord::Base
self.abstract_class = true
end
class Foo < AbstractModel
end
class Bar < AbstractModel
end
abstract_models
。我应该放在哪里?
self.abstract_class = true
到您的中AbstractModel
。Rails现在将模型识别为抽象模型。
AbstractModel
在数据库中阻塞时放弃了。谁知道一个简单的二传手会帮助我干些事情!(我开始畏缩...这很糟糕)。感谢托比和哈里斯!
您还可以使用ActiveSupport::Concern
更多的Rails核心习惯,例如:
module MyExtension
extend ActiveSupport::Concern
def foo
end
module ClassMethods
def bar
end
end
end
ActiveRecord::Base.send(:include, MyExtension)
[编辑] @daniel发表评论后
然后,所有模型都将方法foo
作为实例方法ClassMethods
包括在内,并将方法 作为类方法包括在内。例如,FooBar < ActiveRecord::Base
您将拥有:FooBar.bar
和FooBar#foo
http://api.rubyonrails.org/classes/ActiveSupport/Concern.html
InstanceMethods
从Rails 3.2开始不推荐使用,只需将您的方法放入模块主体即可。
ActiveRecord::Base.send(:include, MyExtension)
一个初始化程序,然后为我工作。Rails 4.1.9
使用Rails 4时,使用关注点对模型进行模块化和DRY处理的概念已成为重点。
基本上,您可以通过关注将一个模型的相似代码或跨多个模型的代码组合到一个模块中,然后在模型中使用此模块。这是一个例子:
考虑文章模型,事件模型和评论模型。文章或事件有很多评论。评论属于文章或事件。
传统上,模型可能如下所示:
评论模型:
class Comment < ActiveRecord::Base
belongs_to :commentable, polymorphic: true
end
文章模型:
class Article < ActiveRecord::Base
has_many :comments, as: :commentable
def find_first_comment
comments.first(created_at DESC)
end
def self.least_commented
#return the article with least number of comments
end
end
事件模型
class Event < ActiveRecord::Base
has_many :comments, as: :commentable
def find_first_comment
comments.first(created_at DESC)
end
def self.least_commented
#returns the event with least number of comments
end
end
我们可以注意到,事件和文章模型都有大量的通用代码。使用关注点,我们可以在单独的模块Commentable中提取此通用代码。
为此,在app / model / concerns中创建一个commentable.rb文件。
module Commentable
extend ActiveSupport::Concern
included do
has_many :comments, as: :commentable
end
# for the given article/event returns the first comment
def find_first_comment
comments.first(created_at DESC)
end
module ClassMethods
def least_commented
#returns the article/event which has the least number of comments
end
end
end
现在,您的模型如下所示:
评论模型:
class Comment < ActiveRecord::Base
belongs_to :commentable, polymorphic: true
end
文章模型:
class Article < ActiveRecord::Base
include Commentable
end
事件模型
class Event < ActiveRecord::Base
include Commentable
end
在使用关注点时,我想强调的一点是,关注点应该用于“基于域”的分组,而不是“技术”分组。例如,域分组类似于“ Commentable”,“ Taggable”等。基于技术的分组将类似于“ FinderMethods”,“ ValidationMethods”。
希望这篇文章对您有所帮助:)
第1步
module FooExtension
def foo
puts "bar :)"
end
end
ActiveRecord::Base.send :include, FooExtension
第2步
# Require the above file in an initializer (in config/initializers)
require 'lib/foo_extension.rb'
第三步
There is no step 3 :)
只是为了补充这个话题,我花了一段时间研究如何测试这些扩展(我走了ActiveSupport::Concern
。)
这是我建立用于测试扩展的模型的方式。
describe ModelExtensions do
describe :some_method do
it 'should return the value of foo' do
ActiveRecord::Migration.create_table :test_models do |t|
t.string :foo
end
test_model_class = Class.new(ActiveRecord::Base) do
def self.name
'TestModel'
end
attr_accessible :foo
end
model = test_model_class.new(:foo => 'bar')
model.some_method.should == 'bar'
end
end
end
使用Rails 5时,所有模型都继承自ApplicationRecord,并且它提供了不错的方式来包含或扩展其他扩展库。
# app/models/concerns/special_methods.rb
module SpecialMethods
extend ActiveSupport::Concern
scope :this_month, -> {
where("date_trunc('month',created_at) = date_trunc('month',now())")
}
def foo
# Code
end
end
假设特殊方法模块需要在所有模型中都可用,并将其包含在application_record.rb文件中。如果我们想将此应用于一组特定的模型,则将其包括在各个模型类中。
# app/models/application_record.rb
class ApplicationRecord < ActiveRecord::Base
self.abstract_class = true
include SpecialMethods
end
# app/models/user.rb
class User < ApplicationRecord
include SpecialMethods
# Code
end
如果要将模块中定义的方法作为类方法,请将模块扩展到ApplicationRecord。
# app/models/application_record.rb
class ApplicationRecord < ActiveRecord::Base
self.abstract_class = true
extend SpecialMethods
end
希望对别人有帮助!
我有
ActiveRecord::Base.extend Foo::Bar
在初始化器中
对于如下所示的模块
module Foo
module Bar
end
end