Reputation: 2703
I'm working with validations in rails, stuff like:
validates_presence_of :some_field
I've noticed that if the validation fails, all changes are overwritten with existing values from the database. This makes some sense, as the page is basically being reloaded (as I gather from my development log), however this increases the risk of user error/frustration, as a single error in one field will require the hapless fellow to re-enter the changes he made to all fields.
My question: How can I get rails to reload the data that was just submitted if validation fails? That way, the user can correct the mistake without needing to re-enter the rest of his revisions.
Thanks for any advice.
Edit: My update method, as requested, is as follows:
def update
@incorporation = Incorporation.find(params[:id])
@company = @incorporation.company
begin
@company.name="#{params[:company][:names_attributes].values.first["name_string"]} #{params[:company][:names_attributes].values.first["suffix"]}"
rescue NoMethodError
@company.name="Company #{@company.id} (Untitled)"
end
if @company.update(company_params)
redirect_to incorporations_index_path
else
redirect_to edit_incorporation_path(@incorporation)
end
end
Full disclosure regarding my controller: the above update
is from my incorporations_controller
even though I'm updating my Company
model. Company has_one :incorporation
. I did this because, in the larger context of my app, it made my associations much cleaner.
Upvotes: 3
Views: 1746
Reputation: 76784
To add to the correct answer, you can clean up your code quite a bit:
def update
@incorporation = Incorporation.find params[:id]
respond_to do |format|
if @incorporation.update company_params
format.html { redirect_to({:action => "index"})}
else
format.html { render :edit }
format.json { render json: @incorporation.errors, status: :unprocessable_entity }
end
end
end
If you're using accepts_nested_attributes_for
, you definitely should not hack the associated objects on the front-end.
You should look up fat model, skinny controller
(let the model do the work):
#app/models/company.rb
class Company < ActiveRecord::Base
before_update :set_name
attr_accessor :name_string, :name_suffix
private
def set_name
if name_string && name_suffix
self[:name] = "#{name_string} #{name_suffix}"
else
self[:name] = "Company #{id} (Untitled)"
end
end
end
This will allow you to populate the name
of the `company. To edit your nested/associated objects directly is an antipattern; a hack which will later come back to haunt you.
The key from the answer is: render :edit
Rendering the edit view means that your current @company
/ @incorporation
data is maintained.
Redirecting will invoke a new instance of the controller
, overriding the @incorporation
, hence what you see on your front-end.
Upvotes: 1
Reputation: 574
Update your controller to this
def update
@incorporation = Incorporation.find(params[:id])
@company = @incorporation.company
begin
@company.name="#{params[:company][:names_attributes].values.first["name_string"]} #{params[:company][:names_attributes].values.first["suffix"]}"
rescue NoMethodError
@company.name="Company #{@company.id} (Untitled)"
end
respond_to do |format|
if @company.update(company_params)
format.html { redirect_to({:action => "index"})}
else
format.html{render :edit}
format.json { render json: @incorporation.errors, status: :unprocessable_entity }
end
end
end
Upvotes: 2