Rails 2.3 - Redirection Issues - ruby-on-rails

I have an application where folks search for an item. If the item is found, they are presented with a list of related items found by parameters in the URL AND a contact form. I'm having issues redirecting the visitor back to the same page (with the URL parameters) after submitting the form.
Any ideas?

Try redirect_to(:back).

You could use redirect_to :back, but note that this depends on the Referer header being set, and you'll run into an error if it's not for some reason.
To get around this, I use a method like the following in my application (I put it into ApplicationController so it's accessible in all my controllers):
def redirect_back_or_to(options = {})
if request.env["HTTP_REFERER"].blank?
redirect_to options
else
redirect_to :back
end
end
Which will redirect back if the Referer header is set and otherwise work like a normal redirect_to (so you can specify where to redirect to by default).

Related

How to prevent Brakeman 'unprotected redirect' warning when redirect to external domain is desired?

A model in a Rails app has a url column, where users can enter the address of external sites.
The urls are displayed on a page. When clicked, in addition to routing to that url, I need to perform some actions in the app. So I defined a controller action as follows
#objects_controller.rb
def click
#object = Object.find params[:id]
# do some stuff
respond_to do |format|
format.html { redirect_to #object.url }
end
end
and in the view
<%= 'click me', click_object_path #object %>
Brakeman is (as expected) throwing a warning
High - Redirect - Possible unprotected redirect
Normally the solution to this would be to add only_path: true to the redirect and only allow redirects within the current app. But in this case the desired behaviour is to navigate to an external site.
My questions
Are there any steps I should be taking to ensure malicious code cannot be entered and activated from the Object.url column (or in other words, is my click controller action the best way to archive the desired in-app actions plus navigation)?
If this is the correct approach, is there a way to quieten Brakeman so that this particular issue is no longer reported?
For anyone else having a similar issue, I added some checks to my controller to verify that #object.url is indeed a properly formatted url.
def click
#object = Object.find params[:id]
if #object.url =~ URI::regexp
obj_url = URI.parse(#object.url)
else
obj_url = nil
end
# do some stuff
respond_to do |format|
format.html { redirect_to obj_url }
end
end
And Brakeman reports 1 fixed warning. Result!

Can I override just part of an ActiveAdmin controller action using `super` + custom redirect?

I've registered a Widget in ActiveAdmin and want to change the redirect that takes place after creating a new one. So that I can accomplish various things with Javascript, I've created a custom form for creating/editing them such that in /admin/widget.rb I have this:
form do |f|
render "create_or_edit_widget"
end
I want to modify the basic Admin::WidgetsController#create action to change where the user is redirected after successfully creating one. I can fill out the rest of the custom action to complete this, except I don't know how to handle a case where the .save fails and the user is redirected back to the form with the formtastic inline error messages. I know how I could do this if I wanted the normal Rails form behavior of creating a list of error messages but not enough about Formtastic to copy its behavior. So far I have this:
controller do
def create
#widget = Widget.new(params[:widget])
if #widget.save
redirect_to admin_widgets_path, notice: "Successfully created Widget."
else
redirect_to :back
end
end
end
I was wondering if I can somehow user super and then only change the redirect path after successful creation instead of having to write out the entire action. If that's not possible, can anyone tell me where in the ActiveAdmin GitHub I'd be able to find the standard #create action so I can copy it out and change the one part?
Yes, you can do that. Here is a working code from my application using super and just changing the redirection
def create
super do |format|
redirect_to admin_submission_discussion_path(id: resource.discussion.slug, submission_id: resource.discussion.client_application.slug) and return if resource.valid?
end
end

Redirect from custom devise edit page

I am using devise for user registrations. I set up a custom edit page '/info' to use as an additional signup page. The only problem is after you submit the edits on the info page it redirects to the user profile. I am able to change it redirect to the home page (where I want after /info) but then it also redirects there from the normal edit page. I am not sure how to redirect based on what page the user is on.
My one idea was to get the users current path and use an if statement but I haven't been able to get that to work.
registrations_controller.rb:
def update
...
current_uri = request.env['PATH_INFO']
if current_uri == '/info'
redirect_to root_path, notice: "Welcome"
else
redirect_to user_path(#user)
end
end
Normally it just looks like this:
def update
...
redirect_to user_path(#user)
end
The problem seems to be you need to keep data around to determine where to redirect. A few ideas:
You could store data in the session when a user visits a previous page and check this data in your action to determine where to redirect the user. The session is often a convenient place to store things that are consistent between requests but that should not be persisted to the database.
You could store data in the database (for instance, add a flag to your user model) and check this to determine where to redirect.
You could check request.referer and redirect based on the value there. This may not be as reliable.

when to render with instance variable, and when to redirect?

My new and edit pages depend on an #important_data instance variable that is not used in the create and update actions.
As a result my page can't render the new page upon failure.
def create
#my_object = MyObject.new(params[:my_object])
if #my_object.save
redirect_to root_path
else
render action: "new"
#this can't render because the page asks for an #important_data variable that's not defined.
end
end
Which of the two solutions below should I choose?
What are the advantages/disadvantages of each?
OPTION 1: declare #important_data prior to render
def create
#my_object = MyObject.new(params[:my_object])
if #my_object.save
redirect_to root_path
else
#important_data = ImportantData.all
render action: "new"
end
end
OPTION 2: Redirect
def create
#my_object = MyObject.new(params[:my_object])
if #my_object.save
redirect_to root_path
else
redirect_to new_my_object_path
end
end
When you use render, you're using #my_object with the attributes updated from params[:my_object]. Most of the case, this is what you want. When you show the page to the user, you want to preserve the changes they made to the form and show them the errors.
When you use redirect, you're doing a different and additional request so the parameters submitted from the form are not preserved (unless you pass them in your call to redirect and build them up in the controller action).
So in most cases, you'll definitely want to declare #important_data when the validation fails. I can't think of a case where you'd want to redirect.
Offcourse, the Option1 will work best, since you are rendering new in case of errors only. Also, redirection li'l bit mess up the user experience, it will take a bit long to render the page again with same query #important_data = .... running again.
I think you should use OPTION1
So the place where redirect_to should be used is when you're doing a HTTP POST request and you don't want the user to resubmit the request when it's done (which may cause duplicate items and other problems).
In Rails, when a model fails to be saved, render is used to redisplay the form with the same entries that was filled previously. This is simpler because if you use redirect, you'll have to pass the form entries either using parameters or session. The side effect is that if you refresh the browser, it will try to resubmit the previous form entries. This is acceptable because because it will probably fail the same way, or if it's successful now, it was what the user should expect in the first place anyway.
The above answer is referenced from: Are redirect_to and render exchangeable?

Forward the user back to a post after adding a comment

This is probably a fairly simple thing to do - I have a site with a news feed that shows various posts. There are also other pages that similarly show posts. Comments can be added to these posts directly from any of these pages.
What I need to do is redirect the user back to the URL they came from, once they've added a comment, and to the particular post they commented on (each post has an id of post-#{post.id}, so I'd just have to stick #post-2 or whatever to the URL.
If the post could not be saved, for whatever reason, I'd also like to have the content that the user had submitted pre-filled into the comment box after the redirect.
How can I do these two things? The first is the more important one..
I'd have to store the URL that the user is coming from in the session on the new action and redirect to this on the create action? How can I get the URL?
I'm on Rails 3.1 by the way.
Thanks for the help!
You could use redirect :back which will send the user back to the page that issued the request
redirect_to :back
Assuming Comment is a resource nested under Post in your routing (/posts/123/comment/new):
def create
comment = Comment.new(params[:comment])
if comment.save
redirect_to post_path(comment.post)
else
redirect_to new_post_comment_path(params)
# or maybe you have the comment form on the Post#show page
# redirect_to post_path(params)
end
end

Resources