Как сохранить связывающую запись между классами has-many в Ruby on Rails
-
16-09-2019 - |
Вопрос
Я создал три класса для представления Книги, Люди, и КнигаКредиты.Хотя я могу показать связь людей с книгами через BookLoans, я заполняю свою базу данных.
Теперь мне нужно сохранить оформление заказа на книгу.Я намеревался выполнить это действие через контроллер книги.В частности, создание действия кредита в BooksController.Хотя теоретически это имеет для меня смысл, мне очень трудно реализовать соответствующий синтаксис.
Я добавил возможность одалживать книгу из режима показа книги.Это представление теперь содержит форму, которая использует действие ссуды контроллера книги для записи ссуды.
Я добавил в свою модель Book, как мне кажется, подходящие методы.С помощью IV Я зафиксировал соответствующую информацию в контроллере.К сожалению, когда я нажимаю «Ссуда» в режиме просмотра книги, запись book_loan не записывается.
Что мне не хватает?
Модель книги
class Book < ActiveRecord::Base
has_many :book_loans
has_many :borrowers, :through => :book_loans, :source => :person
accepts_nested_attributes_for :book_loans, :allow_destroy => true
def loaned?
book_loans.exists?(:return_date => nil)
end
def current_borrower
if loaned?
book_loans.first(:order => "out_date desc").person
end
end
def add_loan (person_id)
book_loans.create(:book_id => id,
:person_id => person_id,
:out_date => Date.current)
end
end
Метод кредита от BooksController
def loan
@book.add_loan(params[:book_loan][:person_id])
redirect_to :action => 'book', :id => params[:id]
end
Просмотр книжной выставки с формой займа
<p>
<b>Title:</b>
<%=h @book.title %>
</p>
<p>
<b>Isbn10:</b>
<%=h @book.isbn10 %>
</p>
<p>
Currently loaned to:
<%=h borrower_name(@book) %>
</p>
<% form_for(@book) do |x| %>
<p>
<%= x.label :loan_person_id %><br/>
<%= collection_select(:book_loan, :person_id,
Person.find(:all, :order => 'name ASC'), :id, :name) %>
<%= x.submit 'Loan', :action => 'loan' %>
</p>
<% end %>
Модель BookLoan
class BookLoan < ActiveRecord::Base
belongs_to :book
belongs_to :person
end
Модель человека
class Person < ActiveRecord::Base
has_many :book_loans
has_many :books, :through => :book_loans
end
Журнал разработки
Processing BooksController#update (for 127.0.0.1 at 2009-09-24 13:43:05) [PUT]
Parameters: {"commit"=>"Loan", "authenticity_token"=>"XskHLuco7Q7aoEnDfVIiYwVrMEh5uwidvJZdrMbYYWs=", "id"=>"1", "book_loan"=>{"person_id"=>"3"}}
[4;35;1mBook Columns (3.0ms)[0m [0mSHOW FIELDS FROM `books`[0m
[4;36;1mBook Load (4.0ms)[0m [0;1mSELECT * FROM `books` WHERE (`books`.`id` = 1) [0m
[4;35;1mSQL (0.0ms)[0m [0mBEGIN[0m
[4;36;1mBook Load (1.0ms)[0m [0;1mSELECT `books`.id FROM `books` WHERE (`books`.`title` = BINARY 'Dreaming in Code: Two Dozen Programmers, Three Years, 4,732 Bugs, and One Quest for Transcendent Software' AND `books`.id <> 1) LIMIT 1[0m
[4;35;1mSQL (1.0ms)[0m [0mCOMMIT[0m
Redirected to http://localhost:3000/books/1
Completed in 19ms (DB: 10) | 302 Found [http://localhost/books/1]
[4;36;1mSQL (0.0ms)[0m [0;1mSET NAMES 'utf8'[0m
[4;35;1mSQL (0.0ms)[0m [0mSET SQL_AUTO_IS_NULL=0[0m
Решение
Когда ты has_many
модели, вы получаете доступ к нескольким дополнительным методам, в частности двум collection.build
и collection.create
— build
как new
, create
как create
:).Взгляните на имеет много документации.В этом случае вы можете переписать add_loan как
def add_loan (person_id)
book_loans.create(:book_id => id,
:person_id => person_id,
:out_date => Date.current)
end
или что-то подобное.
Чтобы ответить на ваш вопрос о том, что представление будет отправлять контроллеру, оно отправит params
хэш, как обычно, но если вы просто хотите передать person_id
к add_loan
, вы можете извлечь это.Предполагая, что часть представленного выше представления заключена в форму для выдачи книги напрокат, вы можете получить доступ к этому человеку, выполнив params[:book_loan][:person_id]
.Вам также нужно сначала выполнить поиск в этом действии, иначе @book
будет равен нулю.
Надеюсь это поможет.Ваше здоровье.
РЕДАКТИРОВАТЬ:Я не уверен, что то, что у вас есть сейчас, работает, но я думаю, вы хотите изменить свое Person
модель для чтения
class Person < ActiveRecord::Base
has_many :book_loans
has_many :books, :through => :book_loans
end
РЕДАКТИРОВАТЬ 2:В вашем журнале разработки указано, что вы на самом деле не попадаете loan
, ты бьешь update
.Несколько вещей, которые вы могли бы сделать:проверьте, чтобы убедиться, что у вас есть loan
как указанный ресурс в ваших маршрутах;объединить loan
действие в update
действие — может начать становиться беспорядочным, поэтому я не знаю, лучший ли это подход.Я уверен, что их больше, но это первое, что приходит на ум.Кроме того, я не знаю, можете ли вы добавить :action => 'loan'
в тег отправки.Я думаю, что это будет выглядеть так, как будто это опция HTML.Возможно, вы захотите изменить свой form_for
читать
<% form_for(@book), :url => { :action => 'loan' } do |x| %>
как только вы убедитесь, что маршруты в порядке.Но, как я уже говорил ранее, я почти уверен, что при этом действии вы получите сообщение об ошибке, поскольку вы не определили Book.find
для этого.