Использование вложенных атрибутов для простого выбора ассоциаций в форме
Я пытаюсь создать вложенную форму атрибута для создания модели, которая в первую очередь является связующим звеном между двумя другими моделями. В моем случае модели представляют books
, awards
и модель "разъем" book_awards
, Когда я редактирую книгу, я хочу быстро выбрать, какие награды она получила.
Я использую http://railscasts.com/episodes/196-nested-model-form-part-1 чтобы помочь мне начать, но я боюсь, что застрял.
Другой вопрос SO, который кажется похожим, это acceptpts_nested_attributes_for с find_or_create? К сожалению, это также не совсем то, что я делаю, и я не смог адаптировать это.
Мои модели выглядят так. У каждой модели есть дополнительные атрибуты, проверки и т. Д., Но я удалил их для ясности.
class Book < ActiveRecord::Base
has_many :book_awards
accepts_nested_attributes_for :book_awards, :allow_destroy => true
end
class Award < ActiveRecord::Base
has_many :book_awards
end
class BookAward < ActiveRecord::Base
belongs_to :book, :award
end
В моей книге методы контроллера для редактирования и новые, и случаи сбоя для создания и обновления у меня есть строка @awards = Award.all
,
На мой взгляд, я хотел бы видеть список всех наград с флажками рядом с ними. Когда я отправляю, я бы хотел обновить, создать или уничтожить book_award
модель. Если флажок установлен, я хотел бы обновить существующую модель или создать новую, если она не существует. Если флажок не установлен, то я хотел бы уничтожить существующую модель или ничего не делать, если награда никогда не существовала. У меня есть частичное book_awards
, Я не уверен, должен ли переключатель выбора флажка быть в этом частичном или нет.
Я думаю, что мой флажок будет моим крючком для :_destroy
но с его полярностью наоборот. Я думаю, что-то подобное в основном сделает это:
= f.check_box :_destroy, {}, 0, 1
В настоящее время у меня есть это в моем частичном, но я не уверен, где это действительно принадлежит.
Далее следует мой взгляд, который в настоящее время не работает, но, возможно, это поможет продемонстрировать, что я пытаюсь сделать. Я перебираю awards
и использовать fields_for
установить вложенные атрибуты для всего, что уже существует. Это ужасно уродливо, но я думаю, что это работает. Тем не менее, я не знаю, как начать с другим делом.
= f.label :awards
- @awards.each do |a|
- if f.object.awards && f.object.awards.include?(a)
= f.fields_for :book_awards, f.object.book_award.select{|bas| bas.award == a } do |ba|
= render 'book_awards', :f => ba, :a => a
- else
= fields_for :book_awards do |ba|
= render 'book_awards', :f => ba, :a => a
Я бы предпочел, чтобы награды были перечислены в том же порядке каждый раз (мой @awards
назначение в контроллере, вероятно, будет указывать порядок), а не перечисление существующих наград первым или последним.
1 ответ
Ненавижу отвечать на свой вопрос, но я наконец-то понял, что работает. Первое, что мне нужно было сделать, это обновить "новый" корпус на основе сумасшедшего объекта, который был включен в Railscast. Далее мне нужно было вручную установить :child_index
, Наконец, мне нужно было вручную установить :_destroy
установите флажок соответственно.
.field
= f.label :awards
- @awards.each_with_index do |a,i|
- if exists = (f.object.awards && f.object.awards.include?(a))
- new_ba = f.object.book_awards.select{|s| s.award == a}
- else
- new_ba = f.object.class.reflect_on_association(:book_awards).klass.new
= f.fields_for :book_awards, new_ba, :child_index => i do |ba|
= render 'book_awards', :f => ba, :a => a, :existing => exists
Мой частичный выглядит так:
.field
= f.check_box :_destroy, {:checked => existing}, 0, 1
= f.label a.name
= f.hidden_field :award_id, :value => a.id
= f.label :year
= f.number_field :year
Это не очень красиво, но, кажется, делает именно то, что я хотел.