views:

141

answers:

2

An event has many artists, and an artist has many events. The join model for an artist and an event is a performance. I want to add artists to an event.

This works except that I'm getting duplicate entries into my join table when creating a new event. This causes problems elsewhere.

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?}
# accepts_nested_attributes_for :performances, :reject_if => proc { |a| a['artist_id'].blank? }

artist.rb

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

has_attached_file :photo, :styles => { :small => "150x150>"  },
              :url  => "/images/artists/:id/:style/:basename.:extension",
              :path => ":rails_root/public/images/artists/:id/:style/:basename.:extension"

# validates_attachment_presence :photo
validates_attachment_size :photo, :less_than => 5.megabytes
validates_attachment_content_type :photo, :content_type => ['image/jpeg', 'image/png']

validates_presence_of :name

has_many :mixes  

performance.rb

belongs_to :artist
belongs_to :event

events_controller.rb

def new
  @event = Event.new
  @event.artists.build

  respond_to do |format|
    format.html # new.html.erb
    format.xml  { render :xml => @event }
  end
end

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| %>
    <p>   
        <%= builder.label :name, "Artist"%><br/>
        <%= builder.text_field :name %><br/>
    </p>
<% end %>
<p>
    <%= f.submit 'Submit' %> <%= link_to 'Cancel', admin_events_path %>
</p>
<% end %>

output with second accepts_nested_attributes_for commented out

Processing Admin::EventsController#create (for 127.0.0.1 at 2010-06-15 21:10:24) [POST]
Parameters: {"commit"=>"Submit", "authenticity_token"=>"KigiyUNIE2iYTwo59lf7SClbG9Dxge7WEWDDd08OLEc=", "event"=>{"name"=>"test event", "artists_attributes"=>{"0"=>{"name"=>"test artist"}}, "date(1i)"=>"2010", "location"=>"some location", "date(2i)"=>"6", "date(3i)"=>"16", "description"=>"blah"}}
User Columns (2.4ms)   SHOW FIELDS FROM `users`
User Load (0.3ms)   SELECT * FROM `users` WHERE (`users`.`id` = 13) LIMIT 1
Event Columns (1.2ms)   SHOW FIELDS FROM `events`
Artist Columns (1.4ms)   SHOW FIELDS FROM `artists`
SQL (0.1ms)   BEGIN
Event Create (0.3ms)   INSERT INTO `events` (`name`, `created_at`, `location`, `updated_at`, `date`, `description`) VALUES('test event', '2010-06-16 04:10:24', 'some location', '2010-06-16 04:10:24', '2010-06-16', 'blah')
Artist Create (0.2ms)   INSERT INTO `artists` (`name`, `created_at`, `photo_file_size`, `updated_at`, `photo_file_name`, `photo_content_type`, `photo_updated_at`, `bio`) VALUES('test artist', '2010-06-16 04:10:24', NULL, '2010-06-16 04:10:24', NULL, NULL, NULL, NULL)
[paperclip] Saving attachments.
Performance Columns (1.1ms)   SHOW FIELDS FROM `performances`
Performance Create (0.2ms)   INSERT INTO `performances` (`event_id`, `artist_id`) VALUES(10, 22)
Performance Create (0.1ms)   INSERT INTO `performances` (`event_id`, `artist_id`) VALUES(10, 22)
SQL (0.4ms)   COMMIT
Redirected to http://localhost:3000/admin/events
Completed in 97ms (DB: 8) | 302 Found [http://localhost/admin/events]
A: 

I just created a quick test rails app with the code you supplied and here are the results:

Processing EventsController#create (for 192.168.1.2 at 2010-06-16 00:33:05) [POST]
    Parameters: {"commit"=>"Create", "authenticity_token"=>"R8lKqeTIbRQ5Ft8K+TNMNusCh4qmnOv8xxSIi25MMNE=", "event"=>{"name"=>"Event", "artists_attributes"=>{"0"=>{"name"=>"Me"}}, "date(1i)"=>"2010", "location"=>"nowhere", "date(2i)"=>"6", "date(3i)"=>"16", "description"=>"Test Event"}}
      Event Create (0.4ms)   INSERT INTO "events" ("name", "location", "created_at", "updated_at", "date", "description") VALUES('Event', 'nowhere', '2010-06-16 04:33:05', '2010-06-16 04:33:05', '2010-06-16', 'Test Event')
      Artist Create (12.3ms)   INSERT INTO "artists" ("name", "created_at", "updated_at") VALUES('Me', '2010-06-16 04:33:05', '2010-06-16 04:33:05')
      Performance Create (0.2ms)   INSERT INTO "performances" ("name", "created_at", "event_id", "updated_at", "artist_id") VALUES(NULL, '2010-06-16 04:33:05', 1, '2010-06-16 04:33:05', 1)
    Redirected to http://192.168.1.5:3000/events/1
    Completed in 251ms (DB: 13) | 302 Found [http://192.168.1.5/events]

What version of Rails are you running?

Have you tried creating a clean test app to see if it works?

There may be a gem or some plugin that's causing an issue. I'm running 2.3.8 with SQLite3.

I do not get all of the extra output you are showing, which may be something MySQL specific related to the has_many :through relationship, but that's something to look at as well.

Here is my schema for reference:

  create_table "artists", :force => true do |t|
    t.string   "name"
    t.datetime "created_at"
    t.datetime "updated_at"
  end

  create_table "events", :force => true do |t|
    t.string   "name"
    t.string   "location"
    t.date     "date"
    t.text     "description"
    t.datetime "created_at"
    t.datetime "updated_at"
  end

  create_table "performances", :force => true do |t|
    t.string   "name"
    t.integer  "artist_id"
    t.integer  "event_id"
    t.datetime "created_at"
    t.datetime "updated_at"
  end
Awgy
added full output and commented out second accepts_nested_attributes_for. results seem to be the same.
shalako
@shalako: I think that should fix it.
Awgy
good catch, but looks like my code is correct (just as you've suggested) and i just copied it into stackoverflow wrong. :(
shalako
updated artists.rb here, confirmed my code is correct, ran test again. updated output. same behavior.
shalako
@shalako: I updated my answer. I'm off to bed for now. I'll check back tomorrow to see how things went. Good luck! :)
Awgy
@Awgy thanks for your help. I created the app from scratch using only bare essentials and I'm still getting duplicates in the performances table. Rails 2.3.5
shalako
A: 

This was solved by updating Rails to the latest version, 2.3.8. This appears to be a bug in 2.3.5.

https://rails.lighthouseapp.com/projects/8994/tickets/3659-accepts_nested_attributes_for-causes-duplicate-entries-in-join-model-table

shalako
Hey! I'm glad to hear that you fixed it. If I was of some help to you with my "what version of rails are you running?" question, please consider up voting my question or accepting it as the answer. Rep appears really hard to come by when you just answer questions =)
Awgy