コード共有

オブジェクトとしてアクションは多くの利点を持っているが、彼らは、コードの共有がより直感的にします。このセクションでは、これを可能にするためにいくつかのテクニックを共有しています。

 

準備します

私たちの設定(でapps/web/application.rb)、私たちはのためのコードを共有することを可能にするコードブロックがあるすべてのアクション我々のアプリケーションのでは。アクションが含まれている場合Web::Action、モジュールを、そのブロック符号は、そのクラスのコンテキスト内で生じています。これは、頻繁にRubyのモジュールとその触発されincludedたフック。

我々は現在のリクエストが認証されたユーザから来ているかどうかを確認したい想像してみてください。

私たちは、モジュールを作りますapps/web/controllers/authentication.rb

# apps/web/controllers/authentication.rb
module Web
  module Authentication
    def self.included(action)
      action.class_eval do
        before :authenticate!
        expose :current_user
      end
    end

    private

    def authenticate!
      halt 401 unless authenticated?
    end

    def authenticated?
      !!current_user
    end

    def current_user
      @current_user ||= UserRepository.new.find(session[:user_id])
    end
  end
end

アクションによって含まれると、それが設定されます前に、コールバック実行:authenticate!要求ごとに。ログインしていない場合は、Aが401返され、そうでない場合、フローは先に行くとヒットすることができます#call。また、公開するcurrent_userすべてのビュー(参照のためのエクスポージャーを)。

我々のアプリのすべてのアクションのために、このモジュールが含まれて本当に退屈になります。我々は使用することができcontroller.prepareスコープのため。

# apps/web/application.rb
require_relative './controllers/authentication'

module Web
  class Application < Hanami::Application
    configure do
      controller.prepare do
        include Web::Authentication
      end
    end
  end
end

コードは経由含まれprepareたアプリケーションのすべてのアクションのために利用可能です。

 

コールバックをスキップ

我々は含まれていたとしましょうAuthentication世界的に、しかし、特定のリソースのためのコールバックの実行をスキップしたいです。典型的なユースケースは、形で私たちの看板に認証されていない要求をリダイレクトすることです。

解決策は、同時に本当にシンプルかつエレガントです:そのメソッドをオーバーライドします。

# apps/web/controllers/sessions/new.rb
module Web::Controllers::Sessions
  class New
    include Web::Action

    def call(params)
      # ...
    end

    private
    def authenticate!
      # no-op
    end
  end
end

アクションはまだ起動しようとする:authenticate!技術的に言えば、ため、コールバックの実行をスキップすることはできません。私たちは空の実装でそのメソッドをオーバーライドした場合でも、それは何もしませんし、私たちの非signedinユーザーが希望のリソースに到達することができます。

 

モジュールのインクルージョン

私たちは名前のRESTfulなリソースを持っている想像してみてbooks。いくつかのアクション(がありshoweditupdatedestroy自分の仕事を実行するための具体的な本を見つける必要があります)。

私たちは、これらすべてのアクションのコードを乾燥させるために何をしたい場合は?Rubyは私たちの救助に来ます。

# apps/web/controllers/books/set_book.rb
module Web::Controllers::Books
  module SetBook
    def self.included(action)
      action.class_eval do
        before :set_book
      end
    end

    private

    def set_book
      @book = BookRepository.new.find(params[:id])
      halt 404 if @book.nil?
    end
  end
end

私たちは、私たちの行動を共有するためのモジュールを定義しています。のは、それを必要とするすべてのアクションに含めましょう。

# apps/web/controllers/books/update.rb
require_relative './set_book'

module Web::Controllers::Books
  class Update
    include Web::Action
    include SetBook

    def call(params)
      # ...
    end
  end
end