답변:
그래서 나는 그것을 스스로 알아 냈습니다. 실제로는 매우 단순하지만 강력한 개념입니다. 아래 예제와 같이 코드 재사용과 관련이 있습니다. 기본적으로 아이디어는 모델을 정리하고 너무 뚱뚱하고 지저분 해지는 것을 피하기 위해 공통 및 / 또는 컨텍스트 특정 코드 덩어리를 추출하는 것입니다.
예를 들어, 잘 알려진 하나의 태그 가능한 패턴을 넣겠습니다.
# app/models/product.rb
class Product
include Taggable
...
end
# app/models/concerns/taggable.rb
# notice that the file name has to match the module name
# (applying Rails conventions for autoloading)
module Taggable
extend ActiveSupport::Concern
included do
has_many :taggings, as: :taggable
has_many :tags, through: :taggings
class_attribute :tag_limit
end
def tags_string
tags.map(&:name).join(', ')
end
def tags_string=(tag_string)
tag_names = tag_string.to_s.split(', ')
tag_names.each do |tag_name|
tags.build(name: tag_name)
end
end
# methods defined here are going to extend the class, not the instance of it
module ClassMethods
def tag_limit(value)
self.tag_limit_value = value
end
end
end
따라서 제품 샘플에 따라 원하는 모든 클래스에 Taggable을 추가하고 기능을 공유 할 수 있습니다.
이것은 DHH에 의해 잘 설명되어 있습니다 .
Rails 4에서는 자동으로로드 경로의 일부인 기본 app / models / concerns 및 app / controllers / concerns 디렉토리에 관심을 갖도록 프로그래머를 초대합니다. ActiveSupport :: Concern 래퍼와 함께이 경량 팩토링 메커니즘을 빛나게하는 데 충분한 지원입니다.
나는 모델 코드를 건조 할뿐만 아니라 뚱뚱한 모델을 피부 에 맞게 만들기 위해 모델 문제 를 사용하는 것에 대해 읽었 습니다. 다음은 예제를 사용한 설명입니다.
기사 모델, 이벤트 모델 및 설명 모델을 고려하십시오. 기사 나 이벤트에는 많은 의견이 있습니다. 의견은 기사 또는 이벤트에 속합니다.
전통적으로 모델은 다음과 같습니다.
댓글 모델 :
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 / models / 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
이벤트 모델을 고려하십시오. 이벤트에는 많은 참석자와 의견이 있습니다.
일반적으로 이벤트 모델은 다음과 같습니다.
class Event < ActiveRecord::Base
has_many :comments
has_many :attenders
def find_first_comment
# for the given article/event returns the first comment
end
def find_comments_with_word(word)
# for the given event returns an array of comments which contain the given word
end
def self.least_commented
# finds the event which has the least number of comments
end
def self.most_attended
# returns the event with most number of attendes
end
def has_attendee(attendee_id)
# returns true if the event has the mentioned attendee
end
end
많은 연관성이 있고 그렇지 않으면 더 많은 코드를 누적하고 관리 할 수없는 경향이있는 모델이 있습니다. 우려 사항은 지방 모듈을 피부에 맞게 처리하여보다 모듈화되고 이해하기 쉬운 방법을 제공합니다.
위의 모델은 다음과 같은 우려를 사용하여 리팩토링 할 수 있습니다 : a 작성 attendable.rb
및commentable.rb
app / models / concerns / event 폴더에 파일
attendable.rb
module Attendable
extend ActiveSupport::Concern
included do
has_many :attenders
end
def has_attender(attender_id)
# returns true if the event has the mentioned attendee
end
module ClassMethods
def most_attended
# returns the event with most number of attendes
end
end
end
commentable.rb
module Commentable
extend ActiveSupport::Concern
included do
has_many :comments
end
def find_first_comment
# for the given article/event returns the first comment
end
def find_comments_with_word(word)
# for the given event returns an array of comments which contain the given word
end
module ClassMethods
def least_commented
# finds the event which has the least number of comments
end
end
end
이제 관심사를 사용하면 이벤트 모델이
class Event < ActiveRecord::Base
include Commentable
include Attendable
end
* 사용하는 동안 '기술적'그룹화보다는 '도메인'기반 그룹화를 사용하는 것이 좋습니다. 도메인 기반 그룹은 'Commentable', 'Photoable', 'Attendable'과 같습니다. 기술 그룹화는 'ValidationMethods', 'FinderMethods'등을 의미합니다.
def self.my_class_method
하고 클래스 범위의 클래스 메소드 (포함 ), 인스턴스 메소드 및 메소드 호출 및 지시문을 포함 할 수 있습니다. 불필요module ClassMethods
add_item
예를 들어 두 가지가 모두 구현 과 관련되어 있다면 문제 가 생길 수 있습니다. 일부 유효성 검사기가 작동을 멈췄을 때 Rails가 고장 났다고 생각하지만 누군가가 any?
염려에 빠졌습니다. 다른 해결책을 제안합니다. 다른 언어로 된 인터페이스와 같은 관심사를 사용하십시오. 기능을 정의하는 대신 해당 기능을 처리하는 별도의 클래스 인스턴스에 대한 참조를 정의합니다. 그러면 한 가지 일을하는 더 작고 깔끔한 수업이 있습니다.
많은 사람들은 우려를 이용하는 것이 나쁜 생각으로 여겨진다는 것을 언급 할 가치가 있습니다.
몇 가지 이유 :
include
방법입니다. 전체 의존성 처리 시스템이 있습니다. 아주 오래된 오래된 Ruby 믹스 인 패턴에는 너무 복잡합니다.우려 사항은 다리에 자신을 쏠 수있는 쉬운 방법이므로 조심하십시오.
나는 여기에있는 대부분의 예 module
들이 어떻게 ActiveSupport::Concern
가치를 더하는 것보다 힘을 발휘한다고 느꼈다 module
.
예 1 : 더 읽기 쉬운 모듈.
그래서 이것이 전형적인 module
것이 될 것인지 걱정하지 않아도 됩니다.
module M
def self.included(base)
base.extend ClassMethods
base.class_eval do
scope :disabled, -> { where(disabled: true) }
end
end
def instance_method
...
end
module ClassMethods
...
end
end
와 리팩토링 후 ActiveSupport::Concern
.
require 'active_support/concern'
module M
extend ActiveSupport::Concern
included do
scope :disabled, -> { where(disabled: true) }
end
class_methods do
...
end
def instance_method
...
end
end
인스턴스 메소드, 클래스 메소드 및 포함 된 블록이 덜 지저분하다는 것을 알 수 있습니다. 우려 사항이 귀하에게 적절하게 주입됩니다. 이것이을 사용하는 이점 중 하나입니다 ActiveSupport::Concern
.
예 2 : 모듈 종속성을 정상적으로 처리하십시오.
module Foo
def self.included(base)
base.class_eval do
def self.method_injected_by_foo_to_host_klass
...
end
end
end
end
module Bar
def self.included(base)
base.method_injected_by_foo_to_host_klass
end
end
class Host
include Foo # We need to include this dependency for Bar
include Bar # Bar is the module that Host really needs
end
이 예에서는 실제로 필요한 Bar
모듈입니다 Host
. 그러나 클래스 Bar
와 Foo
의 종속성이 있기 때문에Host
include Foo
(그러나 않는 이유를 대기 Host
에 대해 알고 싶은가 Foo
? 그것은 피할 수 있습니까?).
그래서 Bar
어디에서나 의존성을 추가합니다. 그리고 포함 순서도 여기서 중요합니다. 이는 거대한 코드 기반에 많은 복잡성 / 종속성을 추가합니다.
리팩토링 후 ActiveSupport::Concern
require 'active_support/concern'
module Foo
extend ActiveSupport::Concern
included do
def self.method_injected_by_foo_to_host_klass
...
end
end
end
module Bar
extend ActiveSupport::Concern
include Foo
included do
self.method_injected_by_foo_to_host_klass
end
end
class Host
include Bar # It works, now Bar takes care of its dependencies
end
이제 간단 해 보입니다.
모듈 자체 에 Foo
의존성을 추가 할 수없는 이유를 생각하고 있다면 Bar
? 그렇지 않은 method_injected_by_foo_to_host_klass
클래스에 주입해야하기 때문에 작동 Bar
하지 않습니다.Bar
모듈 자체 .
우려 파일 이름을 만듭니다 .rb
예를 들어 속성 create_by가 존재하는 응용 프로그램에서 1 씩 값을 업데이트하고 updated_by에 대해 0을 원합니다.
module TestConcern
extend ActiveSupport::Concern
def checkattributes
if self.has_attribute?(:created_by)
self.update_attributes(created_by: 1)
end
if self.has_attribute?(:updated_by)
self.update_attributes(updated_by: 0)
end
end
end
인수를 실제로 전달하려면
included do
before_action only: [:create] do
blaablaa(options)
end
end
그런 다음 모델에 다음과 같이 포함하십시오.
class Role < ActiveRecord::Base
include TestConcern
end