[英]rails validate nested attributes
Artists have many Events. 艺术家有很多活动。 Events have many Artists.
活动有很多艺术家。 The join between these two models is called Performances.
这两个模型之间的连接称为性能。
Currently the Event form creates the Performance but creates a new artist for each Artist added to the Event form. 目前,“事件”表单会创建“演奏组”,但会为添加到“事件”表单的每个艺术家创建新的艺
I would like the Event form to: 我希望活动表格能够:
I've tried adding 'validates_uniqueness_of :name' to artist.rb but this prevents the event from being saved. 我已经尝试将“validates_uniqueness_of:name”添加到artist.rb,但这可以防止事件被保存。 The join (performance) should be created if it does not already exist and the artist should be created if it does not already exist, but the existence of the artist should not prevent the join/association from being created.
如果连接(性能)尚不存在,则应创建连接(性能),如果尚未存在,则应创建艺术家,但艺术家的存在不应阻止创建连接/关联。
event.rb event.rb
validates_presence_of :name, :location
has_many :performances, :dependent => :destroy
has_many :artists, :through => :performances
accepts_nested_attributes_for :artists, :reject_if => proc {|a| a['name'].blank?}, :allow_destroy => true
artist.rb artist.rb
has_many :performances
has_many :events, :through => :performances
perfomance.rb perfomance.rb
belongs_to :artist
belongs_to :event
events_controller.rb events_controller.rb
def create
@event = Event.new(params[:event])
respond_to do |format|
if @event.save
flash[:notice] = 'Event was successfully created.'
format.html { redirect_to(admin_events_url) }
format.xml { render :xml => @event, :status => :created, :location => @event }
else
format.html { render :action => "new" }
format.xml { render :xml => @event.errors, :status => :unprocessable_entity }
end
end
end
_form.html.erb _form.html.erb
<% form_for([:admin,@event]) do |f| %>
<p>
<%= f.label :name %><br />
<%= f.text_field :name %>
</p>
<p>
<%= f.label :location %><br/>
<%= f.text_field :location %>
</p>
<p>
<%= f.label :date %><br />
<%= f.date_select :date %>
</p>
<p>
<%= f.label :description %><br />
<%= f.text_area :description %>
</p>
<% f.fields_for :artists do |builder| %>
<%= render 'artist_fields', :f => builder %>
<% end %>
<p><%= link_to_add_fields "Add Artist", f, :artists %></p>
<p>
<%= f.submit 'Submit' %> <%= link_to 'Cancel', admin_events_path %>
</p>
<% end %>
artist_fields.html.erb artist_fields.html.erb
<p class="fields">
<%= f.label :name, "Artist"%><br/>
<%= f.text_field :name %>
<%= link_to_remove_fields "remove", f %>
</p>
You have the proc to reject artist attributes if the name is blank: you could also reject it if the artist already exists on the model, but that doesn't solve the problem of duplicate Artists. 如果名称为空白,您可以使用proc来拒绝艺术家属性:如果艺术家已经存在于模型中,您也可以拒绝它,但这并不能解决重复艺术家的问题。 Essentially you want to do a find_or_create_by_name when adding them to your event.
基本上,您希望在将事件添加到事件时执行find_or_create_by_name。
I think in your case it would be better to define your own artist_attributes=
method instead of relying on accepts_nested. 我认为在你的情况下,最好定义自己的
artist_attributes=
方法而不是依赖accepts_nested。 This way you can do your lookup for each artist name and add it only as needed: 这样,您可以查找每个艺术家名称并仅根据需要添加它:
def artist_attributes=(params)
if existing_artist = Artist.find_by_name(params[:name])
self.artists << existing_artist unless self.artists.include? existing_artist
else
self.build_artist(params)
end
end
You should really take a look at these Railscasts: 你应该看看这些Railscasts:
Don't create various artists. 不要创造各种艺术家。 Just use the existing one (or create if needed):
只需使用现有的(或创建,如果需要):
http://railscasts.com/episodes/167-more-on-virtual-attributes http://railscasts.com/episodes/167-more-on-virtual-attributes
You can also check these nested form railscasts (part one linked here): 您还可以检查这些嵌套表单railscast(这里链接的第一部分):
http://railscasts.com/episodes/196-nested-model-form-part-1 http://railscasts.com/episodes/196-nested-model-form-part-1
For the validation, you can just have a method do the just-once-in-the-event validation for you. 对于验证,您可以让方法为您进行一次性事件验证。 Something like (at Event.rb):
像(在Event.rb)的东西:
validate :artists_appear_just_once private def artists_appear_just_once self.artists.size == self.artists.uniq.size end
Alternatively you can make the artsits appear just once by default using the uniq! 或者,您可以使用uniq默认显示artsits一次! method before saving.
保存前的方法。 Just call a before_save hook and process the artists array...
只需调用before_save钩子并处理艺术家数组......
before_save :make_artists_unique
private
def make_artists_unique
artists.uniq!
end
Hope I got what you need right :P 希望我得到你需要的东西:P
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.