Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rails3 redirect to previous action upon user authentication? (before_filter & store_location)

I've read almost all the posts related to Rails friendly redirecting, but I can't seem to figure out how to redirect a user to a previous action after authenticating with Devise.

This is what I would like to do.

  1. Unlogged-in user clicks "Vote"
  2. User is directed to login page, because of "before_filter :authenticate_user!" (I've gotten this far)
  3. After user logs in, "after_sign_in_path_for(resource)" redirects user to previous action (the vote).
  4. The vote action is casted, and then is redirected to the original page where user clicked vote button. ('request.referer' does this if the user was already signed in, but because the user had to go through the login page in this case, request.referer doesn't work.)

*note that I want to redirect to the previous "action," not just the "page." In other words, I want the intended action to have already been performed after user logs in.

Here is my code.

class MissionsController < ApplicationController
  before_filter :store_location
  before_filter :authenticate_user!, :except => [:show, :index] 

  def vote_for_mission
    @mission = Mission.find(params[:id])
    if @mission.voted_by?(current_user) 
      redirect_to request.referer, alert: 'You already voted on this mission.'
    else
      @mission.increment!(:karma)
      @mission.active = true
      @mission.real_author.increment!(:userpoints) unless @mission.real_author.blank?

      current_user.vote_for(@mission)
      redirect_to request.referer, notice: 'Your vote was successfully recorded.'
    end
  end
end

and in my applications controller,

class ApplicationController < ActionController::Base

  protect_from_forgery                                                                                                       

  def after_sign_in_path_for(resource)
    sign_in_url = "http://localhost:3000/users/sign_in"                                     
    if (request.referer == sign_in_url)
        session[:user_return_to] || env['omniauth.origin'] || request.env['omniauth.origin']  || stored_location_for(resource) || root_path      
    else
      request.referer
    end
  end

  private
  def store_location
    session[:user_return_to] = request.referer
  end

I think my main problem is that the "request.referer" inside the vote_for_mission action is going somewhere unintended when the user is required to log in, because the previous page is the signin page. Somehow, I would like to save the page where user clicks vote as FOO -> save the vote action as BAR -> redirect to signin page -> when user logs in, redirect to BAR -> after performing the BAR action, redirect to FOO.

Thanks in advance for the help!

like image 264
kibaekr Avatar asked Dec 03 '25 15:12

kibaekr


1 Answers

What I generally do is to have methods within ApplicationController like this:

def remember_location
  session[:back_paths] ||= []
  unless session[:back_paths].last == request.fullpath
    session[:back_paths] << request.fullpath
  end

  # make sure that the array doesn't bloat too much
  session[:back_paths] = session[:back_paths][-10..-1]
end

def back
  session[:back_paths] ||= []
  session[:back_paths].pop || :back
end

Then, in any action (in your case the login handler), you can just

redirect_to back # notice, there is no symbol

and in every action you would like to be able to jump back to, just call

remember_location

I hope this helps.

like image 68
moritz Avatar answered Dec 06 '25 06:12

moritz