问题
If form fails validation, fields for has_many association, disappears from view:
my new action looks like
def new
@realty = Realty.new
@realty.build_user
@realty.build_address
#user, address are has_one association, and they stay in view after failed validation
6.times { @realty.realty_images.build } # and this one vanishes away
respond_to do |format|
format.html # new.html.erb
format.json { render json: @realty }
end
end
if I add to my form this snippet
- if @realty.realty_images.empty?
- 6.times { @realty.realty_images.build }
fields are shown up again, but it is a little rough
I tried
6.times { @realty.realty_images.build } if @realty.realty_images.empty?
or
6.times { @realty.realty_images.build }
6.times { @realty.realty_images.build } if @realty.realty_images.empty?
in controller, but it doesn't works, and fields disappears again on failed validation.
create action:
def create
@realty = Realty.new(params[:realty])
respond_to do |format|
if @realty.save
format.html { redirect_to @realty, notice: 'Realty was successfully created.' }
format.json { render json: @realty, status: :created, location: @realty }
else
format.html { render action: "new" }
format.json { render json: @realty.errors, status: :unprocessable_entity }
end
end
end
my -form
= simple_form_for(@realty) do |f|
= f.error_notification
.form-inputs
= f.input :offer_type
= f.input :realty_type
= f.input :rent_type
= f.input :price
= f.input :description
= f.input :state, as: :hidden
= f.input :number_of_rooms
= f.input :floor
= f.input :service, as: :hidden
= f.simple_fields_for :address do |address_f|
= address_f.input :city, :required => true
= address_f.input :state, :required => true
= address_f.input :street, :required => true
- unless user_signed_in?
= f.simple_fields_for :user do |user_f|
= user_f.input :name, :autofocus => true, :required => true
= user_f.input :phone, :required => true
= user_f.input :email, :required => true
= user_f.input :password, :required => true
= user_f.input :password_confirmation, :required => true
- if @realty.realty_images.empty?
- 6.times { @realty.realty_images.build }
= f.simple_fields_for :realty_images do |image_f|
= image_f.input :image, as: :file
.form-actions
= f.button :submit
realty model
class Realty < ActiveRecord::Base
attr_accessible :description, :floor, :user_id, :number_of_rooms, :price, :service, :state, :realty_images_attributes, :address_attributes, :user_attributes, :offer_type, :realty_type, :rent_type
belongs_to :user, :dependent => :destroy, :class_name => "User"
has_many :realty_images, :dependent => :destroy
has_one :address, :dependent => :destroy
validates :offer_type, :presence => true, :length => { :in => 1..256 }
validates :realty_type, :presence => true, :length => { :in => 1..256 }
validates :state, :presence => true, :length => { :in => 1..256 }
validates :description, :length => { :maximum => 2000 }
validates :service, :presence => true, :length => { :in => 1..256 }
accepts_nested_attributes_for :realty_images
accepts_nested_attributes_for :user
accepts_nested_attributes_for :address
end
回答1:
I think you are confusing two actions: new and create. The "new" action is invoked only when accessing the blank form at /realties/new. And the "create" action is invoked when submitting the form.
You add 6 sample images only in "new" action. In create action, Realty.new
will discard images that are blank (not filled in). This is why you will see them disappear. You will need to re-add them on validation error. You could extract the common setup into a method:
class RealtiesController
def new
@realty = Realty.new
@realty.populate
end
def create
@realty = Realty.new(params[:realty])
if @realty.save
# ...
else
@realty.populate
render 'new'
end
end
end
class Realty
# you could also place it in the controller
# if you feel it fits better there
def populate
6.times{ self.realty_images.build }
end
end
回答2:
To keep the failed object still present in #new, you can just avoid creating a new one if old one existed. Like this:
@realty = || Realty.new
This way #new will use the old failed object instead of the new.
For @realty object, it will work. But for further associations such as user and address, I have not done similar things before so you need to verify it by yourself.
p.s The code relies on the instant variable that's why I'm concerned how the obj is saved. Hope this could be of a little help :)
回答3:
@Billy Chan Thank you for your advice, you really help me. My solution of this issue, is a little rough but it works well
in create action a add
6.times { @realty.realty_images.build } if @realty.realty_images.empty?
if @realty.save return false
it looks like this
def create
@realty = Realty.new(params[:realty])
@realty.user = current_user if user_signed_in?
respond_to do |format|
if @realty.save
format.html { redirect_to @realty, notice: 'Realty was successfully created.' }
format.json { render json: @realty, status: :created, location: @realty }
else
6.times { @realty.realty_images.build } if @realty.realty_images.empty?
format.html { render action: "new" }
format.json { render json: @realty.errors, status: :unprocessable_entity }
end
end
end
来源:https://stackoverflow.com/questions/16413271/nester-attributes-for-has-many-are-not-shown-if-the-form-fails-validation