5

Ci sono state molte domande a riguardo, ma nessuna sembra essere di aiuto. E sì, ho visto this rails cast.Convalida del modello annidata - gli errori non vengono visualizzati

Ho un autore che ha molti libri, in questo modo:

Autore:

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 

libro:

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 

ho creato il seguente modulo per aggiungere un libro da un autore negli autori # show:

<%= 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 %> 

... con il seguente metodo authors_controller:

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

... e il seguente metodo 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 

io non riesco a capire perché il modulo non visualizza alcun messaggio di errore. Ho seguito l'esempio dei railscast in cui si dice che ci dovrebbe essere una variabile di istanza di libri nel modulo anziché @ author.books.build, quindi ho inserito quest'ultimo nel controller e @book nel modulo - ancora inutilmente.

Grazie per qualsiasi aiuto!

risposta

8

Facciamolo.

Si invia la creano, e che entra nella vostra creano l'azione

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 

(Nota a margine, che cosa se @author non viene trovato. Non sta gestendo questo caso.)

Ora, l'Autore viene trovato, ma @ author.books.create non riesce (restituisce false), quindi si esegue il rendering dell'azione di visualizzazione.

Questo utilizza il modello di presentazione, ma non chiama il codice di azione dello spettacolo. (Nota a margine, forse la nuova pagina sarebbe una scelta migliore, quindi l'utente può provare a creare nuovamente.)

A questo punto @author viene istanziato con l'autore che hai trovato, ma non con @book. Quindi @book, se chiamato, sarà nullo.

Il modello spettacolo fa

if @book.errors.any? 

che non sarà vero, in modo che il resto del modello all'interno del se verrà saltato. Ecco perché non ci sono errori.

Non è necessario un form_for per visualizzare i messaggi di errore. Se passi a utilizzare il nuovo modello, ci sarà un modulo per riprovare.

Quindi passiamo al rendering nuovo.

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 

Il nuovo modello sarà

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

Grazie per questa risposta dettagliata già! Non ho un nuovo metodo nel controller dei libri: il modulo per un nuovo libro viene visualizzato quando viene mostrato un autore. Inoltre, quando cambio i libri # crea il metodo come suggerito, ricevo un errore di routing che dice che non è possibile trovare il metodo di modifica. Cosa devo fare in modo diverso per risolvere questo problema? – weltschmerz

+0

Ho dimenticato di cambiare il reindirizzamento a: nuovo. Il design RESTful standard (non necessariamente il miglior design) è come ho descritto, dove ci sarebbe una nuova pagina per i libri. Se vuoi che funzioni in modo diverso, cerca di capire cosa non ha funzionato e risolvilo nel modo desiderato. –

1

controller Libri /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 

Se autore non è presente reindirizzamento alla pagina di indice autori con messaggio di errore dont rendere il nuova forma in quanto non sarai in grado di costruire il modulo di libri come autore è nullo.

E nei tuoi libri nuova forma si può avere l'errore elencato per i libri

/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 %>