Rails collection_select со многими ко многим не создает запись в таблице соединений

Я работаю над приложением, напоминающим приложение для бронирования библиотек. Я застрял в создании вложенной формы для добавления новой книги. У меня есть форма, работающая для отношений «один ко многим» (изображения для книги и т. д.), но я также хочу ВЫБРАТЬ и привязать существующего автора к этой книге (у книги много авторов, а у автора много книг через< /em> таблица вкладов) с помощью collection_select.

При отправке формы она не делает запись в таблице соединения с book_id и author_id. (Мне удалось заставить его работать с простыми полями text_entry при создании нового автора, но collection_select просто не работает. Прежде чем добавить reject_if к accepts_nested_attributes, он продолжал создавать нового автора с пустыми first_name и last_name и делать запись в присоединиться к таблице с этим пустым новым автором)

Вот моя форма, разделенная на важные части

    <%= form_for @book do |f| %>

    <div class="panel panel-default">
        <div class="panel-body">
            <%= f.label :name, "Book title" %>
            <%= f.text_field :name %>
            <%= f.label :description %>
            <%= f.text_area :description, rows: 5 %>
            <%= f.label :year_of_publication %>
            <%= f.text_field :year_of_publication %>
        </div>
    </div>

    <div class="panel panel-default">
        <div class="panel-body">
            <h3>Add authors</h3>
            <h4>Choose from existing authors</h4>
            <%= f.fields_for :authors do |builder| %>
                <%= builder.collection_select( :id, Author.all, :id, :full_name, prompt: "Select from existing authors") %>
            <% end %>
        </div>
    </div>

    <%= f.submit "Submit", class: "btn btn-info" %>
<% end %>

И это HTML, отображаемый в настоящее время для collection_select

<select id="book_authors_attributes_0_id" name="book[authors_attributes][0][id]"><option value="">Select from existing authors</option>
<option value="1">Berman, Jules J.</option>
<option value="2">Writerton, Andy R.</option>
<option value="3">Goldner, Merle</option>
<option value="4">Auer, Cordell</option>
<option value="5">Metz, Dewitt</option>
<option value="6">Leffler, Briana</option>
<option value="7">Trantow, Audra</option>
<option value="8">Murazik, Ebony</option>
<option value="9">Bahringer, Cale</option>
<option value="10">Schmitt, Wiley</option>
<option value="11">Casper, Zoe</option>

Вот моя модель книги.

class Book < ActiveRecord::Base
# default_scope -> { order('name ASC') }

validates :year_of_publication, presence: true
validates :description, presence: true
validates :name, presence: true

has_many :stock_items,      dependent: :destroy
has_many :libraries,        through: :stock_items
has_many :contributions,    dependent: :destroy 
has_many :authors,          through: :contributions
has_many :bookings,         through: :stock_items

has_many :book_images, dependent: :destroy
accepts_nested_attributes_for :book_images
accepts_nested_attributes_for :authors, :allow_destroy => true, :reject_if => proc {|attributes| attributes['last_name'].blank? }
accepts_nested_attributes_for :libraries
accepts_nested_attributes_for :stock_items
accepts_nested_attributes_for :contributions

validates :name, presence: true
# validate year of pub length to 4
end

И моя авторская модель.

class Author < ActiveRecord::Base
validates :first_name, presence: true
validates :last_name, presence: true

has_many :contributions, dependent: :destroy
has_many :books, through: :contributions

def full_name
    "#{last_name}, #{first_name}"
end

end

Модель вклада (таблица соединений)

class Contribution < ActiveRecord::Base
    belongs_to :author
    belongs_to :book

    validates :author_id, presence: true
    validates :book_id, presence: true
end

Соответствующие части схемы

  create_table "authors", force: true do |t|
    t.string   "last_name"
    t.string   "first_name"
    t.datetime "created_at"
    t.datetime "updated_at"
  end

  create_table "contributions", force: true do |t|
    t.integer  "book_id"
    t.integer  "author_id"
    t.datetime "created_at"
    t.datetime "updated_at"
  end

  create_table "books", force: true do |t|
    t.string   "name"
    t.datetime "created_at"
    t.datetime "updated_at"
    t.string   "year_of_publication"
    t.string   "description"
  end

Мои действия new и create в BooksController

def new
@book = Book.new

# Displays empty fields in the new book action view (n.times)
1.times { @book.authors.build }
1.times { @book.book_images.build }
@book.stock_items.build
end

def create

@book = Book.new(book_params)

if @book.save
  redirect_to @book
  flash[:success] = "Book added"
else
  render 'new'
  flash.now[:danger] = "Book NOT added"
end
end

Мои параметры_книги

частный

def book_params
  # Include the nested parameters in the strong parameters as model_name_attributes !!!!!!!!!!
  params.require(:book).permit( :name, 
                                :description, 
                                :year_of_publication, 
                                authors_attributes: [ :first_name, :last_name ], 
                                book_images_attributes: [ :image_url, :book_id ], 
                                libraries_attributes: [ :name ], 
                                stock_item_attributes: [ :book_id, :library_id ], 
                                contribution_attributes: [ :book_id, :author_id ])
end

person Mihkel Mark    schedule 16.06.2014    source источник
comment
Разве эта строка <%= builder.collection_select( :id, Author.all, :id, :full_name, prompt: "Select from existing authors") %> не должна быть <%= builder.collection_select(:author_id, Author.all, :id, :full_name, prompt: "Select from existing authors") %>?   -  person Pavan    schedule 16.06.2014
comment
Спасибо за ваш комментарий! Если я попробую это, я получу NoMethodError в Books#new. неопределенный метод `merge' для :full_name:Symbol Я не совсем уверен, что это значит (я определил full_name в моей модели Author выше). Еще раз спасибо!   -  person Mihkel Mark    schedule 16.06.2014
comment
Можете ли вы опубликовать log info после отправки form?   -  person Pavan    schedule 16.06.2014
comment
Извините, я забыл удалить :id в предложенной вами строке. Я снова попробовал то, что вы сказали, теперь я получил неопределенный метод `author_id' для #‹Author:0x007f885b6c9590›.   -  person Mihkel Mark    schedule 16.06.2014
comment
Возможно, вам следует изменить эту строку <%= f.fields_for :authors do |builder| %> на <%= f.fields_for :contributions do |builder| %> и попробовать мое первое предложение.   -  person Pavan    schedule 16.06.2014
comment
После этого я получаю сообщение об ошибке в форме о том, что книга вкладов не может быть пустой. Вот отображаемый HTML после того, как вы сказали. <select id="book_contributions_attributes_0_author_id" name="book[contributions_attributes][0][author_id]">   -  person Mihkel Mark    schedule 16.06.2014
comment
Кроме того, это находится в параметрах "contributions_attributes"=>{"0"=>{"author_id"=>"33"}}, , которые являются идентификатором правильного автора, которого я выбрал из раскрывающегося списка.   -  person Mihkel Mark    schedule 16.06.2014
comment
Можете ли вы опубликовать полные сгенерированные параметры?   -  person Pavan    schedule 16.06.2014
comment
Удалите эту строку validates :book_id, presence: true из режима взносов.   -  person Pavan    schedule 16.06.2014
comment
{"utf8"=>"✓", "authenticity_token"=>"NKhJhFicid/SPNYkYzQ7oZ.....", "book"=>{"name"=>"Alice in Wonderland", "description"=>"Foo bar baz etc", "year_of_publication"=>"1865", "contributions_attributes"=>{"0"=>{"author_id"=>"33"}}, "book_images_attributes"=>{"0"=>{"image_url"=>"http://blogs.slj.com/afuse8production/files/2012/05/AliceWonderland22.jpg"}}, "stock_items_attributes"=>{"0"=>{"book_id"=>"", "library_id"=>"3"}}}, "commit"=>"Submit", "action"=>"create", "controller"=>"books"} Между прочим, соединение stock_items также использует выбор коллекции, и я тоже не могу заставить его работать. (Это book_id?)   -  person Mihkel Mark    schedule 16.06.2014
comment
Ты ангел Паван. Удаление проверки заставило его работать. Итак, в будущем я должен всегда создавать collection_select для таблицы join в отношениях «многие ко многим»?   -  person Mihkel Mark    schedule 16.06.2014
comment
Только в этих частных случаях.   -  person Pavan    schedule 16.06.2014
comment
Я опубликовал свой ответ. Пожалуйста, примите его, если он кажется полезным.   -  person Pavan    schedule 16.06.2014


Ответы (2)


Если я правильно понял, вы должны использовать свою join_table contributions. Изменение вашей части fields_for на это заставит ее работать

<div class="panel panel-default">
        <div class="panel-body">
            <h3>Add authors</h3>
            <h4>Choose from existing authors</h4>
            <%= f.fields_for :contributions do |builder| %>
            <%= builder.collection_select(:author_id, Author.all, :id, :full_name, prompt: "Select from existing authors") %>
            <% end %>
        </div>
    </div>
person Pavan    schedule 16.06.2014
comment
Точно, я пробовал это раньше, но не смог заставить его работать, потому что эта строка была рядом и стоила мне 2 полных дня: validates :book_id, presence: true Делая то, что Паван предложил в этом ответе, и удаляя строку в моей модели книги, все заработало. Спасибо! - person Mihkel Mark; 16.06.2014

Можете ли вы показать все три модели, которые вы используете для отношения «многие ко многим»?

class Physician < ActiveRecord::Base
attr_accessible :name, :title
  has_many :appointments
  has_many :patients, through: :appointments
end

class Appointment < ActiveRecord::Base
 attr_accessible :details, :patient_id, :physician_id
  belongs_to :physician
  belongs_to :patient
end

class Patient < ActiveRecord::Base
  attr_accessible :name , :details
  has_many :appointments
  has_many :physicians, through: :appointments
end

Должна быть какая-то проблема с самими определениями отношений, это обычно сразу работает

person Ravi D    schedule 16.06.2014
comment
Спасибо, я добавил в код модель Contributions, посмотрите. - person Mihkel Mark; 16.06.2014