I have an action in a controller that I call from two different views. In each case, I want the action to redirect back to the page on which the link was clicked. At the moment I am doing this...
In this view I am passing a parameter like this...
%a.showtooltip#wprofile{:href => idea_vote_up_path(#idea, :source => 'idea'), :title => 'Awesome idea - vote up !', }
and in the controller...
if params[:source] == 'idea'
redirect_to idea
else
redirect_to ideas_path
end
This works fine, but does not feel elegant, especially as it ends up being in a few actions. Is there a better way?
You can rewrite it in following way:
redirect_to params[:source] == 'idea' ? idea : ideas_path
If you want to redirect back to the page (refresh current page)
redirect_to request.referer
Store the referrer in the session like so session[:previous] ||= request.referer and use it as redirect_to session.delete(:previous)
I find that a good way is to have a hidden input with the value you'd like to be as the return url. Seems like an easily manageable solution and has worked for me. This way you can create the hidden input in 1 or 1000 views and have a single line of code in the controller to do the redirects. I can't immediately think of what the cons to this approach would be.
In form
hidden_field_tag(:redirect_to, params[:redirect_to]) # in the form that is to be submitted, value determined by a query string
hidden_field_tag(:redirect_to, "/a/direct/value") # in the form, value specified directly
In controller
redirect_to params[:redirect_to].presence || idea_path(#idea)
Didn't test the code and don't know ruby sups well so double check but the logic should stand. The ".presence" takes care of situations where you don't want a custom redirect to and have no hidden input to specify.
Related
In my app I have a /thanks page that users were originally redirected to when completing a certain action. Now I want to redirect them to this page after multiple kinds of events and render different partials based on what the event was. So I added this to the /thanks page:
- case #event
- when "reservation"
= render 'thanks_job_created'
- when "charge"
= render 'thanks_job_charged'
Then, in the the JobsController#create action, I changed redirect_to thanks_jobs_path to this:
redirect_to thanks_jobs_path(params.merge(event: "reservation"))
...and added #event = params[:event] to JobsController#thanks.
The behavior works as intended, but I've found that using params.merge this way now displays every paramter in the URL, including authenticity token of the #create form, all of the Job attributes, etc. Before the URL looked correct (/jobs/thanks) because the only params were action and controller which are already indicated in the URL.
Is there a way for me to use params.merge without displaying all of that info in the URL?
If you just want to pass the event as a parameter, you don't need to use params.merge at all.
redirect_to thanks_jobs_path(event: "reservation")
will give you the path /jobs/thanks?event=reservation.
You could simply use except:
params.merge.except(:auth_token)
In your situation:
redirect_to thanks_jobs_path(params.merge(event: "reservation").except(:auth_token))
I have two different ways to access the url "localhost:3000/childrens/new".
I have a drop down in childrens/new page and when the user selects an option through the drop down, it shows the different partials using ajax to call the childrens#new method.
accessing the childrens new page from url "localhost:3000/parents"
accessing the childrens new page from url "localhost:3000/parents1"
After the children have been successfully created, the user should be redirected to the relevant url (either localhost:3000/parents or localhost:3000/parents1)
Store the value in session like session[:last_request] in parent
After create children redirect it to session[:last_request] || session[:return_to] and after that clear the session[:last_request]
There are more than one way of how you can achieve this.
One solution would be to store the referrer inside of the session/cookie when the childrens/new is requested: (inside children_controller)
def new
session['children_new_referrer'] = request.env["HTTP_REFERER"]
#....YOUR CODE....
end
And then using that referrer value stored in session/cookie to redirect appropriately:
def create
#.....YOUR CODE....
if #child.save
format.html {redirect_to (session['children_new_referrer'] || parents_path)}
#.....YOUR CODE....
end
where #child is the object which I assume you are building with the parameters, and parents_path is being defined through your routes. Feel free to adjust these two based on your needs.
An alternative solution would be to not use sessions, but instead save the referrer uri/path inside of the children/new form page itself. This alternative has the benefit of making the solution session/request scope independent with handling the requirement of storing the referral uri/path within the page scope.
Do something like this
def create
redirect_to :back
end
redirect_to :back should come after save.
Pass the referrer as a parameter in the link. I would much prefer this solution to using the session store.
<%= link_to "New child", new_child_path(referrer: #parent.id) %>
.. or whatever you want to call it. Then you can inspect params[:referrer]. You're not wanting to persist data across a 'session', so why use the session store.
request.url
in your controller gives the url you are asking for.
So,
def create
if #child.save
redirect_to request.url
end
end
will do the job perfectly
I think this is a pretty simple question but nothing I've read has answered my question directly:
I have a new products page with a standard form. After successfully submitting the form, I redirect to a custom controller action and view called "thanks".
On the "thanks" page, I want to be able to print the name of the product just created and possibly some other attributes.
How do I pass the object just created into my new action? Right now the controller looks like this:
def create
#product = Product.new(params[:product])
if #product.save
flash[:notice] = "Successfully created Product."
redirect_to thanks_path
else
render :action => 'new'
end
end
def thanks
end
You can't send object through redirect.
There are three ways to solve your problem:
Render the 'thanks' template directly(not action #thanks)
render 'thanks' # thanks template
You can send whatever instance variable to this template directly. #thanks is no longer needed in this case.
Drawback: The url won't be changed.
Convey messages through session
If you want to show certain messages, you can prepare it in #create and send it through session or flash(part of session actually). flash is better as you don't need to clear it manually.
Note: You may want to use ActiveRecord as session storage if the message size is big, otherwise you'll meet CookiesOverflow by default setting.
Send very simple message through session say obj_id
Similar to #2 but I thinks this is better than #2. In #thanks, you can construct complex message according to if obj_id is present, what is the id and then find related data through db.
You have two fairly decent options.
First, you could adjust the thanks_path route to take an id parameter, and call it like redirect_to thanks_path(#product). Then you can call it up in your thank you method like any standard show method. It might be worth mentioning that if you are going to be displaying sensitive information on the thank you screen, you may want to use a random uuid, instead of an id, to look up the product.
A better way might be to not redirect at all, but rather adjust your view from simply drawing the form to something like this:
<% if #product && !#product.new_record %>
THANK YOU MESSAGE GOES HERE
<% else %>
EXISTING FORM GOES HERE
<% end %>
Is there a way in rails/ruby to simplify my routing code to be elegant like:
redirect_to user.role + _url
This way if the user is an admin they will be routed to the admin page so on so forth for other user types...
Sure!
redirect_to send("#{user.role}_url")
in ruby, the send will execute the method on the receiver, and that's exactly what you want. Usually, that would look like:
#receiver_object.send(:admin_url)
But the url-helpers work in the global namespace, so you can send to global and have it work.
Easy way to test: Add this to a controller and watch it redirect you home:
redirect_to send("root_path")
Probably the best way would be to use the url_for helper. For example.
redirect_to url_for( :controller => users, :action => user.role )
This would generate a path /users/admin or /users/guest etc.
If you want to do it a hackish way you could use
redirect_to eval("#{user.role}_url")
Be careful with that though. The reason your string isn't working is it isn't evaluated, so redirect_to "admin_url" doesn't do anything, it's just a meaningless string and redirect is expecting the string to be a URL.
If you evaluate the string it would work, because redirect_to eval("#{user.role}_url") is going to first convert "admin_url" into calling the admin_url method, which returns some path like users/admin, and THAT string is useable by the redirect method.
You can use render "#{user.role}". Just be sure to have corresponding views with the names admin.html.erb' and so on.
I really like Andrew's answer, but you could also do something like
redirect_to send(user.role.to_s + '_url')
There are several things that you could do, but nothing built in and nothing that would be significantly simpler than send("#{user.role}_url"). Be sure to use send() - otherwise it will redirect to the URL "/admin_url" instead of calling the admin_url helper.
One such other solution would be to create an action called 'home' that would redirect to the current_user's role's page. That would add an extra redirect (slightly increase the page load time), but it would make your redirects simpler
redirect_to home_url
From the list view of my app, I can view a list of records or drill down and edit/update a record. After updating, I want to go directly back to the list view, bypassing a couple of intermediate pages - but I don't simply want to link_to(:action => list) - there's pagination involved. I want to go back to the exact 'list' page I came from. What's the best way? Pass a hidden arg somewhere with the page number? Is there an elegant way to accomplish this?
I'm just going to throw this one out there with the disclaimer that there may be security considerations or existing gems.
On your edit action, you could store the previous page in a session. Then in your update action, redirect to it.
class MyController < ApplicationController
def edit
session[:prev_url] = request.referer
end
def update
redirect_to session[:prev_url]
end
end
As an alternative to use the session, you could carry the referer through the actions using a hidden form field.
class MyController < ApplicationController
def edit
#prev_url = request.referer
end
def update
redirect_to params[:prev_url]
end
end
Form using hidden_field:
f.hidden_field :prev_url, :value => #prev_url
If you do not want to carry along the whole referer url you could also do the same with the page parameter instead and append the parameter to the url in the update action. I would also expect Rails' url helpers to accept parameters.