0

I have releases that can have many artists and artists can appear on many releases. Artists can be created within my release form via nested attributes. What i'm having trouble with is getting find_or_create to work on an artist.

I have the following code defined in my models and as you can see a rather ridiculous get/set/delete routine in the ArtistRelease model to achieve the desired outcome. This does work, but I don't like it. I know there's a better way via find_or_create. Can anyone help? Where should I place the find_or_create for this to work?

class Release < ActiveRecord::Base
  has_many :artist_releases, :dependent => :destroy
  has_many :artists, :through => :artist_releases
  accepts_nested_attributes_for :artists, :reject_if => lambda { |a| a[:name].blank? }, :allow_destroy => :true
  accepts_nested_attributes_for :artist_releases
end

class Artist < ActiveRecord::Base
  has_many :artist_releases
  has_many :releases, :through => :artist_releases
end

class ArtistRelease < ActiveRecord::Base
  belongs_to :artist
  belongs_to :release

  before_create :set_artist_id
  after_create :destroy_artist

  default_scope :order => 'artist_releases.position ASC'

  private    
  def set_artist_id
    a = Artist.where("name =?", artist.name).reorder("created_at").find(:first)
    a.role = artist.role
    a.position = artist.position
    a.save
    artist_id = a.id
    self.artist_id =  artist_id
  end

  def destroy_artist
    c = Artist.count(:all, :conditions => [ "name = ?", artist.name])
      if c > 1
        a = Artist.where("name =?", artist.name).reorder("created_at").find(:last)
        a.destroy
      end
    end
end
Raoot
  • 1,751
  • 1
  • 25
  • 51

1 Answers1

1

It seems you are looking for autosave_associated_records_for_[model_name] method which you should override in one of your models.

It is explained here: accepts_nested_attributes_for with find_or_create?. The example is for a simple has_many associacion.

For a has_many :through association I've developed sth like in the code below.

In my app I have a order_item --< seat >-- client connection. I am creating clients using new order_item form. Solution lets me create a new client and a seat association OR only a seat association when there already is a client with provided email in clients table. It won't update existing clients' other attributes but it can easily be extended to do that as well.

class OrderItem < ActiveRecord::Base
  attr_accessible :productable_id, :seats_attributes

  has_many :seats, dependent: :destroy
  has_many :clients, autosave: true, through: :seats

  accepts_nested_attributes_for :seats, allow_destroy: true   
end

class Client
  attr_accessible :name, :phone_1
  has_many :seats
  has_many :order_items, through: :seats
end

class Seat < ActiveRecord::Base
  attr_accessible :client_id, :order_item_id, :client_attributes

  belongs_to :client, autosave: true
  belongs_to :order_item

  accepts_nested_attributes_for :client

  def autosave_associated_records_for_client
    if new_client = Client.find_by_email(client.email)
      self.client = new_client
    else
      # not quite sure why I need the part before the if, 
      # but somehow the seat is losing its client_id value
      self.client = client if self.client.save!
    end
  end
end

Hope it helps!

Community
  • 1
  • 1
tomruss
  • 218
  • 2
  • 8