Rails扩展ActiveRecord :: Base

xpe*_*int 160 ruby-on-rails extend rails-activerecord

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

Har*_*tty 336

有几种方法:

使用ActiveSupport :: Concern(首选)

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

创建目录中调用active_record_extension.rblib文件.

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)
Run Code Online (Sandbox Code Playgroud)

在被config/initializers调用的目录中创建一个文件,extensions.rb并将以下行添加到该文件中:

require "active_record_extension"
Run Code Online (Sandbox Code Playgroud)

继承(首选)

请参阅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
Run Code Online (Sandbox Code Playgroud)

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

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

猴子修补简单快捷.但是,节省的时间和精力总是在未来的某个时候被提取出来; 复利.这些天我限制猴子修补,以快速在rails控制台中原型解决方案.

  • 你必须在`environment.rb`的末尾``require`文件.我已经在我的回答中添加了这个额外的步骤. (3认同)
  • 有点讽刺的是,您的链接实际上是在情境化的情况下指出人们如何错误和过度使用这句话的。但说实话,我很难理解为什么“猴子补丁”在这种情况下不是最好的方法。如果您想添加多个类,那么模块显然是最佳选择。但是,如果您的目标是扩展一个类,那么这不正是 Ruby 使以这种方式扩展类变得如此简单的原因吗? (2认同)

Tob*_*ede 70

您可以只扩展类并简单地使用继承.

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

class Foo < AbstractModel
end

class Bar < AbstractModel
end
Run Code Online (Sandbox Code Playgroud)

  • 将`self.abstract_class = true`添加到`AbstractModel`中.Rails现在将模型识别为抽象模型. (23认同)

nik*_*ola 21

你也可以使用ActiveSupport::Concern和更多Rails核心惯用法,如:

module MyExtension
  extend ActiveSupport::Concern

  def foo
  end

  module ClassMethods
    def bar
    end
  end
end

ActiveRecord::Base.send(:include, MyExtension)
Run Code Online (Sandbox Code Playgroud)

[编辑]跟随@daniel的评论

然后,所有模型都将该方法foo作为实例方法ClassMethods包含在内,并将方法 作为类方法包含在内.例如,FooBar < ActiveRecord::Base你将拥有:FooBar.barFooBar#foo

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

  • 请注意,自Rails 3.2以来,不推荐使用`InstanceMethods`,只需将方法放入模块体中即可. (5认同)

Aad*_*ain 17

使用Rails 4,使用关注点模块化和干燥模型的概念已经成为亮点.

问题基本上允许您在单个模块中将模型的相似代码或多个模型分组,然后在模型中使用此模块.这是一个例子:

考虑文章模型,事件模型和评论模型.文章或A事件有很多评论.评论属于文章或事件.

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

评论模型:

class Comment < ActiveRecord::Base
  belongs_to :commentable, polymorphic: true
end
Run Code Online (Sandbox Code Playgroud)

文章模型:

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
Run Code Online (Sandbox Code Playgroud)

事件模型

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
Run Code Online (Sandbox Code Playgroud)

我们可以注意到,事件和文章模型都有一个共同的重要代码.使用关注点,我们可以在单独的模块中提取此公共代码.

为此,在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
Run Code Online (Sandbox Code Playgroud)

现在您的模型看起来像这样:

评论模型:

    class Comment < ActiveRecord::Base
      belongs_to :commentable, polymorphic: true
    end
Run Code Online (Sandbox Code Playgroud)

文章模型:

class Article < ActiveRecord::Base
    include Commentable
end
Run Code Online (Sandbox Code Playgroud)

事件模型

class Event < ActiveRecord::Base    
    include Commentable
end
Run Code Online (Sandbox Code Playgroud)

在使用Concerns时我想强调的一点是,应该将关注点用于"基于域"的分组而不是"技术"分组.例如,域分组就像"可评论","可标记"等.基于技术的分组将类似于"FinderMethods","ValidationMethods".

这是一个帖子链接,我发现这对于理解模型中的问题非常有用.

希望写作有帮助:)


Vit*_*ner 7

步骤1

module FooExtension
  def foo
    puts "bar :)"
  end
end
ActiveRecord::Base.send :include, FooExtension
Run Code Online (Sandbox Code Playgroud)

第2步

# Require the above file in an initializer (in config/initializers)
require 'lib/foo_extension.rb'
Run Code Online (Sandbox Code Playgroud)

第3步

There is no step 3 :)
Run Code Online (Sandbox Code Playgroud)


Ado*_*obe 5

滑轨5提供了用于扩展的内置机制ActiveRecord::Base

这可以通过提供额外的层来实现:

# app/models/application_record.rb
class ApplicationRecord < ActiveRecord::Base
  self.abstract_class = true
  # put your extensions here
end
Run Code Online (Sandbox Code Playgroud)

所有模型都继承自该模型:

class Post < ApplicationRecord
end
Run Code Online (Sandbox Code Playgroud)

参见例如此博客文章


Ash*_*man 5

在 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
Run Code Online (Sandbox Code Playgroud)

假设特殊方法模块需要在所有模型中可用,请将其包含在 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
Run Code Online (Sandbox Code Playgroud)

如果您希望将模块中定义的方法作为类方法,请将模块扩展为 ApplicationRecord。

# app/models/application_record.rb
class ApplicationRecord < ActiveRecord::Base
  self.abstract_class = true
  extend SpecialMethods
end
Run Code Online (Sandbox Code Playgroud)

希望它对其他人有帮助!