ruby-on-rails - rails5 - rubyonrails blog




Rails 4での懸念の使用方法 (4)

デフォルトのRails 4プロジェクトジェネレータはコントローラとモデルの下にディレクトリ "concern"を作成します。 私はルーティングの問題を使う方法についていくつかの説明を見つけましたが、コントローラやモデルについては何も見つかりませんでした。

私はコミュニティの現在の "DCIトレンド"と関係があり、それを試してみたいと思っています。

問題は、どのように私はこの機能を使用することになっています、それを動作させるために命名/クラス階層を定義する方法に関する規則がありますか? モデルやコントローラに懸念事項を含めるにはどうすればよいですか?


この投稿は私が懸念を理解するのを助けました。

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

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

ここでは、 ActiveSupport::Concernmoduleどのように価値を付け加えるかではなく、 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

この例では、 BarHost本当に必要とするモジュールです。 しかしBarFooの依存関係を持っているので、 Hostクラスinclude Fooinclude Foo必要がありinclude Foo (ただし、 Host include 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

今はシンプルに見えます。

なぜあなたはBarモジュール自体にFoo依存関係を追加するのか考えているのですか? method_injected_by_foo_to_host_klassBarモジュールではなくBarを含むクラスにmethod_injected_by_foo_to_host_klassなければならないので、 method_injected_by_foo_to_host_klassは動作しません。

ソース: Rails ActiveSupport :: Concern


心配を使うことは多くの人にとって悪い考えであると言及する価値があります。

  1. この男のように
  2. これと

いくつかの理由:

  1. その背後には暗い魔法がいくつか起こっています - 問題にはパッチを当てる方法があります。依存システムを扱うシステム全体があります。古き良き古いRubyミックスインパターンのために複雑すぎます。
  2. あなたのクラスはあまり乾燥していません。 50個のパブリックメソッドをさまざまなモジュールに入れてそれらをインクルードすると、クラスには50個のパブリックメソッドがあります。コードの臭いを隠すだけです。あなたのゴミをドロワに入れます。
  3. コードベースは実際には、それらの懸念をすべて回避してナビゲートするのが実際より困難です。
  4. あなたのチームのすべてのメンバーが本当に代わりになるべきことを理解していますか?

懸念事項は、脚に自分を撃つ簡単な方法です。慎重に行ってください。


懸念されるファイルfilename.rbを作る

例えば、私のアプリケーションでは、属性create_byが存在していて、その値が1で更新され、0がupdated_by

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

その後、あなたのモデルに次のように追加します:

class Role < ActiveRecord::Base
  include TestConcern
end




dci