Ruby-on-rails 扩展 ActiveRecord::Base 的 Rails

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2328984/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-02 22:19:32  来源:igfitidea点击:

Rails extending ActiveRecord::Base

ruby-on-railsextendrails-activerecord

提问by xpepermint

I've done some reading about how to extend ActiveRecord:Base class so my models would have some special methods. What is the easy way to extend it (step by step tutorial)?

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

回答by Harish Shetty

There are several approaches :

有几种方法:

Using ActiveSupport::Concern (Preferred)

使用 ActiveSupport::Concern(首选)

Read the ActiveSupport::Concerndocumentation for more details.

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

Create a file called active_record_extension.rbin the libdirectory.

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)

Create a file in the config/initializersdirectory called extensions.rband add the following line to the file:

config/initializers名为的目录中创建一个文件,extensions.rb并将以下行添加到文件中:

require "active_record_extension"

Inheritance (Preferred)

继承(首选)

Refer to Toby's answer.

请参阅托比的回答

Monkey patching (Should be avoided)

猴子补丁(应该避免)

Create a file in the config/initializersdirectory called active_record_monkey_patch.rb.

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

The famous quote about Regular expressions by Jamie Zawinskican be re-purposed to illustrate the problems associated with monkey-patching.

Jamie Zawinski关于正则表达式的名言可以重新用于说明与猴子补丁相关的问题。

Some people, when confronted with a problem, think “I know, I'll use monkey patching.” Now they have two problems.

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

Monkey patching is easy and quick. But, the time and effort saved is always extracted back sometime in the future; with compound interest. These days I limit monkey patching to quickly prototype a solution in the rails console.

猴子修补既简单又快捷。但是,节省的时间和精力总是在将来的某个时间提取回来;与复利。这些天我限制猴子修补以在 rails 控制台中快速构建解决方案原型。

回答by Toby Hede

You can just extend the class and simply use inheritance.

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

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

class Foo < AbstractModel
end

class Bar < AbstractModel
end

回答by nikola

You can also use ActiveSupport::Concernand be more Rails core idiomatic like:

您还可以使用ActiveSupport::Concern更多的 Rails 核心惯用语,例如:

module MyExtension
  extend ActiveSupport::Concern

  def foo
  end

  module ClassMethods
    def bar
    end
  end
end

ActiveRecord::Base.send(:include, MyExtension)

[Edit] following the comment from @daniel

[编辑] 遵循@daniel 的评论

Then all your models will have the method fooincluded as an instance method and the methods in ClassMethodsincluded as class methods. E.g. on a FooBar < ActiveRecord::Baseyou will have: FooBar.barand FooBar#foo

然后,您的所有模型都将foo包含作为实例方法的方法和 ClassMethods作为类方法包含的方法。例如,FooBar < ActiveRecord::Base您将拥有:FooBar.barFooBar#foo

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

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

回答by Aaditi Jain

With Rails 4, the concept of using concerns to modularize and DRY up your models has been in highlights.

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

Concerns basically allow you to group similar code of a model or across multiple models in a single module and then use this module in the models. Here is a example:

关注点基本上允许您将模型的相似代码或跨多个模型的代码分组到单个模块中,然后在模型中使用该模块。下面是一个例子:

Consider a Article model, a Event model and a Comment Model. A article or A event has many comments. A comment belongs to either article or event.

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

Traditionally, the models may look like this:

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

Comment Model:

评论型号:

class Comment < ActiveRecord::Base
  belongs_to :commentable, polymorphic: true
end

Article Model:

文章型号:

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

Event Model

事件模型

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

As we can notice, there is a significant piece of code common to both Event and Article Model. Using concerns we can extract this common code in a separate module Commentable.

正如我们所注意到的,事件模型和文章模型都有一段重要的代码。使用关注点,我们可以在一个单独的模块 Commentable 中提取这个公共代码。

For this create a commentable.rb file in app/model/concerns.

为此,在 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

And Now your models look like this :

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

Comment Model:

评论型号:

    class Comment < ActiveRecord::Base
      belongs_to :commentable, polymorphic: true
    end

Article Model:

文章型号:

class Article < ActiveRecord::Base
    include Commentable
end

Event Model

事件模型

class Event < ActiveRecord::Base    
    include Commentable
end

One point I will like to highlight while using Concerns is that Concerns should be used for 'domain based' grouping rather than 'technical' grouping.For example, a domain grouping is like 'Commentable', 'Taggable' etc. A technical based grouping will be like 'FinderMethods', 'ValidationMethods'.

在使用关注点时我想强调的一点是,关注点应该用于“基于域”的分组而不是“技术”分组。例如,域分组类似于“Commentable”、“Taggable”等。基于技术的分组将类似于“FinderMethods”、“ValidationMethods”。

Here is a link to a postthat I found very useful for understanding concerns in Models.

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

Hope the writeup helps :)

希望写的有帮助:)

回答by Vitaly Kushner

Step 1

第1步

module FooExtension
  def foo
    puts "bar :)"
  end
end
ActiveRecord::Base.send :include, FooExtension

Step 2

第2步

# Require the above file in an initializer (in config/initializers)
require 'lib/foo_extension.rb'

Step 3

第 3 步

There is no step 3 :)

回答by Adobe

Rails 5 provides a built-in mechanism for extending ActiveRecord::Base.

Rails 5 提供了一个内置机制来扩展ActiveRecord::Base.

This is achieved by providing additional layer:

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

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

and all models inherit from that one:

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

class Post < ApplicationRecord
end

See e.g. this blogpost.

参见例如这篇博文

回答by Ashik Salman

With Rails 5, all models are inherited from ApplicationRecord & it gives nice way to include or extend other extension libraries.

使用 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

Suppose the special methods module needs to be available across all models, include it in application_record.rb file. If we wants to apply this for a particular set of models, then include it in the respective model classes.

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

If you want to have the methods defined in the module as class methods, extend the module to ApplicationRecord.

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

# app/models/application_record.rb
class ApplicationRecord < ActiveRecord::Base
  self.abstract_class = true
  extend SpecialMethods
end

Hope it help others !

希望对其他人有帮助!

回答by Will Tomlins

Just to add to this topic, I spent a while working out how to test such extensions (I went down the ActiveSupport::Concernroute.)

只是为了补充这个主题,我花了一段时间研究如何测试这些扩展(我沿着这ActiveSupport::Concern条路走下去。)

Here's how I set up a model for testing my extensions.

下面是我如何设置一个模型来测试我的扩展。

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

回答by Ed Richards

I have

我有

ActiveRecord::Base.extend Foo::Bar

in an initializer

在初始化程序中

For a module like below

对于像下面这样的模块

module Foo
  module Bar
  end
end