文字列を処理するための特定のメソッドや、多数のコントローラーで実行されるその他のタスクを作成しようとしています。コントローラーにヘルパーを含めるのは悪い習慣だと知っているので、コントローラーで使用されるアプリケーション全体のメソッドを配置するのに最適な場所はどこでしょうか。
モデルに入れると言う人もいると思いますが、すべてのコントローラーにモデルが関連付けられているわけではないことを理解する必要があります。ありとあらゆる入力をいただければ幸いです。
文字列を処理するための特定のメソッドや、多数のコントローラーで実行されるその他のタスクを作成しようとしています。コントローラーにヘルパーを含めるのは悪い習慣だと知っているので、コントローラーで使用されるアプリケーション全体のメソッドを配置するのに最適な場所はどこでしょうか。
モデルに入れると言う人もいると思いますが、すべてのコントローラーにモデルが関連付けられているわけではないことを理解する必要があります。ありとあらゆる入力をいただければ幸いです。
私はそれらをヘルパーに入れる傾向があります。それらが自動的にビューに含まれるという事実は、私にとって問題ではありませんでした。app/cerns/やlib/のようなものに配置することもできます
ApplicationControllerをプライベートメソッドで乱雑にするのは好きではありません。これはしばしば混乱するからです。
例:
module AuthenticationHelper
def current_user
@current_user # ||= ...
end
def authenticate!
redirect_to new_session_url unless current_user.signed_in?
end
end
module MobileSubdomain
def self.included(controller)
controller.before_filter :set_mobile_format
end
def set_mobile_format
request.format = :mobile if request.subdomain == "m"
end
end
class ApplicationController
include AuthenticationHelper
include MobileSubdomain
end
アプリケーションスコープでメソッドを使用する必要がある場合は、それらのメソッドをアプリケーションコントローラー内に保持し、ビュー内で使用するために、それらをヘルパーメソッドとして宣言することをお勧めします。
例えば、
class ApplicationController < ActionController::Base
helper_method :current_user, :some_method
def current_user
@user ||= User.find_by_id(session[:user_id])
end
def some_method
end
end
lib
それらをフォルダに入れることをお勧めします。たとえば、私は次のようにしています。
lib/utils/string_utils
module StringUtils
def foo
...
end
end
class BarController < ActionController::Base
include StringUtils
end
これは、ファットモデル、シンコントローラーと呼ばれる優れた方法論を示しています。この場合、ロジックを分離するためにモデルの代わりにミックスインを使用していますが、考え方は同じです。コントローラはできるだけシンプルにする必要があります。
それはすべてあなたのニーズに依存します。ここでは2つの例を示します。どちらも、lib
ディレクトリの下にある単なるカスタムライブラリです。
最初の例-「カスタム文字列処理」
# lib/filters.rb
module Filters
# Converts value to canonical view
def self.phone(value)
# remove all non-digits
clean_value = value.gsub(/\D/, '')
country_codes = configus.phone.country_codes
area_code = configus.phone.defaults.area_code
case clean_value.length
when 7
"#{area_code}#{clean_value}"
when 11
# remove country code only if phone starts with the allowed country code
if country_codes.include?(clean_value[0].to_i)
clean_value[1..-1]
else
clean_value
end
else clean_value
end
end
# usage
# app/api/phones_controller.rb
class Api::PhonesController < Api::ApplicationController
def exists
if params[:q]
clean_value = Filters.phone(params[:q])
...
end
end
end
2番目の例-フラッシュメッセージのヘルパー
# lib/flash_helper.rb
module FlashHelper
def flash_translate(key, options = {})
scope = [:flash, :controllers]
scope += params[:controller].split('/')
scope << params[:action]
t(key, {:scope => scope}.merge(options))
end
end
# app/application_controller.rb
class ApplicationController < ActionController::Base
include FlashHelper
end
# usage
# app/your_controller.rb
class YourController < ApplicationController
def create
@object = Object.new(params[:object])
if @object.save
flash[:success] = flash_translate(:success)
...
end
end
end
lib
注:自動ロードパスにdirを追加することを忘れないでください。このconfig/application.rb
行を追加/変更しますconfig.autoload_paths += %W(#{config.root}/lib)
。だから私にとっての答えはlib
ディレクトリです。
Rails 4以降、専用のフォルダーがありますapp/controllers/concerns
。したがって、そこでモジュールを作成し、それを特定のコントローラーに含めるか、すべてのコントローラーで使用できるようにする必要がある場合はApplicationControllerに含めることができます。
これらのメソッドが多数のコントローラーで使用されている場合は、で定義しますapplication_controller.rb
。すべてのコントローラーはそれを継承し、そこで定義された任意のメソッドを使用できるようになります