Repopulating page with previous values in rails - ruby-on-rails

I have a validation that needs to be done in controller. If it fails I need to go back to the view action back again with all values populated as it is on the page.
Is there a simple way to do that (using incoming params map).

This is the basic way all Rails controllers and scaffolds work. Perhaps you should try generating scaffolds?
def create
#banner_ad = BannerAd.new(params[:banner_ad])
if #banner_ad.save
flash[:notice] = 'BannerAd was successfully created.'
redirect_to :action => "show", :id => #banner_ad
else
render :action => "new"
end
end
end
I populate a #banner_ad here, attempt to save it, if it fails, I return to the form and the #banner_ad object is available to me. I then need to have a form that uses the Rails form helpers to populate the values from the object.

Depends on the flow of your app, really.
If the validation fails, you could pull the data out fo the database ...
if invalid?
#model = model.find(:id
end
Otherwise you might need to store the original values in hidden fields in the view and use those.

Related

Difference between new and create (or edit and update) Rails

I know that this question has been asked many times on StackOverflow, but i have a more specific question:
I know that new is used to create a form and it doesn't save nothing on db.
Instead, the create action saves and validates data on db.
Let's see these:
def new
#country = Country.new
end
def create
#country = Country.new(params[:country])
respond_to do |format|
if #country.save
format.html { redirect_to countries_index_path, notice: 'Provincia Creata.' }
format.json { render :json => countries_index_path, :status => :created, :location => #country }
else
format.html { render :action => "new" }
format.json { render :json => #country.errors, :status => :unprocessable_entity }
end
end
end
I want to know , why the framework doesn't permit to use a single variable , passed from new to create to handle the creation of a resource?
I mean , in new and create we create every time two different variable, Country.new: we use one to create the form , and the other to pass the data of the form Country.new(params[:country]).
Or better , why we can't collide the two action new and create to one action? (for the Restfull theory we can't I think). It should seems a stupid question but i want to have clear this concept in my mind.
Thank you.
These two actions do two completely different things - the one action renders something and never writes s.th. to the DB while the other ones main purpose is not to render s.th. but to write s.th. to the DB.
Of course you can write a whole application with just one single action. But you would end up which a huge cascade of ifs. So you use routing to clear up that mess, and separate what does not belong together.
And the one action is idempotent while the other one is not - which is mirrored by one being a GET and the other one being a POSTrequest.
why the framework doesn't permit to use a single variable , passed from new to create to handle the creation of a resource
Well, many reasons. One is that those variables are not identical. This creates a blank country to render an empty form:
#country = Country.new
While this one is part one of two-step process (new+save). It creates country object from submitted data.
#country = Country.new(params[:country])
Or better , why we can't collide the two action new and create to one action?
It's possible to implement such action. Tell me, how would you then differentiate between "I want to render a blank form, not saving anything" and "I want to save an empty object, taking all default values"? Not to mention, you would now have to branch in the view, separating two distinct logical states ("new form" and "page for object that has just been created")
The new and create are very much different in their implementation
The action new is used to render an empty form.Thus new uses an HTTP GET,because GET request isn't supposed to modify any data. new only creates the local object but does not attempt to validate or save it to the DB.
But in case of create since our aim is to create new data we are using an HTTP POST to the create controller. create instantiates the new object, validates it, and then saves it to the database.

Missing template error after adding custom validation, template exsists and works without validation

This one is a bit challenging so bear with me. Here is the summary. I added a custom validation to one of my models. After I added this everything works fine with all actions except the update action. If I restrict the new validator to only the create action, then the update action works fine. Below is the related code:
In my model
validate :start_must_be_before_end_time
def start_must_be_before_end_time
return if customer_start.blank? || customer_end.blank?
if customer_start > customer_end
errors.add(:customer_start, "start time must be before end time")
end
end
In my controller for the update action:
def update
#handover = Handover.find(params[:id])
if #handover.update_attributes(params[:handover])
UpdatedHandover.perform_async(#handover.id)
flash[:success] = "Handover Template Updated and Approvals Sent!"
redirect_to view_context.select_handover_cal(current_user)
else
flash[:error] = "Please correct the following errors in your form!"
render edit_handover_path(#handover.id)
end
end
So if the start time is before the end time in the create action, everything works fine. It renders the new action and displays the error. If this happens in the update action it gives me a missing template error for the edit action. The edit file is in the proper place and this works if the validator is restricted to the create action. I cannot figure out for the life of me why this is giving me so much trouble. This is rails 3.2.18. Thanks for your help!
You should pass template name to render method, not a path. So if you want to render 'edit.html.erb', pass 'edit'.
Change
render edit_handover_path(#handover.id)
to
render 'edit'
Note that if you used extra instance variables in edit template, you would need to set them in update action.
For better understanding of render:
When you use render, you pass the instantiated object (newly created or updated). When attempting to update the object, validation was triggered and, if somehow unsuccessful, you render edit, since your in memory object contains necessary validation errors.
But edit_something_path is used when you use redirect_to. When you have the object saved and you can get the persisted data from the database.
You problem can be solved in two ways:
render 'edit'
render :edit
# Your validation errors will persist
or
redirect_to edit_handover_path(#handover.id)
# Your validation errors will be gone

Rails - how to pass created record from the new form to a redirected page

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 %>

Rails - When calling NEW, create a record before displaying a form?

Here's what I'm trying to do.
when the user clicks new note.. I want the user to be taken to a page when they can start typing a note, and save it to the server all with AJAX..
Problem is, every time the page saves, it's making a new note.
This leads me to believe that when Rails gets the DEF NEW controller, some how I need rails to first make a NEW NOTE record and then redirect to the edit controller of that new note, where the user can create/edit the note all with AJAX.
Thoughts? Thanks.
I had the same problem once, creating the note first is probably a good idea.
Another way would be to send the user to the new action. When the first save occurs you send the new object back as a JSON object, and replace the form's action with the update url for that record as well as setting the form's method to put.
This way you don't end up with empty records in the database (with your use-case, you might want exactly that, so a User can continue a note later.)
Just my two cents.
Ok a way of implementing this could look like this:
Form
<%= form_for resource,
:remote => true,
:html => { 'id' => 'autosave' },
:url => resources_path(:format => :json) do |f| %>
...
<% end %>
Application JS
var $form = $('#autosave');
// bind to the first success event from the form
$form.one('ajax:success', function(data, status, xhr) {
// data contains our json object (your note as json)
// now we update the form
$form.attr('action', '/notes/' + data.id);
$form.attr('method', 'put');
$form.attr('data-method', 'put');
});
Controller
class ExampleController
...
def create
#
# respond with the json object if format = json,
# see the form above I'm passing the format with :url parameter in form_for
#
respond_with(resource) do |format|
format.json { render :json => resource }
end
end
end
If you really want use to use #new to create a note and save it, then you can simply do
def new
#note = Note.create # instead of Note.new
end
Rails will then display this note just like the #edit action, so the note id will be in a hidden field. Then when you send the Ajax calls, you'll be calling #edit. If you want to preserve the behavior of #new for when javascript is turned off, then you might want to create a different action.
def new
#note = Note.new
end
def new_js
#note = Note.create
end
When you load the page that has the link to new_note, include some javascript that changes the link to new_js_note. So when JS is off, you get the standard #new form. When JS is on, you get a form that is basically editing a preexisting blank note.

What is causing this redirect_to to fail?

I am trying to use this redirect_to
redirect_to :controller => :note_categories, :action => :destroy, :note_id => params[:id]
This is the URL that results
http://localhost:3000/note_categories/272?note_id=272
and this is the error message
Unknown action
No action responded to show. Actions: destroy
The reason I am redirecting to the note_categories destroy action, and passing in the note id, is that in the destroy action, I am finding all the note_categories related to note, running some code on them, then destroying them. I know this isn't a great way to be doing this, but I couldn't use :dependant => :destroy because the code I have to run on the note_category before I delete it needs access to current_user, which can't happen in the note_category model.
So yeah, can someone please tell me what am I doing wrong in my redirect_to? Thanks for reading.
The redirect_to method is essentially the Rails implementation of the Post/Redirect/Get (PRG) web design pattern. It's used to prevent duplicate form submissions caused by the user clicking the browser's Refresh button after submitting a form.
The typical Rails usage is like this for creating an object:
A form for creating an object is displayed (new action/HTTP GET)
The user fills in the form
The form is submitted (create action/HTTP POST)
The object is created and saved
A redirect_to is performed with an HTTP 301/302 status to the object's show view or perhaps index
—for editing an object it's:
A form for edit an existing object is displayed (edit action/HTTP GET)
The user fills in the form
The form is submitted (update action/HTTP PUT)
The object is updated and saved
A redirect_to is performed with an HTTP 301/302 status to the object's show view or perhaps index
You can't redirect directly to the destroy action because in RESTful Rails that's intended to be invoked as a result of an HTTP DELETE request and doesn't render a template when it's invoked. The redirect_to method always redirects to a template.
You haven't shown us the code for destroying notes, but I suspect that what you're trying to achieve can be done with a before filter and by having the controller passing the current user to a model method.

Resources