Railsの関心がどのように働くか


多くのRailsアプリケーションは、フレームワークそのものを含みます.しかし、あなたがレールにちょうど入っているならば、懸念は理解するために混乱することがありえます.なぜ私たちはそれらを必要とするのですか?私が数ヶ月前にRailsを学び始めたとき、懸念は私が理解するのに長い時間を要した話題の1つでした.
レールAPI documentation どちらも助けない.それは、読者が既に問題を解決しようとしている問題に精通していると仮定して起動し、混乱を追加するだけで解決策を提供するために行く.
それで、私はいくつかの研究をしました、そして、ウェブには関心が散らばった懸念知恵の多くの面白いナゲットがありますthis 懸念の使用を示すDHHからのブログ柱these answers からA May of WTFs thread コアレールメンバーからexplaining との懸念metaphor of writing .
このブログ記事は、より良いコードを書くのを助けることができる方法を示して、コヒーレントな画像を描くために、これらの散乱の情報を要約しようとします.

問題点解決


Using a concern lets you extract the common logic from different classes into a reusable module.


ポストとコメントの2つのモデルを考えます.それらに特有のコードに加えて、両方のモデルはそれらの可視性を扱うコードを含みます、すなわちvisible_to 属性is_visible インスタンスメソッドcount_all_visible クラスメソッド.同様の方法で彼らの視認性をコントロールする必要がある他の多くのモデルがあるかもしれません.このコードを抽象化する方法があればよいでしょう.
# post.rb

class Post < ApplicationRecord
  belongs_to :author
  has_many :comments, dependent: :delete_all
  has_rich_text :content

  validates :title, presence: true, length: { minimum: 2 }
  validate :has_valid_content

  attr_accessor :visible_to

  def is_visible?
    visible_to.present?
  end

  def has_valid_content
    # some code
  end

  def self.count_all_visible
    all.select { |item| item.is_visible? }
  end
end

# comment.rb

class Comment < ApplicationRecord
  belongs_to :post
  validates :commenter, :body, presence: true

  attr_accessor :visible_to

  def is_visible?
    visible_to.present?
  end

  def self.count_all_visible
    all.select { |item| item.is_visible? }
  end
end

何が心配ですか?


A lot of concerns are simply Ruby modules that are mixed in, with no additional stuff added. And then for a few cases, like when your concern includes both class and instance methods, or you want to call class methods on mixin, you can use extend ActiveSupport::Concern. - DHH


レールConcern は、ActiveSupport::Concern モジュールです.懸念によって、クラス(インスタンスとクラスの両方)と定数を持つモジュールをクラスに含めることができ、クラスを含めることができます.
懸念は2つのブロックを提供します.
  • included
  • 付属のブロック内のコードは、そのクラスのコンテキストで評価されます.例えば、Post 懸念、内部の何でも含みますincluded ブロックは内部で書かれたかのように評価されますPost .
  • クラスマクロ(バリデータ、アソシエーション、スコープなど)をここで記述することができ、任意のメソッドは、そのクラスのインスタンスメソッドになります.
  • class_methods
  • このブロック内に追加されたメソッドは、そのクラスのクラスメソッドになります.
  • の代わりにclass_methods ブロックを作成することができますClassMethods .
  • Taggableという名前の懸念は、ここにあります.
    module Taggable
      extend ActiveSupport::Concern
    
      included do
    
      end
    
      class_methods do
    
      end
    end
    

    A concern is a module that you extract to split the implementation of a class or module in coherent chunks, instead of having one big class body. The API surface is the same one, they just help organize the code. A concern is a regular Ruby mixin, there’s nothing else, it is not a new concept. It is plain Ruby. - Xavier Noria


    どのように懸念を使用するには?


    を作成しましょうVisible からの可視性関連コードを抽出する懸念Post and Comment モデル.一般にVisible それが見えるかどうかについて、懸念は実体の可視性を扱います.
    # visible.rb
    
    module Visible
      extend ActiveSupport::Concern
    
      # The code inside the included block is evaluated
      # in the context of the class that includes the Visible concern.
      # You can write class macros here, and
      # any methods become instance methods of the including class.
      included do
        attr_accessor :visible_to
    
        def is_visible?
          visible_to.present?
        end
      end
    
      # The methods added inside the class_methods block (or, ClassMethods module)
      # become the class methods on the including class.
      class_methods do
        def count_all_visible
          all.select { |item| item.is_visible? }
        end
      end
    end
    
    この問題を使用するには、通常通りモジュールを含めます.例えば、Post モデル募集visibility 機能性、それはVisible 懸念
    class Post
      include Visible
    
    end
    
    この懸念を含むvisible_to 属性is_visible インスタンスメソッドcount_all_visible クラスメソッドPost クラス.
    以下のテストはこれを示します.
    require "test_helper"
    
    class PostTest < ActiveSupport::TestCase
    
      test "Post can include the visible concern" do
        post = Post.new
        assert_not post.is_visible?
    
        post.visible_to = "reader"
        assert_equal "reader", post.visible_to
        assert post.is_visible?
    
        assert_equal [], Post.count_all_visible
      end
    end
    

    なぜ我々は懸念が必要ですか?


    あなたは不思議かもしれません:すべてのこの賢さのポイントは何ですか?我々が中央の場所でいくつかの一般的なふるまいを抽象化しようとしているならば、我々は単に新しいクラスを作成することができません.そして、あなたは正しいでしょう.
    共有コードを含むクラスを作成し、インスタンス化して使用できます.
    visibility_manager = Visibilty.new
    
    visibility_manager.is_visible(post)
    
    しかし、懸念はしばしば適切な量の抽象化です.そして、より友好的なAPIに終わります.あなたが必要とするすべてのメソッドは、プライマリオブジェクトの右側にありますvisibility_manager 共有コードにアクセスするには
    DHHがこの問題にどのように対処しているのでしょうか

    So that’s another way of putting this: It’s a writing style. Like using subheads to explain subservient ideas within a broader context. You could probably extract all those subheads out, and turn them into little essays of their own. But that’s often just not the right level of extraction. As you saw, the Accessor role starts life as literally just two methods! It doesn’t warrant being turned into it’s own class. It doesn’t have an independent center of gravity. - A May of WTFs


    それは一つのクラスの下でまだ生活している間、関連する方法をグループ化する方法です.
    それは構造化された文書です.

    Original Post: How Rails Concerns Work and How to Use Them