Tracking request before redirecting - ruby-on-rails

App has a lot of tests, and issue is that only authenticated users can view them. So when there are not, app redirects them to sing_in/login_as_guest page. For example user sings in or logs in as guest, after that I want to redirect them to the page they were actually going to.
But I have no idea from where to begin, and is this possible?
Can you please give me a key from where to begin?r

Here's an example:
class UserController < ApplicationController
def login
if User.authenticate(params[:user][:email], params[:user][:password])
referer = params[:referer] || session[:referer] || request.referer
flash.notice = 'Login succeeded'
redirect_to referer || root_path
else
flash.alert = 'Login failed'
redirect_to user_login_path
end
end
end
Now when you want to redirect back from somewhere, just add a referer path to either a param, the session or the request, and it will redirect back on success.

the end of chapter 5 and chapters 6,7,8,9 are step by step guide of what you need exactly
rails tutorial

Ok, I found the simple solution, works pretty well for me. Application controller:
if #current_permission.allow?(params[:controller], params[:action])
return true
else
redirect_to root_url
session[:was_going]=request.path #here I start session if request causes redirection
end
end
This method returns that request, if it exists
def root_or_request
if session[:was_going]
path=session[:was_going]
session[:was_going] = nil
return path
else
return root_url
end
end
And than after starting session I just redirect with calling this method.

Related

refactoring rails redirects with multiple ifs

In the app I am working on, the user can get to a new form from several different places. I need to redirect them back to where they came from. I solved it by passing a parameter in the link on the view, for example
= link_to "create a new post ยป", new_user_post_path(#current_user, :return_to => 'dashboard')
then in the new action in the controller like so
if params[:return_to] == 'dashboard'
session[:return_to]= 'dashboard'
end
now I am looking at the controller. what I need to do I can achieve by being really verbose, but I'm looking for a more elegant solution. Here is what I have now
if #user_post.save
flash[:notice] = "New Post Created"
if session[:return_to] == 'dashboard'
session.delete(:return_to)
redirect_to dashboard_path and return
else
redirect_to user_hub_path(#user)
end
else
flash[:error] = "Could not save post"
redirect_to new_user_post_path(#user)
end
This does what I need but I was hoping to tidy it up a little. I started looking at 1 line enumerators to see if I could do something like this...
if #user_post.save
flash[:notice] = "New post Created"
session[:return_to] == 'dashboard' ? redirect_to "#{session.delete(:return_to)}_path" : redirect_to user_hub_path(#user)
else
flash[:error] = "Could not save post"
redirect_to new_user_post_path(#user)
end
but it really doesn't like this part....redirect_to "#{session.delete(:return_to)}_path"
any advice? Guess I'm trying to get it to redirect and delete the session in one line and this is beyond my knowledge...
This looks like a good case for using Rails' built-in :back parameter, which, according to the Rails docs here, sends the user "Back to the page that issued the request. Useful for forms that are triggered from multiple places. Short-hand for redirect_to(request.env["HTTP_REFERER"])"
You can avoid passing a return_to param, and change your controller code to:
if #user_post.save
redirect_to :back, notice: "New Post Created" and return
else
redirect_to new_user_post_path(#user), flash: { error: "Could not save post" }
end
What about using send?
send takes a message name and optional arguments and forwards that to send's receiver (http://ruby-doc.org/core-2.2.0/Object.html#method-i-send)
path = send("#{session.delete(:return_to)}_path")
redirect_to path
In this case it sends the message to the current controller instance (same as just calling the ..._path method but gives the flexibility of the dynamic call)
Please instead of using a redirect_to variable of your controller, use the Referer Header.
HTTP referer (originally a misspelling of referrer) is an HTTP header field that identifies the address of the webpage (i.e. the URI or IRI) that linked to the resource being requested
In Rails is quite simple inside a controller
redirect_to request.referer
That is more elegant and efficient, because the session cookie storage can be expensive (cache storage) and could affect your HTTP cache proxies performance.

I don't want to redirect after sending reset password instructions with Devise

I need only show a message when send the reset password instructions, I don't need redirect to new session, I overwritten the controllerPassword but when I put a redirect_to there is a error with this render.
The path used after sending reset password instructions
def after_sending_reset_password_instructions_path_for(resource_name)
flash[:notice] = "We have sent an email with the instructions to reset your password"
redirect_to new_user_password_path and return
end
this is the error:
Render and/or redirect were called multiple times in this action......
How can I fix it?
If you remove redirect_to new_user_password_path and return from your code entirely it will stop redirecting. However, if you do this it won't show your flash notice until the user manually refreshes the page. From here there are two fixes:
redirect to the current page to force a refresh and show the notice.
bind your flash notice to an AJAX request so that it's sent asynchronously. There are a lot of ways to do that, but this answer covers it pretty well.
The controller action which is calling after_sending_reset_password_instructions_path_for has a render or a redirect_to.
Try removing redirect_to in after_sending_reset_password_instructions_path_for, and let the calling action handle it.
I have to overwrite other class called: SessionsController < Devise::SessionsController
I don't know if this is the best solution but worked for me.
This was I did:
class SessionsController < Devise::SessionsController
# GET /resource/sign_in
def new
url = (request.env["HTTP_REFERER"]).to_s
path = url.split("?").first
if path == "http://#{Rails.application.secrets.domain_name}/users/password/new"
redirect_to new_user_password_path and return
end
self.resource = resource_class.new(sign_in_params)
clean_up_passwords(resource)
yield resource if block_given?
respond_with(resource, serialize_options(resource))
end
end

Return user to previous page after login (Rails)

On a rails 2.3.8 site I have login links on each page (that takes a user to a separate signin page). After a successful login the user is currently redirected to root. Instead I'd like to redirect to the page they were previously viewing.
I've tried using request.referer:
redirect_back_or_default(request.referer)
Where redirect_back_or_default:
def redirect_back_or_default(default)
redirect_to(session[:return_to] || default)
session[:return_to] = nil
end
But that generates an "access denied" error, even though the login is successful.
Instead of trying to redirect to the referrer, I would set the session[:return_to]
You'll need a before filter that runs before your authentication on all your actions:
def store_return_to
session[:return_to] = request.url
end
Then change your redirect to just be
redirect_back_or_default()
Before all you must store your url by cookies:
cookies[:return_to_url] = request.url
And then after success logging:
redirect_to cookies[:return_to_url] || root_path
cookies[:return_to_url] = nil
# or even better code in one line:
redirect_to cookies[:return_to_url].delete || root_path
https://api.rubyonrails.org/classes/ActionDispatch/Cookies.html

Redirect after the sign up

Im trying to redirect the user after the sign up by saving the referer in case when user came to sign up through clicking on any specific page. But its not working properly.
In my app controller
def save_referer
unless user_signed_in?
unless session['referer']
session['referer'] = request.referer || 'none'
end
end
end
In user model
def save_with(referer)
referer = referer unless referer == "null"
self.save
end
Here im saving it
if current_user.sign_in_count <= 1
if current_user.save_with(session[:referer])
redirect_to session[:referer]
else
redirect_to any_other
end
In User model, I guess you are not explicitly referring the attribute correctly.
def save_with(referer)
self.referer = referer unless referer == "null"
self.save
end
Generally, I take this strategy:
Anywhere I have a signup button I link to signup like so:
Signup!
Then in my signup's Action I do this:
def signup
session[:signup_refer] = params[:signup_refer] if params[:signup_refer] # put the refer in a session
redirect_to(signup_path) if session[:signup_refer] && params[:signup_refer] # this clears params if you want to keep your url nice an clean for the user
# do signup stuffs
signup_refer = session[:signup_refer] # get the refer info in a variable
session[:signup_refer] = nil # clear the session before redirecting
redirect_to(signup_refer ? signup_refer : "/default_post_signup")
end
I know it could be messy, but it totally works for me (well works in Merb, where it's "redirect() not redirect_to()) but you get the idea.

How to redirect to previous page in Ruby On Rails?

I have a page that lists all of the projects that has sortable headers and pagination.
path:
/projects?order=asc&page=3&sort=code
I choose to edit one of the projects
path:
projects/436/edit
When I click save on that page, it calls the projects controller / update method. After I update the code I want to redirect to the path that I was on before I clicked edit a specific project. In other words, I want to be on the same page with the same sorting.
I saw link_to(:back) and thought that :back may work in redirect_to(:back), but that's a no go.
puts YAML::dump(:back)
yields the following:
:back
How can I get this to work?
In your edit action, store the requesting url in the session hash, which is available across multiple requests:
session[:return_to] ||= request.referer
Then redirect to it in your update action, after a successful save:
redirect_to session.delete(:return_to)
Why does redirect_to(:back) not work for you, why is it a no go?
redirect_to(:back) works like a charm for me. It's just a short cut for
redirect_to(request.env['HTTP_REFERER'])
http://apidock.com/rails/ActionController/Base/redirect_to (pre Rails 3) or http://apidock.com/rails/ActionController/Redirecting/redirect_to (Rails 3)
Please note that redirect_to(:back) is being deprecated in Rails 5. You can use
redirect_back(fallback_location: 'something') instead (see http://blog.bigbinary.com/2016/02/29/rails-5-improves-redirect_to_back-with-redirect-back.html)
I like Jaime's method with one exception, it worked better for me to re-store the referer every time:
def edit
session[:return_to] = request.referer
...
The reason is that if you edit multiple objects, you will always be redirected back to the first URL you stored in the session with Jaime's method. For example, let's say I have objects Apple and Orange. I edit Apple and session[:return_to] gets set to the referer of that action. When I go to edit Oranges using the same code, session[:return_to] will not get set because it is already defined. So when I update the Orange, I will get sent to the referer of the previous Apple#edit action.
This is how we do it in our application
def store_location
session[:return_to] = request.fullpath if request.get? and controller_name != "user_sessions" and controller_name != "sessions"
end
def redirect_back_or_default(default)
redirect_to(session[:return_to] || default)
end
This way you only store last GET request in :return_to session param, so all forms, even when multiple time POSTed would work with :return_to.
In rails 5, as per the instructions in Rails Guides, you can use:
redirect_back(fallback_location: root_path)
The 'back' location is pulled from the HTTP_REFERER header which is not guaranteed to be set by the browser. Thats why you should provide a 'fallback_location'.
request.referer is set by Rack and is set as follows:
def referer
#env['HTTP_REFERER'] || '/'
end
Just do a redirect_to request.referer and it will always redirect to the true referring page, or the root_path ('/'). This is essential when passing tests that fail in cases of direct-nav to a particular page in which the controller throws a redirect_to :back
For those who are interested, here is my implementation extending MBO's original answer (written against rails 4.2.4, ruby 2.1.5).
class ApplicationController < ActionController::Base
after_filter :set_return_to_location
REDIRECT_CONTROLLER_BLACKLIST = %w(
sessions
user_sessions
...
etc.
)
...
def set_return_to_location
return unless request.get?
return unless request.format.html?
return unless %w(show index edit).include?(params[:action])
return if REDIRECT_CONTROLLER_BLACKLIST.include?(controller_name)
session[:return_to] = request.fullpath
end
def redirect_back_or_default(default_path = root_path)
redirect_to(
session[:return_to].present? && session[:return_to] != request.fullpath ?
session[:return_to] : default_path
)
end
end
link_to 'get me back', :back
The symbol :back is your swiss army knife.
I wonder if this will work
def edit
if request.referer != request.original_url
#return_here = request.referer
end
end
and use #return_here as a hidden value in the submit form.
of course reloading will kill this so just go back to a default fall back as needed.

Resources