5

Było wiele pytań na ten temat, ale żadna z nich nie wydaje się pomóc. I tak, obejrzałem this rails cast.Weryfikacja modelu zagnieżdżonego - błędy nie są wyświetlane

Mam autora, który ma wiele książek, tak jak poniżej:

Autor:

class Author < ActiveRecord::Base 
    attr_accessible :name 
    has_many :books, dependent: :destroy 

    accepts_nested_attributes_for :books, allow_destroy: true 

    validates :name, presence: true 
    validates :name, length: { minimum: 3 } 
end 

Book:

class Book < ActiveRecord::Base 
    attr_accessible :name, :year 
    belongs_to :author 

    validates :name, :year, presence: true 
    validates :year, numericality: { only_integer: true, less_than_or_equal_to: Time.now.year } 
end 

stworzyłem poniższy formularz aby dodać książkę do autora w autorach # pokaż:

<%= form_for([@author, @book], html: { class: "well" }) do |f| %> 
<% if @book.errors.any? %> 
    <div class="alert alert-block"> 
     <ul> 
      <% @author.errors.full_messages.each do |msg| %> 
       <li><%= msg %></li> 
      <% end %> 
     </ul> 
    </div> 
<% end %> 
#labels and buttons... 
<% end %> 

... z następującą metodą authors_controller:

def show 
    @author = Author.find(params[:id]) 
    @book = @author.books.build 
end 

... i następujący sposób books_controller:

def create 
    @author = Author.find(params[:author_id]) 
    if @author.books.create(params[:book]) 
     redirect_to author_path(@author) 
    else 
     render action: :show 
    end 
    end 

ja nie potrafię zrozumieć, dlaczego forma nie wyświetla żadnych komunikatów o błędach. Śledziłem przykład z railscastów, gdzie mówią, że powinna istnieć zmienna instancji książek w formie zamiast @ author.books.build, więc umieszczam tę ostatnią w kontrolerze i @book w formularzu - nadal bez skutku.

Dzięki za pomoc!

Odpowiedz

8

Przejdźmy przez to.

przesłaniu tworzyć, a dostanie się do akcji create

def create 
    @author = Author.find(params[:author_id]) 
    if @author.books.create(params[:book]) 
    redirect_to author_path(@author) 
    else 
    render action: :show 
    end 
end 

(Na marginesie, co jeśli @author nie znaleziono. Nie są obsługi tej sprawie.)

Teraz, autor zostanie znaleziony, ale @ author.books.create nie powiedzie się (zwróci false), więc wyrenderujesz działanie programu.

Używa szablonu pokazu, ale nie wywołuje kodu akcji pokazu. (Nota boczna, może nowa strona będzie lepszym wyborem, więc użytkownik może spróbować ponownie utworzyć.)

W tym momencie @author jest tworzone za pomocą znalezionego autora, ale nie @book. Więc @book, jeśli zostanie wywołany, będzie zerowe.

pokazu szablon robi

if @book.errors.any? 

które nie będą prawdziwe, więc reszta szablonu wewnątrz if zostanie pominięty. Dlatego nie ma błędów.

Nie potrzebujesz form_for, aby wyświetlić komunikaty o błędach. Jeśli przejdziesz do korzystania z nowego szablonu, pojawi się formularz, aby spróbować ponownie.

Przejdźmy więc do renderowania nowego.

Class BooksController < ApplicationController 
    def new 
    @author = Author.find(params[:author_id]) 
    @book = @author.books.build 
    end 

    def create 
    @author = Author.find(params[:author_id]) 
    @book = @author.books.build(params[:book]) 
    if @author.save 
     redirect_to author_path(@author) 
    else 
     render action: :new 
    end 
    end 

Twój nowy szablon będzie

<% if @author.errors.any? %> 
    <div class="alert alert-block"> 
     <ul> 
      <% @author.errors.full_messages.each do |msg| %> 
       <li><%= msg %></li> 
      <% end %> 
     </ul> 
    </div> 
<% end %> 
<% if @book.errors.any? %> 
    <div class="alert alert-block"> 
     <ul> 
      <% @book.errors.full_messages.each do |msg| %> 
       <li><%= msg %></li> 
      <% end %> 
     </ul> 
    </div> 
<% end %> 

<%= form_for([@author, @book], html: { class: "well" }) do |f| %> 
#labels and buttons... 
<% end %> 
+0

Dziękuję za szczegółową odpowiedź już! Nie mam nowej metody w kontrolerach książek - formularz nowej książki jest wyświetlany po wyświetleniu autora. Ponadto, gdy zmienię metodę książki # create zgodnie z sugestią, pojawia się błąd routingu, który mówi, że nie może znaleźć metody edycji. Co muszę zrobić inaczej, aby to naprawić? – weltschmerz

+0

Zapomniałem zmienić przekierowanie na: nowe. Standardowy projekt RESTful (niekoniecznie najlepszy projekt) jest taki, jak opisałem, gdzie pojawiłaby się nowa strona książek. Jeśli chcesz, aby działało inaczej, spróbuj zrozumieć, co się dzieje, i napraw to tak, jak chcesz. –

1

W kontrolerze Books /books_controller.rb

def new 
    @author = Author.find_by_id(params[:author_id]) 
    @book = @author.books.build 
end 

def create 
    @author = Author.find_by_id(params[:author_id]) 
    if @author 
    @book = @author.books.build(params[:book]) 
    if @book.save 
     flash[:notice] = "Book saved successfully" 
     redirect_to author_path(@author) 
    else 
     render :new 
    end 
    else 
    flash[:notice] = "Sorry no author found" 
    redirect_to author_path 
    end 
end 

Jeżeli autor nie jest obecny przekierowanie do strony indeksu autorów z komunikatem o błędzie nie uczynienia nowa forma, ponieważ nie będziesz w stanie budować książek, ponieważ autor jest zerowy.

A w swoich książkach nowa forma możesz mieć błąd na liście książek

/books/new.html.erb

<% if @book.errors.any? %> 
    <div class="alert alert-block"> 
     <ul> 
     <% @books.errors.full_messages.each do |msg| %> 
      <li><%= msg %></li> 
     <% end %> 
    </ul> 
    </div> 
<% end %>