Сохранение атрибутов соединения через has_many: through с: условие - PullRequest
5 голосов
/ 11 августа 2011

У меня есть модель Artist, которая выглядит следующим образом:

# app/models/artist.rb
class Artist < ActiveRecord::Base
  # Relationships
  has_many  :releases
  has_many  :songs, :through => :releases
  has_many  :featured_songs,  :through => :releases,
                              :class_name => "Song",
                              :source => :song,
                              :conditions => { 'releases.featured', true }                         

end

Получение featured_songs работает отлично.Проблема в том, что я не могу добавить новый featured_song к исполнителю, потому что по какой-то причине атрибут признака «Featured» установлен в «nil».

Это то, что я пытаюсь:

ruby-1.9.2-p180 :004 > a = Artist.first
ruby-1.9.2-p180 :005 > a.featured_songs.create(:title => "Title", :user => User.first)

Фактический результат:

ruby-1.9.2-p180 :004 > a = Artist.first
ruby-1.9.2-p180 :005 > a.featured_songs.create(:title => "Title", :user => User.first)
  User Load (0.9ms)  SELECT `users`.* FROM `users` LIMIT 1
  SQL (1.0ms)  BEGIN
  SQL (5.5ms)  INSERT INTO `songs` (`created_at`, `title`, `updated_at`, `user_id`) VALUES (?, ?, ?, ?)  [["created_at", Thu, 11 Aug 2011 18:30:34 UTC +00:00], ["title", "Title"], ["updated_at", Thu, 11 Aug 2011 18:30:34 UTC +00:00], ["user_id", 1]]
  SQL (1.2ms)  INSERT INTO `releases` (`album_id`, `artist_id`, `created_at`, `featured`, `song_id`, `updated_at`) VALUES (?, ?, ?, ?, ?, ?)  [["album_id", nil], ["artist_id", 1], ["created_at", Thu, 11 Aug 2011 18:30:34 UTC +00:00], ["featured", nil], ["song_id", 6], ["updated_at", Thu, 11 Aug 2011 18:30:34 UTC +00:00]]
   (0.1ms)  COMMIT

Обратите внимание: ["featured", nil]

Есть идеи, что я делаю неправильно?Как правильно установить атрибуты в моем соединении, не обращаясь к нему напрямую?

спасибо!

РЕДАКТИРОВАТЬ: Чтобы сделать мою проблему более ясной:

  • Из экземпляра исполнителя я не могу создать новые избранные песни с помощью отношения featured_songs

  • Похоже, что при сохранении устанавливаются все атрибуты песни, КРОМЕ для (наиболее важного) featured

  • Атрибут featured по какой-то причине устанавливается на nil, и это реальная проблема здесь.

Ответы [ 4 ]

2 голосов
/ 30 октября 2012

Я нашел рабочее решение после прочтения:

https://github.com/rails/rails/issues/5178#issuecomment-4181551

Хитрость заключается в том, чтобы создать новую ассоциацию has_many первого порядка, которая содержит условие, а затем выполнить has_many: through на , что .

Итак, в вашем случае это будет:

class Artist < ActiveRecord::Base
  # Relationships
  has_many  :releases
  has_many  :songs, :through => :releases

  has_many  :featured_releases, :class_name => "Release", :conditions => { :featured => true }
  has_many  :featured_songs, :through => :featured_releases, :source => :song
end
0 голосов
/ 13 августа 2011

РЕДАКТИРОВАТЬ: Обновлено: release_attributes для отражения отношения has_many.

ответ Джейдела в правильном направлении.Эта проблема решена accepts_nested_attributes_for.has_many описывает только механизм запроса записей, а не их обновления или создания.

Причина обновления перечисленных вами атрибутов заключается в том, что они являются частью объекта песни.Поле, которое вы пытаетесь обновить, является признаковым полем, которое является частью вашей releases таблицы соединений.

accepts_nested_attributes_for - это инструмент для решения проблемы обновления вложенных отношений.Если вы хотите добавить атрибут признака во время создания объекта песни (как вы делаете в своем примере), то вам нужно добавить его как часть вложенных атрибутов для класса песни.

class Song < ActiveRecord::Base
  has_many :releases
  has_many :artists, :through => :releases
  accepts_nested_attributes_for :releases
end

Вашcreate будет выглядеть примерно так:

a.songs.create(:title => 'Title', :user => User.first, :releases_attributes => [{ :id => 123, :featured => true}])

Обратите внимание на добавление _attributes.Это именно то, что Rails будет делать в представлениях, если вы используете вложенные формы.Обратитесь к исходному файлу ActiveRecord nested_attributes.rb для доказательства.

Если вы действительно хотите более чистый способ сделать это, вы можете добавить метод Song#create_featured, который бы объединял хеш :releases_attributesв опции #create.

0 голосов
/ 03 октября 2012

Ключом для сохранения через ассоциацию является предоставление attr_accessible для полей в модели ассоциации.

В этом случае добавьте строку в модель выпуска:

attr_accessible :song_id, :feature_id
0 голосов
/ 12 августа 2011

Вы можете использовать acceptpts_nested_attributes_for в модели.Я хотел бы начать с просмотра Railscast по этой теме, а затем просмотреть саму документацию для метода

EDIT:

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

class User < ActiveRecord::Base
  belongs_to :address

  accepts_nested_attributes_for :address
end

class Address < ActiveRecord::Base
  has_one :user
end

Затем я могу сделать это, чтобы создать новый адрес для пользователя

u = User.new
u.address.build({:city => "bozoville", :zip => "22222", ...})
u.save!

, и мой адрес на моемпользователь и сохранился.Это то, что ты искал?Я скажу, что я не совсем уверен, насколько эффективно это приводит к ассоциации многих со многими, но я предполагал, что это будет то же самое.Возможно, потому что один к одному полагается на один столбец для внешнего ключа, который работает, но когда он включает в себя более сложную связь с реальной таблицей соединений, он не работает?По крайней мере, вы могли бы исследовать возможность дальше ...

...