In our rails application we have a page where upon submit we save data in db. On this page, we have some fields which are dynamically generated and I see that in case of a validation error when page reloads it doesn't populate these fields with the values present upon posting.
In controller we have the following method defined for populating it:
def build_my_registration_type_memberships
#memberships = []
ListCache.my_registration_types.each do |my_registration_type|
#memberships << MyRegistrationTypeMembership.find_or_initialize_by_my_id_and_my_registration_type_id( #my.id, my_registration_type.id )
end end
In above method when my registration is opened in edit/view mode, it shows the values using this #membership method. But on posting in case of error it doesn't reload this with correct information. So my question is how could I repopulate #membership in case of an error on posting?
Thanks for help.
As, I understand you want some values available to your new method or the page that is rendered after if the create fails.
I assume you must have have the respond_to block in your create method. And you're doing this:
def create
...
respond_to do |format|
if #patient.save
format.html { redirect_to #object, :notice => "Object was successfully saved." }
format.xml { render :xml => #object, :status => :created, :location => #object }
else
format.html { render :action => :new }
format.xml { render :xml => #patient.errors, :status => :unprocessable_entity }
end
end
end
As you can notice, in the else part the new action is just rendered. Using some template the view is just delivered. Now, you just have to do whatever you're doing in the new action to make those values available, in the else part.
def create
...
respond_to do |format|
if #patient.save
format.html { redirect_to #object, :notice => "Object was successfully saved." }
format.xml { render :xml => #object, :status => :created, :location => #object }
else
format.html {
#memberships = []
ListCache.my_registration_types.each do |my_registration_type|
#memberships << MyRegistrationTypeMembership.find_or_initialize_by_my_id_and_my_registration_type_id( #my.id, my_registration_type.id )
end
render :action => :new
}
format.xml { render :xml => #patient.errors, :status => :unprocessable_entity }
end
end
end
And, the values you wanted will be available in the rendered form.
Better, you move to that code to a before filter or something, which makes those values available to those two methods (new and create).
Related
What I'm trying to do is update a created item's attributes after it is created through the controller, like so:
def create
#check_out = CheckOut.new(params[:check_out])
#check_out.request_id = #request.id
#check_out.status = 'complete'
#check_out.date_taken = Time.now
etc.....
respond_to do |format|
if #check_out.save
format.html { redirect_to(#check_out, :notice => 'Check out was successfully created.') }
format.xml { render :xml => #check_out, :status => :created, :location => #check_out }
else
format.html { render :action => "new" }
format.xml { render :xml => #check_out.errors, :status => :unprocessable_entity }
end
end
end
The issue is that the item created, is created via a nested attribute. I've come to realize, through painful trial and error, that when nested items are created, it is not through their controller, but some other way. I need to figure out how this is done, so I can attempt to come up with a solution.
The good place to start http://api.rubyonrails.org/classes/ActiveRecord/NestedAttributes/ClassMethods.html#method-i-accepts_nested_attributes_for
I have a very basic app with 1 controller that has new and create methods and a form_for to create an entry in the database with the passed params.
When i hit submit the show view is rendered. Is there a way not to have the page redirect, so the view stays still the same with the form and a flash message get displayed at the top of the view?
I tried flash[:notice] and flash.now[:notice] but no luck.
this is my create controller
def create
#campaign = Campaign.new(params[:campaign])
respond_to do |format|
if #campaign.save
flash[:notice] = "Success"
# format.html { redirect_to(#campaign, :notice => 'Successfully created.') }
# format.xml { render :xml => #campaign, :status => :created, :location => #campaign }
else
format.html { render :action => "new" }
format.xml { render :xml => #campaign.errors, :status => :unprocessable_entity }
end
end
end
I am using ajax to change the displayed cart as the user add product to cart. To do so i call with :remote=>true the correct controller that send back the updated cart.
The controller method to do so is the following :
def create
#cart = current_cart
product = Product.find(params[:product_id])
#line_item = #cart.add_product(product.id)
respond_to do |format|
if #line_item.save
format.html { redirect_to(magasin_url) }
format.js {#current_item = #line_item }
format.xml { render :xml => #line_item, :status => :created, :location => #line_item }
else
format.html { render :action => "new" }
format.xml { render :xml => #line_item.errors, :status => :unprocessable_entity }
end
end
end
I'd like to be able to handle an empty stock by sending a notice message instead of updating the cart.
I tried this :
if product.stock_to_display <=0
respond_to do |format|
format.html { }
format.js {}
end
end
But i do not know what to put in the format. and i have no idea how to do a condition in the rjs :
page.replace_html('panier', render(#cart))
page[:panier].visual_effect :blind_down if #cart.total_items == 1
page[:current_item].visual_effect :highlight,
:startcolor => "#88ff88",
:endcolor => "#114411"
page.select("#notice").each {|notice| notice.hide}
So i'd like to know how to handle the error with ajax/rjs. Thanks
Ok after a little bit of try i managed to do something that seems clean.
I created a #success boolean in the controller and affected him a value, after that i can use the boolean in RJS to either do my stuff or display the notice.
Here is my new RJS.
if #success
page.replace_html('panier', render(#cart))
page[:panier].visual_effect :blind_down if #cart.total_items == 1
page[:current_item].visual_effect :highlight,
:startcolor => "#88ff88",
:endcolor => "#114411"
page.select("#notice").each {|notice| notice.hide}
else
page.replace_html :notice, flash[:notice]
flash.discard
end
If you have a javascript error with the display, check the application layout as it may be restricted by a "if notice" condition
I am just starting a rails 3 app that has a parent model and a child model (parent has_many :children).
I am trying to set things up so that after creating a new parent the user is taken to the show action of that parent (/parent/id). In this view I have included partials to show any children and a form to create a new child. After creating a new child the user is redirected to the show action for the parent where the new child will appear. This all works as intended.
However, if I try to validate fields in the new child form any error messages that occur are not appearing in the form (the necessary lines in the view are there and are correct - cut and pasted from generated scaffold code). Is there a way of passing these error messages for the child successfully to the parent show action?
Here are snippets of relevant code;
From my parent controller:
def show
#parent = Parent.find(params[:id])
#child = #parent.children.new
respond_to do |format|
format.html # show.html.erb
format.xml { render :xml => #admission }
end
end
From my child controller:
def create
#child = Child.new(params[:parent])
respond_to do |format|
if #child.save
format.html { redirect_to(parent_path(params[:child][:parent_id]), :notice => 'Child was successfully created.') }
#This works as intended
format.xml { render :xml => #child, :status => :created, :location => #child }
else
format.html { redirect_to parent_path(params[:child][:patient_id]) }
#This redirects where I want it to go when validation fails but error messages are lost
format.xml { render :xml => #child.errors, :status => :unprocessable_entity }
end
end
end
Alright, I solved this myself. Thanks for Terw's answer though. It works apart from giving the wrong URL because of the lack of redirect.
It was simply a matter of passing the errors via the session hash and then adding them to the child model in the parent controller.
I'm posting the code because I couldn't find any other examples of this out there. Perhaps there's a simpler way but this works perfectly so far. If anyone thinks I'm crazy then please explain.
In my child controller
def create
#parent = Parent.find(params[:child][:parent_id])
#child = #parent.child.build(params[:child])
respond_to do |format|
if #child.save
format.html { redirect_to(parent_path(params[:admission][:parent_id]), :notice => 'Child was successfully created.') }
format.xml { render :xml => #child, :status => :created, :location => #child }
else
if #child.errors.any?
session[:child_errors] = #child.errors
end
format.html { redirect_to(parent_path(params[:child][:parent_id])) }
format.xml { render :xml => #child.errors, :status => :unprocessable_entity }
end
end
end
And in my parent controller
def show
#parent = Parent.find(params[:id])
#child = #parent.children.new
if session[:child_errors]
session[:child_errors].each {|error, error_message| #child.errors.add error, error_message}
session.delete :child_errors
end
respond_to do |format|
format.html # show.html.erb
format.xml { render :xml => #parent }
end
end
What if you just render the parent's show page if the child is invalid?
def create
#child = Child.new(params[:parent])
respond_to do |format|
if #child.save
format.html { redirect_to(parent_path(params[:child][:parent_id]), :notice => 'Child was successfully created.') }
#This works as intended
format.xml { render :xml => #child, :status => :created, :location => #child }
else
format.html { render :controller => :parent, :action => :show }
# Display the parent's show page to display the errors
format.xml { render :xml => #child.errors, :status => :unprocessable_entity }
end
end
end
You might also want to do something like this for the crate action to make sure the parent exists.
#parent = Parent.find(params[:parent][:parent_id])
#child = #parent.children.build(params[:parent])
Then your users can't create an invalid child, and you have the parent to render the show page again. You shouldn't give the users the ability to set the parent_id them selfes.
Basically I am trying to capture the value of the form field before it is saved to the database. Then I intend to use that value in my controller to update a specific field in the database,
using
#taskforms.update_attribute('notes',
$notes)
I need to do this because I know of no other way to update that that does not require the full record to be validated.
The suggestion below to use #taskforms.save(false) is really not what I was looking for optimally. However it could work. However having and issue to get it to work.
What I am currently using (that works with validations)
def myupdate
#taskforms = Taskforms.find(params[:id])
respond_to do |format|
if #taskforms.update_attributes(params[:taskforms])
#taskforms.update_attribute('edited_at', Time.new )
flash[:notice] = 'Note was successfully updated.'
format.html { redirect_to(:controller => "taskforms", :action => "displayedit", :id => #taskforms.id) }
format.xml { head :ok }
else
format.html { render :action => "displayedit" }
format.xml { render :xml => #taskforms.errors, :status => :unprocessable_entity }
end
end
end
However when I try the save(false) it doesn't save and triggers validations anyway
def myupdate
#taskforms = Taskforms.find(params[:id])
if #taskforms.save(false)
#taskforms.update_attribute('edited_at', Time.new )
flash[:notice] = 'Note was successfully updated.'
format.html { redirect_to(:controller => "taskforms", :action => "displayedit", :id => #taskforms.id) }
format.xml { head :ok }
else
format.html { render :action => "displayedit" }
format.xml { render :xml => #taskforms.errors, :status => :unprocessable_entity }
end
end
I have never used Save in the past just the default respond_to do |format| so suspect my code is incorrect.
#taskforms.save(false) will save your model without any validations if that is your main goal.