I'm using responders gem in my Rails 4.2 application. I got a pretty complex situation, where in a Organization model edit view I got a form for a OrganizationUser with one input. Adding user to organization invokes a create action in a OrganizationUsersController. I am using responders there with redirect action, something like this:
def create
#organization_user = #organization.organization_users.create(organization_user_params)
respond_with #organization_user do |format|
format.html { redirect_to edit_organization_path(#organization) }
end
end
And my translations:
flash:
actions:
create:
notice: '%{resource_name} was successfully created.'
alert: '%{resource_name} could not be created.'
organization_users:
create:
notice: "Member has been added"
alert: "Validation error"
The problem is that everything works if a resource is valid and is persisted to database. I am redirected to edit organization view with a proper notice message, but if validation fails I am redirected without any alert.
I can of course set flash alert message unless #organization_user is persisted, but that's the whole point of using responders to set flashes automatically.
Ok I figured it out. It turned out that with validation errors flash was properly set, but it was flash.now instead of flash and after redirect_to flash was deleted. The solution is to use :flash_now => false like so:
respond_with(#organization_user, :flash_now => false) do |format|
format.html { redirect_to edit_organization_path(#organization) }
end
Try:
respond_with #organization_user do |format|
if #organization_user.valid?
format.html { redirect_to edit_organization_path(#organization) }
end
end
Note that for flashes in your config/locales/en.yml to work, you need responders :flash at the top of your controller.
Related
When there was an error on updating my model, I was rendering :edit, but this was stripping the /edit from my url because #update is the same as #show with a different request method. To solve this I tried following the advice given here, but this caused me to get an ActionDispatch::Cookies::CookieOverflow error when I try to submit an invalid form. How should I correctly re render the edit page, while keeping both the /edit url and the flash messages? Is it possible to check for validity and show the errors without making a call to update?
Original code:
def edit
end
def update
respond_to do |format|
format.html do
if #model.update(model_params)
redirect_to home_base_url_or_default(model_url(#model)), notice: "Successfully updated."
else
render :edit
end
end
end
end
Failing code:
def edit
if flash[:model]
#model = flash[:model]
end
end
def update
respond_to do |format|
format.html do
if #model.update(model_params)
redirect_to home_base_url_or_default(model_url(#model)), notice: "Successfully updated."
else
flash[:model] = #model
redirect_to :action => :edit
end
end
end
end
Rather than doing a redirect, in this case the problem was solved by doing a render, then controlling the view by setting an instance var in the controller saying if it is the edit page or not. Also by using the update class in the CSS. However, this still has the the url for the show page, but at least the layout is correct.
One way to do it would be to allow the edit action to accept the POST method as well. Use request.method to check whether it is a POST or GET, then perform your render or redirect accordingly.
I feel somewhat stupid about this one, but:
if #prof.update_attributes(params[:profile])
respond_to do |format|
format.html {redirect_to(#prof, :notice => "Profile successfully created.") }
end
end
...is in the update method of my controller. I have some attributes being validated in the model.
If validation fails, I just want them back on the same form to be scolded by various red text. (ie. everything in the errors array).
I'm getting a 'template missing' error when validation fails - the template for 'update'. I feel like I'm overlooking something extremely simple. Help!
Try this:
respond_to do |format|
if #prof.update_attributes(params[:profile])
format.html { redirect_to(#prof, :notice => "Profile successfully created.") }
else
format.html { render action: 'edit' }
end
end
The cause of the error is due to the fact that Rails, unless told otherwise, will attempt to render a template with the same name as the action, in this case update, which obviously doesn't exist.
What you want to do is tell rails to render the edit action again in the event of an error. Typically, you would do this with the respond_to block, allowing the block to respond differently depending on whether validation passed or failed.
At present, you have your if statement wrapping the block, and no statements telling rails to render differently in the event of an error. To fix this, I would do the following:
respond_to do |format|
if #prof.update_attributes(params[:profile])
# all is well, redirect as you already wrote
else
format.html { render action: 'edit' }
end
end
I have a website that degrades gracefully for users without javascript. For a user without javascript, the controller will respond to a form submit with HTML. For a user with javascript, there will be an AJAX form submit. This is in the create method in the controller:
if !#goal.save
flash[:error] = array_to_list(#goal.errors.full_messages)
else
flash[:success] = "Your goal was successfully added."
end
respond_to do |format|
format.html { redirect_to :action => "show"}
format.js
end
I don't want to put those messages into flash if the user has javascript enabled, because then it will display after the user has already dealt with it. Is there any way to tell Rails to display a flash message only if responding with html?
You can put the flash bits of the code into your format.html block in order to achieve this.
Maybe something like this:
#goal.save
respond_to do |format|
format.html do
if #goal.errors
flash[:error] = array_to_list(#goal.errors.full_messages)
else
flash[:notice] = "Your goal was successfully added."
end
redirect_to :action => "show"
end
format.js
end
Have you thought about that you might want to have some kind of error message with the AJAX request as well? It might be a good idea if your AJAX request breaks by some reason so that stuff doesn't get saved.
I would like to do a conditional update in ruby on rails 3.1
Where based on the location you came from, after update, an redirect will be done.
Splitted my 1 big form in to separate smaller ones, so now the Idea is to redirect to the correct subform.
For example the form can be submitted from:
profile basics form
Profile details form
The only thing I could come up with is checking the action name and use that to redirect. But its very ugly and long code and not fully working either. What would be the railsway of doing this?
This is my controller update action:
def update
#profile = Profile.find(params[:id])
respond_to do |format|
if #profile.update_attributes(params[:profile])
format.html { redirect_to #profile, notice: 'Profile was successfully updated.' }
else
format.html {
render :action => "edit_basics"
#
}
end
end
end
Why not just pass the redirect location as a hidden_field in the form, then have each form set it as needed:
redirect_to params[:redirect_location]
You could also do this using steps or something if you don't want to expose the raw string in your HTML:
redirect_to location_for_step(params[:step])
I currently have a login popup in my header bar which is on every page in my website. I want to be able to reload the current page that the person is on after a successful login. How do I do this in the controller?
def create
#declaring and defining user variable stuff
if user.save
#reload current page <--how do I do this?
end
end
Thanks
For my application, I use redirect_to :back and it does the trick. However, I doubt this might have an error in a non general use case(s) (user came from a special page?) but i haven't found it so far in my app.
If you're looking for a way to get the page to refresh (typically redirect_to :back) with an XHR request, you don't have to look for a way to change the response type - just tell the page to reload with inline JS.
format.js { render inline: "location.reload();" }
Like Elena mentions, this should go in a respond_to block, like so:
respond_to do |format|
format.js {render inline: "location.reload();" }
end
In Rails 5 redirect_to :back is improved by:
redirect_back(fallback_location: root_path)
Since Rails 5 (or maybe older versions), you have a request.referrer method. You simply redirect from controller to referrer and it opens the page where request came from.
redirect_to request.referrer, notice: "You're being redirected"
Archonic's answer above worked for me. However, in Rails 3, I had to place this in a respond_to block in order to avoid an 'ArgumentError (too few arguments)' error:
respond_to do |format|
format.js {render inline: "location.reload();" }
end
Rails 5 introduced alternative function:
redirect_back(fallback_location: root_path)
It redirect back whenever the HTTP_REFERER is known.
Otherwise it redirects to the fallback_location.
The redirect_to :back is deprecated in Rails 5.0 https://github.com/rails/rails/pull/22506 and removed since Rails 5.1
This syntax is what you want... works in Rails 6
respond_to do |format|
format.html { redirect_to request.referrer, notice: "User was successfully WHATEVER." }
end
Building on Archonic's and Elena's Answers, the reload function accepts a parameter to force the page to reload from the server aka forceGet, instead of from cache. A parameter can be set by the controller logic, like successful or failed login of a user, to trigger the desired behavior when it is sent to the page.
# force_get = controller_logic ? true : false
respond_to do |format|
format.js { render inline: "location.reload(#{force_get});" }
end
UPDATE:
the logic has been deprecated for the forceGet option. If you do want to reload from the server you can use this logic:
# force_get = controller_logic ? true : false
respond_to do |format|
format.js { render inline: force_get ? "window.location.href = window.location.href;" : "location.reload();" }
end
just redirect to whatever url you want in the function:
redirect_to what_ever_path