※ RubyやRailsの素人なので,用語や表現など間違っているところがあったら,指摘してもらえば幸いです!
はじめに
コントローラで,あるアクションを処理してから,ビューがレンダーされる前の間に,何かの処理を挟み込む場合ができて,色々考えたり調べたりして方法をまとめてみた.
内容
アプローチ1
ActionController::Instrumentation#render
をオバーライドする.
class UsersController < ApplicationController
def render(*args, &block)
foo if action_name == "index"
bar if action_name == "show"
super
end
end
でも,Reusabilityがまったくないコードになってしまった…
アプローチ2
before_action
,after_action
のように,before_render
というフックメソッドとして実装する.
コントローラのコンサーンとして書いて,複数のコントローラで使えるようにする.
app/controllers/concerns/before_render.rb
module BeforeRender
extend ActiveSupport::Concern
included do
define_callbacks :render
alias_method_chain :render, :before_render
end
def render_with_before_render(*options, &block)
run_callbacks(:render) do
render_without_before_render(*options, &block)
end
end
module ClassMethods
def before_render(*names, &block)
_insert_callbacks(names, block) do |name, options|
set_callback(:render, :before, name, options)
end
end
end
end
コントローラでは,こんな風に使える.
app/controllers/users_controller.rb
class UsersController < ApplicationController
include BeforeRender
before_render :foo, only: [:show]
before_render unless: [:destroy] do |controller|
bar
end
def foo
end
def bar
end
end
まとめ
ちゃんとできているのか確信はないけど,一通りテストをやってみた結果,思い通りには動いてる.
コードは,http://github.com/cryeo/before_render にまとめておいた.
参考
- http://www.perfectline.co/blog/2009/10/ruby-on-rails-before-render-filter/
- http://api.rubyonrails.org/classes/AbstractController/Callbacks/ClassMethods.html
- http://api.rubyonrails.org/classes/ActiveSupport/Callbacks/ClassMethods.html
- http://api.rubyonrails.org/classes/ActiveSupport/Callbacks.html
- http://api.rubyonrails.org/classes/ActionController/Instrumentation.html