我已经做了一些关于如何扩展ActiveRecord:Base类的阅读,所以我的模型会有一些特殊的方法。扩展它的简单方法是什么(逐步教程)?
答案 0 :(得分:331)
有几种方法:
阅读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
的{{1}}目录中创建一个文件,并将以下行添加到该文件中:
extensions.rb
请参阅Toby的answer。
在名为require "active_record_extension"
的{{1}}目录中创建一个文件。
config/initializers
Jamie Zawinski关于正则表达式的着名引用可以重新用于说明与猴子修补相关的问题。
有些人在遇到问题时会想“我知道,我会用 猴子补丁。“现在他们有两个问题。
猴子修补简单快捷。但是,节省的时间和精力总是被提取出来 将来的某个时候;复利。这些天我限制猴子修补,以便在rails控制台中快速构建解决方案原型。
答案 1 :(得分:70)
您只需扩展该类,只需使用继承即可。
class AbstractModel < ActiveRecord::Base
self.abstract_class = true
end
class Foo < AbstractModel
end
class Bar < AbstractModel
end
答案 2 :(得分:21)
你也可以使用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
答案 3 :(得分:16)
使用Rails 4,使用关注点来模块化和干掉模型的概念已经成为亮点。
问题基本上允许您在单个模块中对模型的相似代码或多个模型进行分组,然后在模型中使用此模块。这是一个例子:
考虑文章模型,事件模型和评论模型。文章或A事件有很多评论。评论属于文章或事件。
传统上,模型可能如下所示:
评论模型:
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
我们可以注意到,事件和文章模型都有一个共同的重要代码。使用关注点,我们可以在单独的模块中提取此公共代码。
为此,在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
我在使用问题时要强调的一点是关注点应该用于“基于域”的分组而不是“技术”分组。例如,域名分组就像“可评论” ,'Taggable'等基于技术的分组将类似于'FinderMethods','ValidationMethods'。
我发现link to a post对于理解模型中的问题非常有用。
希望写作有帮助:)
答案 4 :(得分:7)
第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 :)
答案 5 :(得分:4)
为了补充这个主题,我花了一些时间研究如何测试这些扩展(我沿着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
答案 6 :(得分:4)
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
参见例如this blogpost
答案 7 :(得分:4)
使用Rails 5,所有模型都继承自ApplicationRecord&amp;它提供了包含或扩展其他扩展库的好方法。
# 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
希望对别人有所帮助!
答案 8 :(得分:0)
我有
ActiveRecord::Base.extend Foo::Bar
在初始化程序中
对于下面的模块
module Foo
module Bar
end
end