- 更新日: 2015年8月19日
- Rails
RailsのSTIでコントローラーをまとめ、Strong Parametersを動的に設定
Rails で STI(Single Table Inheritance)を使う場合、コントローラーを1つにまとめたくなります。そうしないと、STI のサブクラスごとにコントローラを作成する必要があり、とても面倒くさくなってしまうからです。以下の説明等を参考。
[Rails] STI(Single Table Inheritance)でコントローラも一つに纏める | Developers.IO
Rails ActiveRecordのSTI(Single Table Inheritance)の使い方 | EasyRamble
— 環境 —
Rails 4.1.6
STI でコントローラーをまとめる
STI でコントローラーをまとめる場合、クラスメソッドさんの記事を参考にしまして、STI モデルのクラス名をパラメーター ( params[:type] )で取得して、new, create のアクション等で動的に STI モデルのオブジェクトを生成します。動的にモデルのオブジェクトを生成するので、Strong Parameters も動的に設定する必要がある。コントローラーのコードとしては、以下のような感じになるかと思います。
STI 利用でのコントローラーのサンプルコード
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 |
class SomeController < ApplicationController def new @object = type_class.new end def create @object = type_class.new(permitted_params) if @object.save # save successfully # ... else render 'new' end end #... private def permitted_params params.require(type_symbol).permit( parameters ) end def type # params[:type] に "SomeModel", "OtherModel" など STI モデルのクラス名を渡す params[:type] end def type_class type.constantize end def type_symbol type.underscore.gsub('/', '_').to_sym end def parameters type_class.column_names.map(&:to_sym) - [:id, :type, :created_at, :updated_at] end end |
Strong Parameters を動的に設定する
Strong Parameters の設定で params.require(type_symbol)… のように type_symbol と動的に設定する必要があります。これは、Rails が以下のようにモデル名に対応した params ハッシュのキー(シンボル)を生成するのが理由です。
“SomeModel” => :some_model
“OtherModel” => :other_model
“NameSpace::SomeModel” => :name_space_some_model
type_symbol メソッドで gsub してるのは、NameSpace::SomeModel のようなクラス名に対応するため。以下 pry での動作確認。
1 2 3 4 5 6 7 |
$ bundle exec rails c [1] pry(main)> "NameSpace::SomeModel".underscore.gsub('/', '_').to_sym => :name_space_some_model [2] pry(main)> "SomeModel".underscore.gsub('/', '_').to_sym => :some_model |
Strong Parameters で ActionController::Parameters の params.require(type_symbol).permit() メソッドには配列を渡せる。ソースを見ると分かります。
これを利用して、parameters メソッドの中で ActiveRecord#column_names メソッドを使って、こちらも動的にカラム名を取得するようにしました。不要なカラムは除外。カラム数が少なければ、以下のような通常通りの指定でも良いかと思います。
1 2 3 4 5 |
def permitted_params params.require(type_symbol).permit( :name, :post ) end |
こんな感じで Ruby/Rails の動的なパワーを活用すれば、STI 利用時にもコントローラーを1つにまとめられて良い感じです。
- Rails の関連記事
- RailsでMySQLパーティショニングのマイグレーション
- Rails ActiveRecordでdatetime型カラムのGROUP BY集計にタイムゾーンを考慮する
- RailsプラグインGemの作成方法、RSpecテストまで含めたrails pluginの作り方
- RailsでAMPに対応するgemをリリースしました
- Railsでrequest.urlとrequest.original_urlの違い
- Railsでwheneverによるcronバッチ処理
- Google AnalyticsのRails Turbolinks対応
- Railsアプリにソーシャル・シェアボタンを簡単設置
- Rails監視ツール用にErrbitをHerokuで運用
- Facebook APIバージョンのアップグレード手順(Rails OmniAuth)
Leave Your Message!