Keep form fields filled after an error (RoR)
Your View (new.html.erb) something like following
<%= error_message_for :user %>
<% form_for :user, :action=>"create" do|f|%>
<%= f.text_field :login %>
<% end %>
Controller Code (create method)
def create
@user=User.new(params[:user])
if @user.save
redirect_to :action=>'index'
else
render :action=>'new' #you should render to fill fields after error message
end
end
How does Rails keep the form data when validations fail?
Let's try to understand this whole process point-wise
Instance variables defined in the controller action are shared with the rendered views.
In your case I'm assuming that there's a new
action something like
def new
@movie = Movie.new
end
And you have a corresponding view new.html.erb
where you have created a form like this
= form_for @movie do |f|
Now, as you know the @movie
object that you are passing in form_for
method is defined in new
action. Most of the times we don't pass any parameters to the new
method in new
action. The form fields are blank when you load the form because the attributes of the object(in your case @movie
) are by default blank because we just initialize an empty object(Movie.new
).
Let's assume your Movie
model has a name
attribute, Try doing this in your new
action
def new
@movie = Movie.new(name: 'Hello World!')
end
Now when you will load the new action, you will see Hello World!
populated in your name
text field because your @movie
object is initialized with this value.
Also, keep in mind that Rails Convention-Over-Configuration automatically generates the form URL in this case, by default it points to the create
action. When you submit the form
the request is made to the create action. This takes me to the next point.
When we submit the form all the filled in form values are sent to the action whose route matches with the form URL(in your case URL points to the create
action)
In create
action you are receiving parameters in the form of a hash with model attributes(Movie
attributes) as keys and the filled in information as their values. The first line in your create
action is
@movie = Movie.new(movie_params)
This is a very important line of code, try to understand this. Let's assume your form had only one text field, i.e., name
. Now movie_params
is a method that looks like this
def movie_params
params.require(:movie).permit(:name)
end
Now, the movie_params
method will return a hash something like { 'name' => 'Hello World!' }
, now you are passing this hash as a parameter to Movie.new
method.
So now, after breaking up the code, the first line of your create action looks like
@movie = Movie.new({ name: 'Hello World!' })
That means your @movie
instance variable contains an object of Movie
class with name
attribute set to Hello World!
. Here, when after initialization, if you do @movie.name
it will return Hello World!
.
Now, in the second line you are calling @movie.save
that returned false
due to failed validation in your case as you have already mentioned in the question. As it returned false
the execution will go to the else
part. Now this takes me to the next point.
Calling render :action
(in your case render :new
) in the controller renders only the view that belongs to that action and does not execute that action code.
In your case, you called render :new
, so there you are actually rendering the new.html.erb
view in create action. In other words, you are just using the code in new.html.erb
and not in new
action. Here, render :new
does not actually invoke the new action, it's still in the create action but rendering the new.html.erb
view.
Now, in new.html.erb
you have created a form that looks like
= form_for @movie do |f|
Now as my explained under my first point, the instance variables that are declared in the action are shared by the rendered view, in this case @movie
object that you have defined in create
action is shared by the rendered new.html.erb
in create action. In our case, in create
action the @movie
object was initialized with some values that were received in the parameters(movie_params
), now when new.html.erb
is rendered in the else
, the same @movie
object is used in the form by default. You got the point right, you see the magic here?
This is how Rails works and that's why its awesome when we follow the convention! :)
https://gist.github.com/jcasimir/1210155
http://guides.rubyonrails.org/v4.2/layouts_and_rendering.html
Hope the above examples cleared your doubts, if not, feel free to drop your queries in the comment box below.
To maintain data in a form after doing a validation in rails
As soon as you put something into mensaje
the repond will do a redirect to thenew
action, which is why the form is empty. You have to clear out the controller, those validations do not belong there, I've only done some of that work for you.
def create
@farm = Farm.new(params[:farm])
if @farm.nombre == "" || !valid_prescence?(@farm.nombre)
flash[:notice] = "Favor de capturar los datos que se encuentran como requeridos"
else
@buscar = Farm.where(nombre: params[:farm][:nombre], tipo: params[:farm][:cliente_id])
if @buscar.any?
flash[:notice] = "La finca #{params[:farm][:nombre]} ya se encuentra registrada en el sistema, favor de verificar."
end
end
respond_to do |format|
if @farm.save
format.html { redirect_to @farm, notice: 'Finca creada correctamente.' }
format.json { render json: @farm, status: :created, location: @farm }
else
format.html { render action: "new" }
format.json { render json: @farm.errors, status: :unprocessable_entity }
end
end
end
Retain form fields after validation fail, render not working
You're right about this step:
format.html { render :template => "users/registrations/new" }
The problem is that you're not setting an instance for @user in the "after_step_controller", if you want to do the render, you should have to set an instance for @user, and it should contains the attributes that were submitted in the form, so you could show validations errors.
Hope it helps!
Ruby on Rails - Losing form values after failed validation on some fields
See how you have :value => '0'
in the form fields for both :publiclyfundedteaching
and :non_publicly_funded_teaching
(the third one you mentioned is not in your form).
They will set the value in the fields to 0 even if you reload a previously filled form. You can either remove that or try to add an if statment like so (assuming submission is the model):
<%= f.input :publiclyfundedteaching, label: "Publicly funded teaching (PFT)", input_html: { style: 'width:7%', id: "publiclyfundedteaching", value: @submission.publiclyfundedteaching || 0, onkeyup: "myFunction()" } %>
Keep data form after submit using sessions in rails
The problem has nothing to do with one that you gave a link to. You explicitly set the value of the user_type
parameter in the form, but you shouldn't.
Change
<%= f.input :user_type, as: :radio_buttons, collection: %w(personnal professional), checked: 'personnal' %>
To
<%= f.input :user_type, as: :radio_buttons, collection: %w(personnal professional) %>
The parameter is going to be set automatically, depending on resource
. When you submit the form, the parameter should stay as it was set.
If you want to set a default value, you can do it like this:
<%= f.input :user_type, as: :radio_buttons, collection: %w(personnal professional), checked: resource.user_type || 'personnal' %>
Not the best way, but the simplest.
howto : form with multiple models - re-render form after errors (fields populated)
Answer
If your form is directly bound with a model it's in most cases better to use the form helper form_for
.
To answer your question about repopulating the form and rendering errors. You should not redirect_back
, since this will result in the loss of current values. Instead render the same page again. This will allow the form to have access to the previous result, and fill the form with them. This happens automatically when using the form_for
helper (if you updated the attributes of your model instance).
In case you can't use the form_for
helper and use separate tags instead, don't forget to set the values. <%= text_field :object_name, :attribute_name, value: object.attribute %>
If the value is not set this will result in an empty text field, otherwise it will be filled with the attribute value.
There are some helpers that make form creating somewhat easier. For example Simple Form and Formtastic. But I would at least urge you to take a look at the Rails guide about forms first: Action View Form Helpers
Example
A good example, is the result of scaffolding an model. You end up with the following code in your controller:
class ChairsController < ApplicationController
# ...
def new
@chair = Chair.new
end
def create # I removed the json parts
@chair = Chair.new(chair_params)
if @chair.save
redirect_to @chair, notice: 'Chair was successfully'
else
render :new
end
end
# ...
end
With a chairs/new
view allong the line of:
<%= form_for @chair do |form| %>
<% if @chair.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(@chair.errors.count, "error") %> prohibited this chair from being saved:</h2>
<ul>
<% @chair.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= form.label :name %>
<%= form.text_field :name, id: :chair_name %>
</div>
<div class="actions">
<%= form.submit %>
</div>
<% end %>
Related Topics
Why Does Array.Slice Behave Differently for (Length, N)
Ruby 'Encode': "\Xc3" from Ascii-8Bit to Utf-8 (Encoding::Undefinedconversionerror)
Problems Installing Ruby on Mountain Lion - Ruby 1.9.3 Wont' Compile
Heroku and Rails: Gem Load Error with Postgres, However It Is Specified in Gemfile
How to "Soft Delete" User with Devise
Differencebetween Send_Data and Send_File in Ruby on Rails
Gem Install Pg Doesn't Work on Osx Lion
Determine Ruby Version from Within Rails
Forming Sanitary Shell Commands or System Calls in Ruby
How to Enable Cors in Rails 4 App
How to Convert a Ruby Hash to Xml
"Stack Level Too Deep" Running Rake Db:Create:All
Circular Dependency Detected While Autoloading Constant User
Rvm Is Not a Function, Selecting Rubies with 'Rvm Use ...' Will Not Work
"Which in Ruby": Checking If Program Exists in $Path from Ruby
How to Do a Safe Join Pathname in Ruby
Why Does Ruby Have Trueclass and Falseclass Instead of a Single Boolean Class