Redirect to a specified URL after a POST in Rails

4.2k Views Asked by At

So often I have a form in some webpage that the user submits to a POST, PUT or DELETE action in Rails where I want it to redirect to a specified URL if the submission was a success. I typically make a hidden extra parameter called to with a path like /users. So if the form submission failed, it just stays on that form, but if it succeeds then the browser is redirected to /users.

I'd like to automatically look for this parameter and always redirect to it if a form submission succeeded in any controller/action. Do I put this in the ApplicationController within an after_action?

class ApplicationController < ActionController::Base
  after_action :redirect_if_success

  private
  def redirect_if_success
    redirect_to params[:to] if params[:to]
  end
end

I guess I can check the request object if this was a POST, PUT or DELETE action. How do I know the submission was a success? Will a redirect_to in the after_action override any redirect_tos in the form controller?

2

There are 2 best solutions below

0
On

I think the solution is define private method redirect_if_success in application controller but call it directly in the action. eg:

class ApplicationController < ActionController::Base

  private
  def redirect_if_success(default_ur)
     redirect_to params[:to] || default_url
     # or similar logic
  end
end

class UserController < ApplicationController::Base

  def create
    redirect_if_success("/users") if @user.save
  end
end
0
On

I would create a helper method

def redirect_to_location
  redirect_to params[:to] && params[:to].present?
end

and I would use it explicitly in each action I want this behaviour.

However, you could experiment a bit. To keep this logic in after_action you would need to setup some state that would let you know whether you need to redirect or not.

You could do :

def save
  if @user.save
    @follow_redirect = true
  end
end

and check @follow_redirect flag in after_action filter. Does not look like a very pretty solution but it would work.

You could also try to inspect response variable to see if you have already redirected or rendered an action: (not sure if it would work but it's fun to experiment)

So you could check:

if you need to redirect (action is post/put/delete) and params[:to] is present and if you have not already redirected/redirected

# this is not a copy-paste code but rather to demonstrate an idea
class ApplicationController < ActionController::Base 
  after_action :redirect_to_location

  protected 

  def is_redirectable?
    %w{post put delete}.include?(request.method) && params[:to].present?
  end

  def already_redirected?
    !response.status.nil? # not sure if it would work at all 
  end

  def redirect_to_location
     redirect_to params[:to] if is_redirectable? && !already_redirected?
  end
end