動機
Rails4では、StrongParameterが採用され、コントローラに、permit処理を書く、というのがよくやるパターンです。(scaffoldもそうなっている)べつにこのままでもよいのですが、入力を受け取りmodelとviewへの命令に変換するというMVCにおけるコントローラ責務を考えてみたとき、リクエストパラメータを検証することは、責務として切り出しておいてもおかしくはなさそうです。特に
- コントローラが肥大化してきた
- 何か権限に基づいて、許容するパラメータを変更したくなったりして、permit処理にロジックが入り込む
などでコードの見通しが悪くなったり
- 名前空間をきって同じリソースを扱うコントローラを複数つくったが、permit処理は同じものを使いたい、けどコードが重複してしまう
といった場合にはなんらかの形で切り出したいと思ってしまいます。
共通化したいならconcernsに書けば?????
というご指摘もあるんですが、今回は、
パラメータ検証するという責務をコントローラから切り出す
ということにチャレンジしてみたいと思います。私が行っているプロジェクトで採用してみて、粉の設計判断がどういう結果をもたらすか、検証してみたいと思います。
いろいろご指摘などいただけると幸いです!
設定
app配下にparametersをつくります。その際、アプリケーションが自動でファイルを読み込めるように以下の設定を追加します。
module SampleProject
class Application < Rails::Application
# Settings in config/environments/* take precedence over those specified here.
# Application configuration should go into files in config/initializers
# -- all .rb files in that directory are automat"ically loaded.
config.autoload_paths += %W(#{config.root}/app/parameters)
実装
イベント(Event)という
- タイトル(title)
- 開始時刻(start_datetime)
- 終了時刻(end_datetime)
- 本文(content)
いうデータをもつリソースを扱うコントローラを考えます。
イベントは、コミュニティ(community)ごとに登録/編集することができ、またユーザのダッシュボード画面でも編集することができます。
このような、要件を満たすものを作る場合、以下のようなルーティングで、それぞれコントローラを割り当てます
resource :user_account do
namespace :user_accounts do
resources :events do
end
end
end
resources :communities do
resources :events do
end
end
class EventParameter
def self.create(params)
params.require(:event)
.permit(:title, :content, :start_datetime, :end_datetime)
end
end
class UserAccounts::EventsController < ApplicationController
def update
respond_to do |format|
if @event.update(EventParameter.create(params))
....
end
.....
end
class EventsController < ApplicationController
def create
@event = Event.new(EventParameter.create(params))
....
end
end
すっきりしましたね!!!