0

J'ai créé trois classes pour représenter Livres, Les gens et BookLoans. Bien que je sois capable de montrer l'association de People to Books à BookLoans, j'ai commencé à créer ma base de données.Comment sauvegarder un enregistrement dans l'association entre-a de nombreuses classes dans Ruby on Rails

Je dois maintenant enregistrer une commande d'un livre. J'avais l'intention de faire cette action par l'intermédiaire du contrôleur de livre. Plus précisément, créer une action de prêt dans le BooksController. Bien que cela ait du sens pour moi en théorie, j'ai du mal à implémenter la syntaxe appropriée.

J'ai ajouté la possibilité de prêter un livre à partir de la vue d'un livre. Cette vue contient maintenant un formulaire qui utilise l'action de prêt du contrôleur de livre pour enregistrer le prêt.

J'ai ajouté ce que je crois être les méthodes appropriées à mon modèle de livre. Avec l'aide de theIV j'ai capturé les informations appropriées dans le contrôleur. Malheureusement, lorsque j'appuie sur Prêt dans l'affichage du livre, un enregistrement book_loan n'est pas enregistré.

Qu'est-ce qui me manque?

Modèle livre

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éthode prêt à partir BooksController

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

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

livre Afficher la vue w/Formulaire prêt

<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 Modèle

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

Personne Modèle

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

Développement Log

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 

Répondre

1

Lorsque vous has_many un modèle, vous aurez accès à quelques méthodes supplémentaires, deux en particulier sontEst comme new, create est comme create :). Jetez un oeil à la has many documentation. Dans ce cas, vous pouvez réécrire add_loan comme

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

ou quelque chose de similaire.

Pour répondre à votre question sur ce que la vue va envoyer au contrôleur, il envoie le hachage params comme d'habitude, mais si vous voulez juste passer le person_id-add_loan, vous pouvez extraire cela. En supposant que la partie de la vue que vous avez ci-dessus est enveloppée dans un formulaire pour un prêt de livre, vous pouvez accéder à la personne par params[:book_loan][:person_id]. Vous aurez également envie de faire une recherche dans cette action en premier, sinon @book va être nul.

Espérons que cela aide. À votre santé.

EDIT: Je ne sais pas si la façon dont vous avez cela fonctionne en ce moment, mais je pense que vous voulez changer votre modèle Person pour lire

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

EDIT 2: Votre journal de développement dit que vous aren » t en frappant loan, vous frappez update. Quelques choses que vous pourriez faire: vérifiez pour vous assurer que vous avez loan comme une ressource répertoriée dans vos itinéraires; fusionner l'action loan dans l'action update-pourrait commencer à devenir un peu salissant, donc je ne sais pas si c'est la meilleure approche. Je suis sûr qu'il y en a plus, mais ce sont les premières choses qui me viennent à l'esprit. En outre, je ne sais pas si vous pouvez ajouter :action => 'loan' à une balise submit. Je pense que ça va juste regarder ça comme s'il s'agissait d'une option html. Vous pouvez modifier votre form_for pour lire

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

une fois que vous avez fait en sorte que les routes sont en ordre. Mais comme je l'ai dit plus tôt, je suis sûr que vous allez avoir une erreur sur cette action parce que vous n'avez pas défini un Book.find pour cela.

+0

Quelle serait la meilleure option pour créer une vue. Par souci de simplicité, j'aimerais utiliser le livre comme point de départ et c'est pourquoi je pensais simplement passer le person_id. Pour le moment j'allais essayer d'ajouter un formulaire supplémentaire à la modification du livre. En outre, merci pour la prise sur la personne que j'aurais fait tourner mes roues pour un peu. – ahsteele

+0

Vous pourriez ajouter un 'fields_for' pour le prêt du livre à votre formulaire de livre. Vous pouvez également regarder dans 'accept_nested_attributes_for' http://www.railsapi.com/doc/rails-v2.3.4/classes/ActiveRecord/NestedAttributes/ClassMethods.html – theIV

+0

Désolé, pour développer un peu sur le commentaire précédent. Si vous ajoutez un «fields_for» pour votre prêt de livre, vous devriez construire un prêt de livre dans votre contrôleur d'abord-'@ loan = @ book.book_loans.build'- et ensuite faire les fields_for sur @loan – theIV