Rails扩展ActiveRecord :: Base

我已经做了一些关于如何扩展ActiveRecord:Base类的阅读,所以我的模型会有一些特殊的方法。 什么是简单的方法来扩展它(一步一步的教程)?

有几种方法:

使用ActiveSupport ::关注(首选)

阅读ActiveSupport :: Concern文档以获取更多详细信息。

lib目录下创建一个名为active_record_extension.rb的文件。

 module ActiveRecordExtension extend ActiveSupport::Concern # add your instance methods here def foo "foo" end # add your static(class) methods here class_methods do #Eg: 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, Eg: Order.new.foo def foo "foo" end #class method, Eg: Order.top_ten def self.top_ten limit(10) end end 

有关Jamie Zawinski正则表达式的着名引用可以重新用于说明与修补猴子有关的问题。

有些人在遇到问题时,会想“我知道,我会用猴子补丁”。现在他们有两个问题。

猴子修补很简单,快捷。 但是,节省的时间和精力总是会在未来某个时候被提取出来。 与复利。 现在我限制猴子补丁,以便在滑轨控制台中快速创建解决方案。

你可以扩展这个类并简单地使用继承。

 class AbstractModel < ActiveRecord::Base self.abstract_class = true end class Foo < AbstractModel end class Bar < AbstractModel end 

你也可以使用ActiveSupport::Concern并使用更多的Rails核心ActiveSupport::Concern

 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.barFooBar#foo

http://api.rubyonrails.org/classes/ActiveSupport/Concern.html

使用Rails 4,使用关注点模块化和干化模型的概念一直是亮点。

顾虑基本上允许你在一个模块中将模型的类似代码或多个模型分组,然后在模型中使用这个模块。 这里是一个例子:

考虑文章模型,事件模型和评论模型。 一篇文章或一个事件有很多评论。 评论属于文章或事件。

传统上,模型可能如下所示:

评论型号:

 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 /关键字中创建一个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 

有一点我要强调的是,在使用Concerns时, Concerns应该用于“基于域”的分组而不是“技术”分组。 例如,域名分组就像“可注释”,“可标记”等。基于技术的分组将像“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' 

第3步

 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提供了一个用于扩展ActiveRecord::Base的内置机制。

这是通过提供附加层来实现的:

 # app/models/application_record.rb class ApplicationRecord < ActiveRecord::Base self.abstract_class = true # put your extensions here end 

所有的模型都从这个模型继承而来:

 class Post < ApplicationRecord end 

看看这个博客帖子 。

我有

 ActiveRecord::Base.extend Foo::Bar 

在初始化器中

对于像下面这样的模块

 module Foo module Bar end end