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.bar
和FooBar#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