Rails формирует has_many через ассоциацию с дополнительными атрибутами?

Как создать поля формы для ассоциации has_many :through с дополнительными атрибутами?

Связь has_many :through имеет дополнительный столбец с именем weight.

Вот файл миграции для таблицы соединений:

create_table :users_widgets do |t|
  t.integer :user_id
  t.integer :widget_id
  t.integer :weight

  t.timestamps
end

Модели выглядят так:

User
  has_many :widgets, :through => :users_widgets,
           :class_name => 'Widget',
           :source => :widget
  has_many :users_widgets
  accepts_nested_attributes_for :widgets # not sure if this is necessary


Widget
  has_many :users, :through => :users_widgets,
           :class_name => 'User',
           :source => :user
  has_many :users_widgets
  accepts_nested_attributes_for :users # not sure if this is necessary


UsersWidget
  belongs_to :user
  belongs_to :widget

Для простоты виджет и пользователь имеют только одно собственное поле с именем name, следовательно, User.first.name и Widget.first.name.

Вопросы:

  • Как мне добавить раскрывающийся список для виджетов с соответствующим весом в форму создания/редактирования пользователя?

  • Как я могу динамически добавлять дополнительные формы виджетов к пользователям или формы пользователей к виджетам, чтобы легко добавлять или удалять эти отношения? Драгоценный камень nested_form_for кажется идеальным решением, но я не смог заставить его работать.

  • Помимо моделей и частей формы, нужно ли внести какие-либо изменения в мой контроллер?


Краткое примечание. Меня не интересует создание новых виджетов в форме пользователя или новых пользователей в форме виджета, мне нужна только возможность выбирать из существующих объектов.

Я использую Rails 3.1 и simple_form 2.0.0dev для создания форм.


person Marco    schedule 02.12.2011    source источник


Ответы (3)


Я буду решать вашу проблему, используя cocoon, гем, который я создал для обработки динамически вложенных форм. У меня также есть пример проекта, чтобы показать примеры различных типов отношений.

Ваш буквально не включен, но его не так сложно вывести из него. В вашей модели вы должны написать:

class User 
  has_many :users_widgets
  has_many :widgets, :through -> :user_widgets

  accepts_nested_attributes_for :user_widgets, :reject_if => :all_blank, :allow_destroy => true

  #...
end

Затем вам нужно создать частичное представление, в котором будут перечислены ваши связанные файлы UserWidgets. Поместите этот фрагмент в файл с именем users/_user_widget_fields.html.haml:

.nested-fields
  = f.association :widget, :collection => Widget.all, :prompt => 'Choose an existing widget'
  = f.input :weight, :hint => 'The weight will determine the order of the widgets'
  = link_to_remove_association "remove tag", f

В вашем users/edit.html.haml вы можете написать:

= simple_form_for @user do |f|
  = f.input :name

  = f.simple_fields_for :user_widgets do |user_widget|
    = render 'user_widget_fields', :f => user_widget
  .links
    = link_to_add_association 'add widget', f, :user_widgets

Надеюсь это поможет.

person nathanvda    schedule 17.12.2011
comment
Спасибо @nathanvda, это именно то, что я искал. Ваш драгоценный камень делает это особенно легким. PS: награда была назначена автоматически, прежде чем я смог ее вам дать, но я обратился к модам за помощью. - person Marco; 18.12.2011
comment
Была настроена почти такая же модель, это было удивительно полезно. Я нахожу сложные формы, такие как эта симпатичная, сногсшибательная, спасибо за отличный драгоценный камень / ответ! - person Ryan Haywood; 22.10.2012
comment
Я знаю, что это не совсем хорошая форма комментария к SO, но я просто хотел сказать большое СПАСИБО. Я пытался понять, как применить кокон для соединения таблиц около 6 часов и был почти готов сдаться. - person neanderslob; 14.07.2015


Большое спасибо за указатель кокона nathanvda. Я ломал голову над некоторыми проблемами, которые у меня возникли при попытке реализовать это под rails 4.0.0-rc1, и я подумал, что поделюсь своими выводами на тот случай, если у кого-то возникнут такие же проблемы при попытке этого udner rails4.

Используя приведенный выше код в качестве примера, я добавил user_id и widget_id к разрешенным параметрам, так как они сохранены в соединительной таблице user_widgets. В rails 3 вам нужно было добавить их в attr_accesible в пользовательской модели, но в rails 4 вы должны добавить их в разрешенные параметры в контроллере основной модели, которую вы используете для вложения, так что здесь это будет users_controller:

params.require(:user).permit(...user_fields...,  
  user_widgets_attributes: [:user_id, :widget_id])

Делая только это, вы столкнетесь с несколькими проблемами:

  1. Каждая ассоциация (виджет) умножается при обновлении записи пользователя. 1 становится 2, 4, 8 и т. д. при обновлении и сохранении записи.
  2. удаление ассоциации не работает, поле удаляется из формы, но ассоциация остается в БД.

Чтобы исправить эти проблемы, вам также необходимо добавить :id и :_destroy в список разрешенных атрибутов:

params.require(:user).permit(...user_fields...,  
  user_widgets_attributes: [:user_id, :widget_id, :id, :_destroy])

после этого работает без нареканий.

Юрген

PS: На данный момент вам нужно использовать репозиторий git в вашем Gemfile, чтобы использовать кокон под рельсами 4, пока не будет выпущен гем, совместимый с рельсами 4. Спасибо за электронное письмо nathanvda в моем отчете об ошибке!!

person helmerj    schedule 06.06.2013