Passing flash hash from one controller to another controller - ruby-on-rails

I have a create method in one controller and at the end of this controller I want redirect_to another controller/view. How will I be able to display a flash[:notice] after the first controller is done and the next redirect_to view is rendered?
Here's the code in the first controller:
if #list.save
redirect_to root_path, :notice => "Created!"
I also noticed that it doesn't work here either:
if #list.save
redirect_to root_path, :alert => "Created!"
Here's the routes file:
root :to => 'sessions#new'

To persist a flash message over an additional request you can use flash.keep - from the flash section on Rails Guides:
Let's say this action corresponds to root_url, but you want all
requests here to be redirected to UsersController#index. If an action
sets the flash and redirects here, the values would normally be lost
when another redirect happens, but you can use 'keep' to make it
persist for another request.
Clarification: This solution only applies if you're losing the flash due to a double redirect.

Have you tried this?
redirect_to(whatever_path, :notice=>"hello world")
Also, you can use :error
redirect_to(whatever_path, :error=>"hello error")

What version of Rails are you on? The syntax you are using is a relatively new feature. Try doing it the long way:
flash[:notice] = 'Created'
redirect_to root_path

Related

On create error, should I render `new` or redirect to `new`?

Suppose I have something like this:
def new
#user = User.new
end
def create
#user = User.create(params[:user])
if #user.save
flash[:notice] = 'User created'
redirect_to :action => 'list'
else
flash[:error] = 'Some error here!'
render 'new'
end
end
I think the code is clear.
The problem here is, when the #user object is not saved successfully, should I render new (as above) or should redirect to new?
I know if redirect to new the data input by the user is lost, but if I render new, the URL will be /users/create instead of /users/new (which is ugly!).
You are correct in not using redirect. Redirect is loading an entirely new resource.
render however will keep your session data fresh, and depending on how your form is set up, should repopulate whatever data was inputted.
You mention:
I know if redirect to new the data input by the user is lost, but if I render new, the URL will be /users/create instead of /users/new (which is ugly!).
No, this is not true. If you say render 'new', it will go to the url users/new not create. Create as an action only handles POST requests to your controller, and generally never has a view associated with it. It will instead refer to the new action to handle any errors and displaying of forms.
The create action has this in common with the update action which does the same thing by handling only PUT requests, but refers to the edit action to handle the displaying of views.

Create action redirects to the wrong page?

When I check to see if my error message is working correctly, I notice my redirect goes to /businesses instead of /businesses/new after it POST (create action). I am using the regular RESTFUL routes but I need it to go back to /businesses/new on POST when their is an error. How can I do this?
This is my current code:
def create
#business = Business.new(params[:business])
if #business.save
redirect_to :back, :notice => "You have successfully added a new business."
else
render :action => 'new', :notice => "Please try again."
end
end
You should not redirect if the validation is failed. Here is what i should do to stay on the same page.
def create
#business = Business.new(params[:business])
if #business.save
redirect_to businesses_path
else
render :new
end
end
It is actually not a redirection. If you chech the html code generated for your form, you will see something like this:
<form accept-charset="UTF-8" action="/business"
class="new_business" id="new_business" method="post">
This means that the requested page to load is not the "/business/create" but the "/business". That is why you see it in the browser's address bar. This has nothing to do with your redirection in the create action. There you just render the previous form. This is not an error, it is actually working, maybe a little confusing, but that is not much of a problem, I think. With some javascript you can correct it if really needed.

Are redirect_to and render exchangeable?

For the code below, what happens if replacing redirect_to with render or vise verse?
def create
#product = Product.new(params[:product])
respond_to do |format|
if #product.save
format.html { redirect_to(#product, :notice => 'Product was successfully created.') }
else
format.html { render :action => "new" }
end
end
end
It seems OK replacing one with the other in code above. Is there a place where only redirect_to or render has to be used? Render does nothing but rendering a view. Redirect_to sends 302 request to server and current parameters are lost after redirecting.
Thanks.
If you're using render, when the user refreshes the page, it will submit the previous POST request again. This may cause undesired results like duplicate purchase and others.
But if you're using redirect_to, when the user refreshes the page, it will just request that same page again. This is also known as the Post/Redirect/Get (PRG) pattern.
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 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.
For more in depth explanation about render and redirect, you should read this article.
When you redirect you will generate a new request that hits a controller method, render just renders the associated view. You use render in the create because you want to keep the state of the model object if the save fails so that you can render info about its errors. If you tried to redirect to the new_product path you would create a new model object and loose all the form data the user entered and any errors etc etc
EDIT (with some more info):
An example of a situation where you MUST use redirect_to is if your view template uses instance variables that are not initialized in the controller method you are redirecting from. So you probably could not call render {:action => 'index'} in your create method because the index template probably makes use of a #products variable but your only initialized #product so it would cause an exception
Here is a complete list of what the two methods do that I follow:
1) redirect_to will issue an HTTP 302 status code by default. A 302 redirect is a temporary change and redirects users and search engines to the desired page for a limited amount of time until it is removed. You can optionally specifiy a 301 status code to redirect_to. A 301 status code is used when any page has been permanently moved to another location. Users will now see the new page as it has replaced the old page. This will change the URL of the page when it shows in search engine results.
2) redirect_to will issue a new HTTP request, since it is redirects to a different controller action or URL. You should not make the browser need to make a fresh call unless you really have to, so always question when you are using redirect_to and if it is the right thing, or perhaps a render would be better.
- redirect_to will cause any automatic template rendering of the current action to be skipped.
3) render will issue an HTTP 200 status code by default ( but with an invalid ActiveRecord object, you may want to change this to 422 unprocessable entity). The HTTP 200 OK success status response code indicates that the request has succeeded. The 422 (Unprocessable Entity) status code means the server understands the content type of the request entity nd the syntax of the request entity is correct but was unable to process the contained instructions.
4) render will render a template and any instance variables defined in the controller action will be available in the template. Of course, instance variables will not be available if the subsequent action that redirect_to invokes. IMPORTANT POINT: Redirect hits the controller while Render does not, so if you render a different template, it will not hit the action associated with that template and so those instance variables will not be available!
5) With render, use flash.now, instead of the normal flash.
flash.now[:error] = "There was a problem"
# not
flash[:error] = "There was a problem"
6) If you don't, then the flash message may not show up on the page that's rendered, and it will show up on the next page that's visited.
7) render will not cause the current action to stop executing! redirect_to will not cause the current action to stop executing! You need to invoke 'return' if you need to bypass further execution of code in the action! In the below code, there is an explicit render at the bottom and so you must do a return to avoid an error of redirect and render both being present:
def update
#record = Record.new(record_params)
if #record.save
flash[:success] = "record was successfully saved"
redirect_to records_path
return
end
flash.now[:error] = "please fix the problems in the record"
render :edit
end
Another option:
def update
#record = Record.new(record_params)
if #record.save
flash[:success] = "record was successfully saved"
redirect_to records_path
else
flash.now[:error] = "please fix the problems in the record"
render :edit
end
end
8) The flash message provides a way to pass temporary primitive-types (String, Array, Hash) between actions. Anything you place in the flash will be exposed to the very next action and then cleared out. This is a great way of doing notices and alerts:
class PostsController < ActionController::Base
def create
# save post
flash[:notice] = "Post successfully created"
redirect_to #post
end
def show
# doesn't need to assign the flash notice to the template, that's done automatically
end
end
show.html.erb
<% if flash[:notice] %>
<div class="notice"><%= flash[:notice] %></div>
<% end %>
Since you can have both notices and alerts in the flash, you can display both notices and alerts this way:
<% flash.each do |key, value| %>
<%= content_tag :div, value, class: "flash #{key}" %>
<% end %>

Flash notice with redirect_to is broken in rails

I updated to Rails 2.3.10, Rack 1.2.1 and now none of my flash messages are showing up. I found that during a redirect the notice is passed in like this
redirect_to(#user, :notice => "Sorry there was an error")
And in my view the flash hash is empty
<%= debug flash %>
!map:ActionController::Flash::FlashHash {}
But you can see the message in the controller. What gives?
<%= debug controller.session %>
session{:home_zip=>"94108", :session_id=>"xxx", :flash=>{:notice=>"Sorry there was an error"}, :user_credentials=>"1baf9c9c0423ce0151ec32e24cc422f07309e4ba503eb4830635ecc115da217809997324374bb273b3fb792895c9741a8b8c9ea4267771a1bd149de5b9179ea0", :user_credentials_id=>22, :home_market_id=>11}
Edit Profile
Did you check the rails bug tracker? I still use the old fashioned setter flash[:notice] = message and it works fine, so it seems to be a redirect_to method problem.
https://rails.lighthouseapp.com/
Did you try redirect_to url, :flash => { :notice => "notice" }, as a work around?
The code below should work:
redirect_to(#user, {:notice => "Sorry there was an error"})
I'm guessing this is due to changes in Ruby and not in Rails, because it looks like a token parsing priority change in the compiler.
We just ran into this too. All our flash messages disappear with redirect, but not when set in the controller explicitly.
Does not work:
def create
if #obj.save
flash[:notice] = "The #{cname.humanize.downcase} has been created."
redirect_back_or_default redirect_url
else
render :action => 'new'
end
end
This does work:
def show
#user = current_user
flash[:notice] = "Hello -- this will show up fine"
end
This could be an issue with cookies. Long story short, cookies don't get if you redirect immediately afterwards. Assuming that Rails implements flash using cookies, the redirect is your problem.
Sources:
http://persistall.com/archive/2008/01/25/cookies--redirects--nightmares.aspx
http://stackoverflow.com/questions/1621499/why-cant-i-set-a-cookie-and-redirect

ruby on rails redirect_to(:back) not working

Following some code in Agile Web Development book, theres a method to redirect back to the last viewed page using redirect_to(:back), however when I do that it simply returns back to the page it was on.
Whats the best way of getting the desired result to work? Am I doing something wrong? My code:
def update
#user = current_user
if #user.update_attributes(params[:user])
flash[:notice] = "Successfully updated profile."
redirect_to(:back)
else
render :action => 'edit'
end
end
I think it's behaving as intended:
:back - Back to the page that issued the request. Useful for forms that are triggered from multiple places.
Isn't that what it is supposed to do?
You are probably on you edit page when you click some sort of "submit" button to update the user attributes. Once this update is done, :back will take you back to the edit page (this is the last viewed page). Isnt that what you want?
If you want to go to the users page the you could do something like this
redirect_to user_path(#user)

Resources