Pergunta

Eu criei três classes para representar Livros , Pessoas e BookLoans . Enquanto eu sou capaz de mostrar a associação de pessoas para Livros através BookLoans eu estive semeando meu banco de dados.

Agora eu preciso para salvar um check-out de um livro. Era minha intenção de fazer esta ação através do controlador livro. Especificamente, criando uma ação empréstimo no BooksController. Enquanto isso faz sentido para mim, em teoria, eu estou tendo um momento terrível implementar a sintaxe apropriada.

Eu adicionei a capacidade de emprestar um livro a partir do show ponto de vista de um livro. Este ponto de vista agora contém um formulário que usa a ação empréstimo do controlador livro para registrar o empréstimo.

Eu adicionei o que eu acredito que são os métodos apropriados para o meu modelo Book. Com a ajuda de theIV eu ter capturado as informações apropriadas no controlador. Infelizmente, quando eu pressionar empréstimo no show livro visualizar um registro book_loan não está sendo gravada.

O que eu estou ausente?

Livro Modelo

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

Método Empréstimo do BooksController

def loan
  @book.add_loan(params[:book_loan][:person_id])

  redirect_to :action => 'book', :id => params[:id]
end

Livro Show View w forma de empréstimo /

<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 Modelo

class BookLoan < ActiveRecord::Base
  belongs_to :book
  belongs_to :person
end

Pessoa Modelo

class Person < ActiveRecord::Base
  has_many :book_loans
  has_many :books, :through => :book_loans
end

Log Desenvolvimento

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
Foi útil?

Solução

Quando você has_many um modelo, você tem acesso a alguns métodos extra, duas em particular, são collection.build e collection.create build- é como new, create é como create :). Dê uma olhada na tem muitas documentação . Neste caso, você poderia reescrever add_loan como

def add_loan (person_id)
  book_loans.create(:book_id   => id,
                    :person_id => person_id,
                    :out_date  => Date.current)
end

ou algo similar.

Para responder à sua pergunta sobre o que a visão será enviando para o controlador, ele irá enviar o hash params como de costume, mas se você só quer passar o person_id para add_loan, você pode extrair isso. Assumindo que a parte da visão você tem acima é envolto em um formulário para um empréstimo de livro, você pode acessar a pessoa por params[:book_loan][:person_id]. Você também vai querer fazer um achado em que a ação em primeiro lugar, ou então @book vai ser nulo.

Espero que isso ajude. Felicidades.

EDIT: Eu não tenho certeza se a maneira de tê-lo agora funciona, mas eu acho que você quer mudar seu modelo Person para ler

class Person < ActiveRecord::Base
  has_many :book_loans
  has_many :books, :through => :book_loans
end

EDIT 2: O seu log de desenvolvimento diz que você não está realmente bater loan, você está batendo update. Algumas coisas que você pode fazer: verifique se você tem loan como um recurso listado em suas rotas; mesclar a ação loan no update ação poderia começar a receber tipo de confuso, então eu não sei se esta é a melhor abordagem. Estou certo de que há mais, mas essas são as primeiras coisas que surgem à mente. Além disso, eu não sei se você pode adicionar :action => 'loan' a um tag enviar. Eu acho que ele só vai olhar para isso como se fosse uma opção html. Você pode querer mudar a sua form_for para ler

<% form_for(@book), :url => { :action => 'loan' } do |x| %>

Uma vez que você tenha a certeza de que as rotas estão em ordem. Mas, como eu disse anteriormente, eu tenho certeza que você será jogado um erro naquela ação porque você não definiu um Book.find para ele.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top