Build has_many: через для нового объекта - PullRequest
1 голос
/ 18 марта 2012

Возможно, я все делаю неправильно, но, возможно, кто-то сможет щебетать и помогать.

Проблема

Я хочу иметь возможность построить отношения на несохраненном Объекте, чтобы это работало:

v = Video.new
v.title = "New Video"
v.actors.build(:name => "Jonny Depp")
v.save!

Чтобы добавить к этому, они будут сгенерированы с помощью специального метода, который я пытаюсь изменить для работы, который выполняет следующее:

v = Video.new
v.title = "Interesting cast..."
v.actors_list = "Jonny Depp, Clint Eastwood, Rick Moranis"
v.save

Этот метод выглядит так в video.rb

def actors_list=value
  #Clear for existing videos
  self.actors.clear

  value.split(',').each do |actorname|
    if existing = Actor.find_by_name(actorname.strip)
      self.actors << existing
    else
      self.actors.build(:name => actorname.strip)
    end
  end
end

Что я ожидаю

v.actors.map(&:name)
=> ["Jonny Depp", "Clint Eastwood", "Rick Moranis"]

К сожалению, эта тактика не создает ни Актера, ни ассоциации. Ах да, вы можете спросить меня об этом:

в видео.rb

has_many :actor_on_videos
has_many :actors, :through => :actor_on_videos

accepts_nested_attributes_for :actors

Я также пытался изменить метод actors_list= следующим образом:

def actors_list=value
  #Clear for existing videos
  self.actors.clear

  value.split(',').each do |actorname|
    if existing = Actor.find_by_name(actorname.strip)
      self.actors << existing
    else
      self.actors << Actor.create!(:name => actorname.strip)
    end
  end
end

И он создает Актера, но я бы предпочел не создавать Актера, если при сбое Видео не удается сохранить.

Так я не подхожу к этому неправильно? Или я что-то упустил очевидное?

Ответы [ 2 ]

1 голос
/ 18 марта 2012

Попробуйте это:

class Video < ActiveRecord::Base

  has_many :actor_on_videos
  has_many :actors, :through => :actor_on_videos

  attr_accessor :actors_list
  after_save    :save_actors

  def actors_list=names
    (names.presence || "").split(",").uniq.map(&:strip).tap do |new_list|
      @actors_list = new_list if actors_list_changes?(new_list)
    end
  end

  def actors_list_changes?(new_list)
    new_record? or 
      (actors.count(:conditions => {:name => new_list}) != new_list.size)
  end

  # save the actors in after save.
  def save_actors
    return true if actors_list.blank?
    # create the required names
    self.actors = actors_list.map {|name| Actor.find_or_create_by_name(name)}
    true
  end
end
0 голосов
/ 18 марта 2012

Вы не можете назначить ребенка объекту без идентификатора.Вам нужно будет сохранить актеров в новом видеообъекте и сохранить эти записи после того, как видео было сохранено и имеет идентификатор.

...