Поскольку это ассоциация «многие ко многим», ассоциация has_many :through
часто используется для установки связи «многие ко многим» с другой моделью. Эта связь указывает на то, что декларирующая модель может быть сопоставлена с нулем или более экземплярами другой модели путем прохождения третьей модели. Теперь декларации ассоциации могут выглядеть так:
class Roster < ActiveRecord::Base
has_many :roster_players
has_many :players, :through => :roster_players
end
class RosterPlayer < ActiveRecord::Base
belongs_to :roster
belongs_to :player
end
class Player < ActiveRecord::Base
has_many :roster_players
has_many :roster, :through => :roster_players
end
Шаг 1:
Создать модель ассоциации.
$> rails g model roster_player roster:references player:references
$> rake db:migrate
Шаг 2:
То, что вам требуется, это способ приема вложенных атрибутов. Пройдите по этому рельсовому касту и прочитайте о nested_attributes . Кодовая форма, которую бросают рельсы, была извлечена Райаном Бейтсом как драгоценный камень и очень полезна.
Обновите ваш гемфайл, чтобы он требовал этот камень
gem 'nested_form'
$> bundle install
Затем запустите генератор, чтобы создать файл JavaScript. Это автоматически определит, используете ли вы jQuery или Prototype.
rails g nested_form:install
Запуск генератора добавит файл nested_form.js
, который должен быть включен после инфраструктуры jQuery или Prototype.
<%= javascript_include_tag :defaults, "nested_form" %>
Давайте извлечем вложенные атрибуты в часть с именем _roster_player_fields.html.erb
<div class="field">
<%= f.label :player_id, "Player" %>
<%= f.select :player_id, Player.all.collect { |p| [ p.name, p.id ] }, { :include_blank => true } %>
</div>
То, что мы хотим сделать здесь, это добавить в форму поля для каждого списка игроков. Мы можем использовать метод fields_for для управления связанными полями в форме, передавая ему имя связанной модели, а затем перебирая все связанные записи проигрывателя и создавая построитель форм для каждого из них. Строитель отрендерит партиал для каждого игрока.
<%= form_for(@roster) do |f| %>
<% if @roster.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(@roster.errors.count, "error") %> prohibited this roster from being saved:</h2>
<ul>
<% @roster.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<% f.fields_for :roster_players do |builder| %>
<%= render 'roster_player_fields', :f => builder %>
<% end %>
<%= link_to_add_fields "[+] Add Player", f, :roster_players %>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
Когда эта форма отображается, она будет выглядеть так, как раньше. Это связано с тем, что в новом списке не будет игроков, связанных с ним, и поэтому ни одно из полей игроков не будет отображаться. В конечном итоге мы хотим, чтобы в форме была ссылка «Добавить игрока», но мы можем просто создать roster_player в новом действии RosterController и отобразить его поля.
def new
@roster = Roster.new
@roster.roster_players.build
End
По умолчанию обновление вложенных атрибутов отключено, вы можете включить его, используя метод класса #accepts_nested_attributes_for
. При включении вложенных атрибутов в модели определяется средство записи атрибутов. Это должно сработать и надеюсь, что это поможет.