2010-06-19 3 views
3

У художников много событий. События имеют много художников. Соединение между этими двумя моделями называется Performances.рельсы проверяют вложенные атрибуты

В настоящее время форма Event создает Performance, но создает нового исполнителя для каждого Artist, добавленного в форму Event.

Я хотел бы форму событий на:

  1. Validate, что артист может быть добавлен только к событию, когда
  2. Если артист с таким же именем уже существует в таблице художников, создать ассоциацию в соединительной таблице (выступления), но не создаю другой художник
  3. Если артист с таким именем еще не существует, создайте его и производительность

Я пытался добавить ing 'validates_uniqueness_of: name' to artist.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

has_many :performances 
has_many :events, :through => :performances 

perfomance.rb

belongs_to :artist 
belongs_to :event 

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

<p class="fields"> 
<%= f.label :name, "Artist"%><br/> 
<%= f.text_field :name %> 
<%= link_to_remove_fields "remove", f %> 
</p> 

ответ

1

У вас есть процедурный отклонять художник атрибуты, если имя пустое: вы также можете отклонить его, если художник уже существует на модели, но это не решает проблему дублирующих художников. По сути, вы хотите сделать find_or_create_by_name при добавлении их в свое событие.

Я думаю, что в вашем случае было бы лучше определить ваш собственный метод artist_attributes= вместо того, чтобы полагаться на accepts_nested. Таким образом, вы можете сделать ваш поиск для каждого имени исполнителя и добавить его только по мере необходимости:

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 
+0

Я исследовал то, что вы предложили, но не можете понять, как Начало. – shalako

+0

Поэтому мне нужно добавить настраиваемый метод в модель событий и каким-то образом включить find_or_create_by_name. Мне нужно удалить accepts_nested_attributes_for? Нужно ли использовать виртуальные атрибуты, как предлагает Райан Бэйтс в Railscasts # 102? Before_save, after_save? Я не нашел хорошего примера того, как эти вещи сочетаются друг с другом. – shalako

+0

Я добавил пример метода artist_attributes = выше. Я думаю, вам все равно нужно accepts_nested, если вы хотите использовать «f.fields_for: artist» –

1

Вы должны действительно взглянуть на эти Railscasts:

  1. Не создавать различные художники.Просто используйте существующую (или создать при необходимости):

    http://railscasts.com/episodes/167-more-on-virtual-attributes

  2. Вы также можете проверить эти вложенные формы Railscasts (часть одна связана здесь):

    http://railscasts.com/episodes/196-nested-model-form-part-1

  3. Для проверки достоверности , вы можете просто использовать метод для проверки только один раз в месяц. Нечто подобное (в Event.rb):

    validate :artists_appear_just_once 
    
    private 
    def artists_appear_just_once 
        self.artists.size == self.artists.uniq.size 
    end 
    

В качестве альтернативы вы можете сделать художников появляются только один раз по умолчанию с помощью Uniq! перед сохранением. Просто вызвать before_save крючок и обработать массив художников ...

before_save :make_artists_unique 

private 
def make_artists_unique 
    artists.uniq! 
end 

Надеются, что я получил то, что вам нужно правильно: P

Смежные вопросы