Manually setting return_to with devise - ruby-on-rails

I am currently using Devise to authenticate users on my app. It's working great for the most point, but I am having trouble with a specific action:
view:
<p id="save"><%= link_to "Save", new_save_path, :remote => true %></p>
saves_controller.rb:
def new
if user_signed_in?
#save = Save.create(:user_id => current_user.id)
render :update do |page|
page.replace_html "save", "Saved!"
end
else
redirect_to new_user_session_path, :notice => "You need to sign in to do that."
end
end
As you can see, because the action is an ajax one, I can't use the traditional before_filter :authenticate_user! method. So instead I am redirecting the user to the sign in page.
The problem is, I want to automatically redirect the user back to the previous page when they logged in.
I understand I can do this with the session[:"user.return_to"] but I'm having trouble setting it. How can I do this? Or am I going about this all wrong?

I believe the session key is :"#{scope}_return_to, which will be simply :user_return_to for a User class.

Related

Best approach to hide certain user information on rails using devise as the method for authentication?

Currently I'm creating a rails app for understanding the framework right now my controller authenticates the user, I have three types of user using enum and a field called row in the users table and on my application controller I have this
class ApplicationController < ActionController::Base
protect_from_forgery with: :exception
protected
def authenticate_editor!
redirect_to request.referrer, :flash => { :error => "You don't have
the permissions to do this!" } unless user_signed_in? &&
current_user.editor?
end
def authenticate_admin!
redirect_to request.referrer, :flash => { :error => "You don't have
the permissions to do this!" } unless user_signed_in? &&
current_user.admin?
end
end
So right now on my controllers, I defined a before action for those protected methods, for example the admin role is the only one who can't destroy posts in my posts_controller. That works but on my view any user can see the destroy action link on the index page of that model, if a regular user clicks that link, the flash appears and he's unable to complete the action but I don't want regular users to see the link if is useless to them, I know I can hide it for example using this:
<% if current_user.admin? %>
<%= link_to 'Destroy', post_path(post),
method: :delete,
data: { confirm: 'Are you sure?' } %>
<% end %>
But I want to know if this is the correct approach, should I continue using conditional for those links to actions or if there's a better way?

How do I get flash[:notice] to display in my view?

I'm having difficulty getting my notices to display in my Rails 5 view. I have this before_filter method set up in a controller:
def check_email_confirmed!
redirect_to controller: "users", action: "edit", notice: 'Please confirm your email.' unless current_user.email_confirmed
end
and in my view I have this
<% if flash[:notice] %>
<p class="flash-notice"><%= flash[:notice] %></p>
<% end %>
but despite the fact that I know the notice is getting set (I see it in my URL) the above is not getting invoked in my view (I see no HTML with the class="flash-notice").
Is there some other way I should be setting flash notices in a redirect? Or should I be using a redirect at all (someone told me there might be some security risks in embedding messages in the URL query string)?
You're currently setting a parameter with the key notice, not setting the flash in your session.
To accomplish this the way you're doing it you would have to do:
<p class="flash-notice"><%= params[:notice] %></p>
Most Rails apps that I've worked on set the session[:flash] in the controller method, in which case you would do:
unless current_user.email_confirmed
redirect_to edit_user_path(current_user)
flash[:notice] = 'Please confirm your email.'
end
Unless you have a good reason to pass the notice text as a URL param, I'd recommend doing it this way.
Try
flash[:notice] = 'bla'
redirect_to controller: "users", action: "edit"
I'm pretty sure that
redirect_to edit_user_path(user), notice: 'bla'
Will also work. For some reason your syntax apparently doesn't pick up the notice modifier. But you'll have to assign user to your current user for that to work obviously.

Non Mass assignable field in view

Iam kinda stuck at this problem. Trying to update a non mass-assignable attribute in the job model from an admin view. I need a button which trigger an action method in the admin controller which just changes job's isactive value to true.
In admin controller:
def approve
#job.update_attribute(:isactive = true)
if #job.save
redirect_to(:action => :show)
flash[:notice] = "Job Approved"
else
render 'show'
end
end
In jobs/1 view
<div style="text-align:center;" class="widget">
<%= form_for(#job, :url => url_for(:controller => 'admin', :action => 'approve'), :html => {:id => "contact_form", :class => "g-form"}) do |f| %>
<%= button_tag( :class => "g-btn type_default") do %>
<i class="icon-share-alt icon-white"></i>Approve this job
<% end %>
<% end %>
<% end %>
No matter what i do this form gets submitted to the job update action and show job successfully updated rather than the notice "Job approved" from the approve action in admin.
I have added the following route as well. but not sure what iam doing wrong. I need a simple button (ideally a block because of the styling req) which sets job's isactive field to true.
match "jobs/:id", :via=>:post, :controller=>"admin", :action=>"approve"
Mass assignment was designed to protect precisely against what you're trying to do here so ideally speaking, you should add it to a whitelist (attr_accessible) if you need to modify it.
However, there are a few issues with your controller action that will need to be addressed even if you get the isactive attribute whitelisted.
#job.update_attribute(:isactive = true) is not valid. update_attribute does not handle assignments, the correct syntax is update_attribute(attribute, value) so it should be:
#job.update_attribute(:isactive, true)
Also, the update_attribute method calls save on the passed object. Calling #job.save after update_attribute (provided there is no other code assigning attributes) is redundant.
A better way to write this method would be:
def approve
if #job.update_attribute(:isactive, true)
redirect_to(:action => :show)
flash[:notice] = "Job Approved"
else
render 'show'
end
end
However, if you cannot modify the model and are not worried about callbacks or validation, you can update the database column directly with update_column (or update_columns in Rails 4):
def approve
if #job.update_column(:isactive, true)
redirect_to(:action => :show)
flash[:notice] = "Job Approved"
else
render 'show'
end
end

Rails Devise redirect after login

I am using Devise with Rails for my user login. It all works great, however, i am unable to get a specific redirection working.
I am new to rails so the method in which i am doing things may not be correct.
Essentially, with an example, i am allowing users to like a post. However, they need to be signed in to do so. I have created an action in my controller called 'like' and the controller has the devise filter
before_filter :authenticate_user!, :except => [:index, :show]
entered thereby the sign in page is being shown. Once the user signs in i want to redirect them back to the post which they have liked with the 'like' action having been called.
my controller looks like
def like
#post = Post.find(params[:id])
#like = Like.new;
#like.user_id = current_user.id;
#like.post_id = params[:id];
respond_to do |format|
if #like.save
format.html { redirect_to #post, notice: 'You have like this post' }
format.json { head :no_content }
else
format.html { redirect_to #post, notice: 'Sorry you like was not saved }
format.json { render json: #post.errors, status: :unprocessable_entity }
end
end
end
Naturally i cannot hard code the path using after_sign_in_path_for
def after_sign_in_path_for(resource)
#path to somewhere
end
But i have read that i can use a session variable and perhaps call that in the above code. In which part of Rails could i write the session variable, as it would be too late in the controller action (as devise takes over before it hits the like action) and i cannot see how to set it in the view.
Also my link looks like
<%= link_to "Like", {:controller => :posts, :action => :like, :id => #post.id}, {:method => :post } %> |
PS the redirection when using creating a new 'post' works ok i.e. the user signs in and are redirected to the new post view.
Any help and tips would be greatly appreciated.
Thanks
You are experiencing this because like action is specifically designed for POST. Therefore, you should make sure that user is signed in before you POST to that URL, and doing it with session is tricky:
You'd have to unprotect like method by excluding it from before_filter
Then check manually if user_signed_in? (mind you this is a helper method),
Then (if user is not signed in), stash what you are liking in session and redirect to sign in page with return URL
Upon user visiting this return URL (it will be a GET and not a POST), you would have to look up the session info and do what original Like was supposed to do (but by then user will be signed in).
Seeing that all of this dance will end with a GET request, why not make Like action work on GET requests as well as pass parameters in the Query String in the first place? It will require 0 code changes and it will not expose you to a security threat since Like is protected by before_filter. You would just have to make sure that your Like links aren't followed by search engines by using rel="nofollow" on your <a> tags.
For a related discussion, see redirect_to using POST in rails. There, one of the suggestions is to build and submit a form on the client via JavaScript. That would have to happen on that return URL view once user has authenticated. This might be the best compromise if you object to having your like action exposed as GET (which violates REST principles)
this is easy to fix:
go in application controller:
# after login redirect
after_filter :store_location
def store_location
# previous url save when its not a admin or user url
session[:previous_url] = request.fullpath unless request.fullpath =~ /\/users/ || request.fullpath =~ /\/admin/ || request.fullpath =~ /\/admin\/login/ ||
request.fullpath =~ /\/login/
end

Is there a way to redirect to a specific page after a RESTful delete in Rails?

Lets say I have a message resource. Somewhere in the html I have:
<%= link_to("Delete", message, :title => 'Delete', :confirm => 'Are you sure?',
:method => :delete )%>
Right after I delete it, it redirects me to the page where it lists all the messages. Is there a way to redirect to a page that I specify after the deletion?
In the controller:
def delete
Item.find(params[:id]).destroy
redirect_to :action => "index"
end
To redirect to the last url, use:
redirect_to :back
http://api.rubyonrails.org/classes/ActionController/Base.html#M000662
If you can learn how to read api docs well, they are extremely useful, once you get the hang of them.
It's actually the destroy action that you should be dealing with if you're using Rails' resources.
def destroy
Item.find(params[:id]).destroy
redirect_to other_specified_path
end
If you look at the API documentation, you'll see there's a HUGE difference between the ActiveRecord::Base#delete and ActiveRecord::Base#destroy methods. Only use delete if you really understand why you're using it.
i only need this
def delete
Item.destroy
redirect_to :back
end
i used this if i want to back to current page

Resources