답변:
몇 가지 접근 방식이 있습니다.
자세한 내용은 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의 정규 표현식에 대한 유명한 인용문은 원숭이 패치와 관련된 문제를 설명하기 위해 용도 변경 될 수 있습니다.
어떤 사람들은 문제에 직면했을 때“나는 원숭이 패치를 사용할 것입니다”라고 생각합니다. 이제 두 가지 문제가 있습니다.
원숭이 패치는 쉽고 빠릅니다. 그러나 절약 된 시간과 노력은 항상 언젠가 다시 추출됩니다. 복리 관심. 요즘에는 레일 콘솔에서 솔루션을 신속하게 프로토 타입하기 위해 원숭이 패치를 제한합니다.
require
끝에 파일 이 있어야합니다 environment.rb
. 이 추가 단계를 답변에 추가했습니다.
ImprovedActiveRecord
그로부터 상속해야합니다.를 사용할 때 module
해당 클래스의 정의가 업데이트됩니다. 상속을 사용했습니다 (수년간의 Java / C ++ 경험으로 인해). 요즘에는 주로 모듈을 사용합니다.
Refinements
에는 원숭이 패치 ( yehudakatz.com/2010/11/30/ruby-2-0-refinements-in-practice ) 와 관련된 대부분의 문제를 해결 하는 새로운 기능이 도입되었습니다 . 때로는 운명을 유혹하도록 강요하는 기능이 있습니다. 때로는 그렇습니다.
클래스를 확장하고 상속을 사용하면됩니다.
class AbstractModel < ActiveRecord::Base
self.abstract_class = true
end
class Foo < AbstractModel
end
class Bar < AbstractModel
end
abstract_models
. 어디에 두어야합니까?
self.abstract_class = true
하십시오 AbstractModel
. Rails는 이제 모델을 추상 모델로 인식합니다.
AbstractModel
가 데이터베이스에서를 찾고 질식했을 때 포기했습니다 . 간단한 세터가 나를 건조시키는 데 도움이 될 줄 누가 알았습니까! (나는 울기 시작했다.. 그것은 나빴다). 고마워 Toby와 Harish!
다음 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
InstanceMethods
레일 3.2 이후 사용되지 않으며, 그냥 모듈 본체에 당신의 방법을 넣어.
ActiveRecord::Base.send(:include, MyExtension)
이니셜 라이저에 넣고 이것이 나를 위해 일했다. 레일 4.1.9
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
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
모든 메소드에서 특수 메소드 모듈을 사용할 수 있어야한다고 가정하십시오 (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
그것이 다른 사람들을 돕기를 바랍니다!