Subscribed unsubscribe Subscribe Subscribe

アクションにおけるrespond_toの分岐をDRYにしてみる(Responders)

Railsで以下のようなrespond_toの分岐を見ることがあると思います。

こちらはRails4.2からはrespondersというgemでDRYに書くと以下のようになります。

これによって、respond_toに関連する処理がresponders内のソースに集約され、
また、flash時の文言もi18nのファイルに集約されます。

def create
  @user = User.new(params[:user])
  respond_to do |format|
    if @user.save
      flash[:notice] = 'User was successfully created.'
      format.html { redirect_to(@user) }
      format.xml { render xml: @user }
    else
      format.html { render action: "new" }
      format.xml { render xml: @user }
    end
  end
end

↓

respond_to :html, :xml

def create
  @user = User.new(params[:user])
  flash[:notice] = 'User was successfully created.' if @user.save
  respond_with(@user)
end

また、flashの文言は以下のようにi18nのファイルに記載すれば自動的に使用されます。

flash:
  actions:
    create:
      notice: "%{resource_name} was successfully created."
    update:
      notice: "%{resource_name} was successfully updated."
    destroy:
      notice: "%{resource_name} was successfully destroyed."
      alert: "%{resource_name} could not be destroyed."

respond_withは以下の通りです。

responders/respond_with.rb at master · plataformatec/responders · GitHub

def respond_with(*resources, &block)
  if self.class.mimes_for_respond_to.empty?
    raise "In order to use respond_with, first you need to declare the " \
      "formats your controller responds to in the class level."
  end

  mimes = collect_mimes_from_class_level()
  collector = ActionController::MimeResponds::Collector.new(mimes, request.variant)
  block.call(collector) if block_given?

  if format = collector.negotiate_format(request)
    _process_format(format)
    options = resources.size == 1 ? {} : resources.extract_options!
    options = options.clone
    options[:default_response] = collector.response
    (options.delete(:responder) || self.class.responder).call(self, resources, options)
  else
    raise ActionController::UnknownFormat
  end
end

save等の成功時には以下のようになると考えてください。

redirect_to options[:location] || resources

ちなみにエラー時は以下の対応するアクションがレンダーされます。

DEFAULT_ACTIONS_FOR_VERBS = {
  :post => :new,
  :patch => :edit,
  :put => :edit
}