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
Related
I doubt that if between both commands there's a difference, when I want to create an action without a view in rails I've always used redirect_to with no return after it and I've never had any problems, but until I forgot to put the redirect_to I realized that rails recommend to do a redirect_to and return if I don't want to have a view for the action, then I wonder, is there any difference when adding the return?, at least in my case I have never noticed any difference or error.
redirect_to will cause any automatic rendering to be skipped.
You only need the 'return' if you need to bypass further code in the action. If the further code does an explicit render, then you must do a return to avoid an error of redirect and render both being present.
For example, a typical pattern in an update action might be...
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
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'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.
Just to clarify: I'm new to Ruby and Rails.
I've tryed to solve my problem with the sugestions in here, here and here, but they didn't seem to have direct relation with my problem, or I'm too dumb do understand.
I'm trying to test a scenario where I don't update an object and I want my app to redirect. I'm not sure if my controller code is right, I think I'm probably not covering this scenario. Here's my test code:
test "should not update status if nothing has changed" do
sign_in users(:rodrigo)
put :update, id: #status
assert_redirected_to status_path(assigns(:status))
assert_equal assigns(:status).user_id, users(:rodrigo).id
end
, and my controller update code:
def update
#status = current_user.statuses.find(params[:id])
#document = #status.document
if params[:status] && params[:status].has_key?(:user_id)
params[:status].delete(:user_id)
end
respond_to do |format|
if #status.update_attributes(params[:status]) &&
#document && #document.update_attributes(params[:status][:document_attributes])
format.html { redirect_to #status, notice: 'Status was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: "edit" }
format.json { render json: #status.errors, status: :unprocessable_entity }
end
end
end
I've already tried to verify if #status.changed?, and it really didn't. I'm without options here. If anyone want to help and need more information, I can provide it.
Facepalm for me...
I've mentioned in my question:
I've already tried to verify if #status.changed?, and it really didn't.
It did change when I put something different in one of the model attributes, but I've only asked .changed? after saving my #status model. I'm really sorry about it, I'm yet just figuring out how Ruby on Rais works.
That said, I've came up with a solution to my problem, that was just setting the only one attribute of my model (except the id, of course) with the value from the params[:status] hash. And BEFORE saving it, I ask if #status.changed?. If it doesn't, I redirect_to the unchanged #status, otherwise, I just save it and go through the old code.
Of course that doesn't cover all my scenario, since I also have to check if my #document model has changed, but this is not the scope of this question.
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.