[ruby-on-rails] Rails 4에서 우려 사항을 사용하는 방법

기본 Rails 4 프로젝트 생성기는 이제 컨트롤러 및 모델 아래에 “우려”디렉토리를 만듭니다. 라우팅 문제를 사용하는 방법에 대한 설명을 찾았지만 컨트롤러 나 모델에 대해서는 설명하지 않았습니다.

커뮤니티의 현재 “DCI 트렌드”와 관련이 있으며 시도해보고 싶습니다.

문제는이 기능을 어떻게 사용해야합니까? 네이밍 / 클래스 계층 구조를 정의하여 작동하게하는 방법에 대한 규칙이 있습니까? 모델이나 컨트롤러에 관심을 어떻게 포함시킬 수 있습니까?



답변

그래서 나는 그것을 스스로 알아 냈습니다. 실제로는 매우 단순하지만 강력한 개념입니다. 아래 예제와 같이 코드 재사용과 관련이 있습니다. 기본적으로 아이디어는 모델을 정리하고 너무 뚱뚱하고 지저분 해지는 것을 피하기 위해 공통 및 / 또는 컨텍스트 특정 코드 덩어리를 추출하는 것입니다.

예를 들어, 잘 알려진 하나의 태그 가능한 패턴을 넣겠습니다.

# 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 래퍼와 함께이 경량 팩토링 메커니즘을 빛나게하는 데 충분한 지원입니다.


답변

나는 모델 코드를 건조 할뿐만 아니라 뚱뚱한 모델을 피부 에 맞게 만들기 위해 모델 문제 를 사용하는 것에 대해 읽었 습니다. 다음은 예제를 사용한 설명입니다.

1) 모델 코드 건조

기사 모델, 이벤트 모델 및 설명 모델을 고려하십시오. 기사 나 이벤트에는 많은 의견이 있습니다. 의견은 기사 또는 이벤트에 속합니다.

전통적으로 모델은 다음과 같습니다.

댓글 모델 :

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

2) 피부 크기의 지방 모델.

이벤트 모델을 고려하십시오. 이벤트에는 많은 참석자와 의견이 있습니다.

일반적으로 이벤트 모델은 다음과 같습니다.

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.rbcommentable.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’등을 의미합니다.


답변

많은 사람들은 우려를 이용하는 것이 나쁜 생각으로 여겨진다는 것을 언급 할 가치가 있습니다.

  1. 이 남자처럼
  2. 그리고 이것

몇 가지 이유 :

  1. 배후에는 약간의 어두운 마법이 있습니다. 문제는 패치 include방법입니다. 전체 의존성 처리 시스템이 있습니다. 아주 오래된 오래된 Ruby 믹스 인 패턴에는 너무 복잡합니다.
  2. 당신의 수업은 더 건조하지 않습니다. 다양한 모듈에 50 개의 퍼블릭 메소드를 채우고 포함 시키면 클래스에 여전히 50 개의 퍼블릭 메소드가 있습니다.이 코드 냄새를 숨기고 쓰레기를 서랍에 넣는 것입니다.
  3. 코드베이스는 실제로 모든 문제를 탐색하기가 더 어렵습니다.
  4. 팀의 모든 구성원이 실제로 대체해야 할 사항을 동일하게 이해하고 있습니까?

우려 사항은 다리에 자신을 쏠 수있는 쉬운 방법이므로 조심하십시오.


답변

이 게시물 은 관심사를 이해하는 데 도움 이되었습니다 .

# app/models/trader.rb
class Trader
  include Shared::Schedule
end

# app/models/concerns/shared/schedule.rb
module Shared::Schedule
  extend ActiveSupport::Concern
  ...
end


답변

나는 여기에있는 대부분의 예 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. 그러나 클래스 BarFoo의 종속성이 있기 때문에Hostinclude 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모듈 자체 .

출처 : Rails ActiveSupport :: 문제


답변

우려 파일 이름을 만듭니다 .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


답변