[ruby-on-rails] ActiveRecord :: Base를 확장하는 레일

모델에 특별한 메소드가 있도록 ActiveRecord : Base 클래스를 확장하는 방법에 대해 약간의 독서를했습니다. 그것을 확장하는 쉬운 방법은 무엇입니까 (단계별 튜토리얼)?



답변

몇 가지 접근 방식이 있습니다.

ActiveSupport :: Concern 사용 (선호)

자세한 내용은 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라는 디렉토리에 파일을 작성하고 파일에 extensions.rb다음 행을 추가하십시오.

require "active_record_extension"

상속 (권장)

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

Jamie Zawinski의 정규 표현식에 대한 유명한 인용문은 원숭이 패치와 관련된 문제를 설명하기 위해 용도 변경 될 수 있습니다.

어떤 사람들은 문제에 직면했을 때“나는 원숭이 패치를 사용할 것입니다”라고 생각합니다. 이제 두 가지 문제가 있습니다.

원숭이 패치는 쉽고 빠릅니다. 그러나 절약 된 시간과 노력은 항상 언젠가 다시 추출됩니다. 복리 관심. 요즘에는 레일 콘솔에서 솔루션을 신속하게 프로토 타입하기 위해 원숭이 패치를 제한합니다.


답변

클래스를 확장하고 상속을 사용하면됩니다.

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

class Foo < AbstractModel
end

class Bar < AbstractModel
end


답변

다음 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.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 / 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

관심사를 사용하면서 강조하고 싶은 한 가지는 ‘기술적’그룹화보다는 ‘도메인 기반’그룹화에 관심사를 사용해야한다는 것입니다. 예를 들어 도메인 그룹은 ‘Commentable’, ‘Taggable’등과 같습니다. 기술 기반 그룹은 ‘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 :)


답변

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

예를 들어이 블로그 게시물을 참조하십시오 .


답변

이 주제에 추가하기 위해 그러한 확장을 테스트하는 방법을 연구하는 데 잠시 시간을 보냈습니다 ( 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