2009-10-08 12 views
7

Próbuję forum beast napisane w szynach i użyję tego jako przykładu problemu, który napotykam.Sprawdzanie poprawności tras przez przekierowanie

Na forum znajduje się temat/akcja pokazu i widok z formularzem na dole, aby utworzyć nowy wpis w temacie.

Przesłanie formularza przechodzi do postów/utworzenia i jeśli sprawdzanie poprawności przekieruje z powrotem do tematów/pokazu i działa poprawnie, ale jeśli walidacja nie powiedzie się (pomijając pole ciała), nastąpi przekierowanie do tych samych tematów/pokazów i powrót do formularza, bez błędów sprawdzania poprawności ... normalnie, jeśli sprawdzanie poprawności nie powiedzie się, pozostaniesz na czymkolwiek/create przy pomocy render: action => new.

Czy sprawdzanie poprawności jest tracone w przekierowaniu i jaka jest najlepsza metoda sprawdzenia, czy działa?

patrz kod poniżej:

PostsController.rb

def create 
    @post = current_user.reply @topic, params[:post][:body] 

    respond_to do |format| 
     if @post.new_record? 
     format.html { redirect_to forum_topic_path(@forum, @topic) } 
     format.xml { render :xml => @post.errors, :status => :unprocessable_entity } 
     else 
     flash[:notice] = 'Post was successfully created.' 
     format.html { redirect_to(forum_topic_post_path(@forum, @topic, @post, :anchor => dom_id(@post))) } 
     format.xml { render :xml => @post, :status => :created, :location => forum_topic_post_url(@forum, @topic, @post) } 
     end 
    end 
    end 

TopicsController.rb

def show 
    respond_to do |format| 
     format.html do 
     if logged_in? 
      current_user.seen! 
      (session[:topics] ||= {})[@topic.id] = Time.now.utc 
     end 
     @topic.hit! unless logged_in? && @topic.user_id == current_user.id 
     @posts = @topic.posts.paginate :page => current_page 
     @post = Post.new 
     end 
     format.xml { render :xml => @topic } 
    end 
    end 

tematów/show widok

<% form_for :post, :url => forum_topic_posts_path(@forum, @topic, :page => @topic.last_page) do |f| %> 

    <%= f.error_messages %> 

    <table width="100%" border="0" cellpadding="0" cellspacing="0"> 
    <tr> 
     <td rowspan="2" width="70%"> 
     <%= f.text_area :body, :rows => 8 %> 
     </td> 
     <td valign="top"> 
     <%= render :partial => "posts/formatting" %> 
     </td> 
    </tr> 
    <tr> 
     <td valign="bottom" style="padding-bottom:15px;"> 
     <%= submit_tag I18n.t('txt.views_topics.save_reply', :default => 'Save reply') %> 
    </td> 
    </tr> 
    </table> 
    <% end %> 

Dziękujemy.

+0

Sam proces pracy wygląda dziwnie – Chirantan

+0

Jak masz na myśli? Mogłem prosić o to prościej bez przykładu. Zasadniczo, co dzieje się z komunikatami o błędach, jeśli przekierowujesz zamiast renderować i gdzie można uzyskać do nich dostęp? – sebastyuiop

Odpowiedz

12

Myślę, że masz tu dwa problemy.

  1. Utrzymanie błędy walidacji poprzez przekierowanie
  2. zasiedlać te pola formularzy, dzięki czemu użytkownik nie musi ponownie wprowadzić wszystkie informacje.

Obie te rzeczy są ze sobą połączone.

Błędy sprawdzania poprawności są zwykle wyświetlane za pomocą metody error_msg_for, która działa na obiekcie. Zwykle jest dostarczany przez kontroler jako zmienna instancji obiektu, której nie można zapisać. Ta sama instancja zmiennej służy do ponownego wypełnienia formularza.

Podczas przekierowania kontroler zwykle tworzy instancję zmiennej instancji za pomocą skrótu params. Tak więc wszelkie informacje używane do określenia przyczyny niepowodzenia zapisu są tracone. Normalne zasoby będą renderowane przy niepowodzeniu i przekierowaniu na sukces, co powoduje dwie rzeczy.

  1. Wystąpienie obiektu jest przekazywane do error_msg_for tworzenia tego ładnego, jednolitego pola błędu.
  2. Instancja obiektu służy do wypełniania pól formularza, umożliwiając użytkownikowi edycję tylko tego, co jest konieczne.

Nie znam Bestii tak dobrze, więc nie jestem pewien, czy forma tworzenia wątków jest aktywnym modelem rekordu. Jednak poniższe informacje pozwolą Ci poradzić sobie z problemem. Wymagałoby to zmodyfikowania lokalnej kopii wtyczki Beast, więc jeśli używasz narzędzia do aktualizacji, Twoje zmiany mogą zostać utracone.

Używam następujących metod, aby uzyskać problemy z walidacją. Zakładając, że formularz, o którym mówisz, bazuje na nmodelu, powinien dostarczyć ci wszystkiego, czego potrzebujesz do ponownego wypełnienia formularza.

Zasadniczo przechowujesz płytką kopię obiektu z błędami w haśle flash, używając clone_with_errors. Musisz użyć płytkiej kopii, bo inaczej napotkasz problemy podczas wyświetlania błędów dla rekordów z wieloma skojarzeniami.

Następnie używam my_error_msg_for, który ma takie same opcje jak standardowe error_msg_for do budowania komunikatów o błędach html. Napisałem go tylko dlatego, że z jakiegoś powodu standardowa metoda error_msg_for nie działała z obiektami przechowywanymi w hashu. Jest prawie identyczny z oficjalną źródłową wersją error_msg_for, która była niepokojąca.

/app/controllers/examples_controller.rb

class ExamplesController < ApplicationController 
    def update 
    ... 

    if @example.save 
     regular action 
    else 
     flash[:errors] = clone_with_errors(@example) 
     respond_to do |format| 
     format.html redirect_to(@example) 
     end 
    end 
end 

/app/views/examples/show.html.erb

<div id="error"> 
     <% if flash[:errors] && !flash[:errors].empty? then -%> 

     <p ><%= my_error_msg_for flash[:errors] %></p> 

     <% end -%> 
</div> 
... 

Oto kod trzeba to zrobić cała praca.

application_controller.rb

def clone_with_errors(object) 
    clone = object.clone 
    object.errors.each{|field,msg| clone.errors.add_to_base(msg)} 
    return clone 
    end 

application_helper.rb

def _error_msg(*params) 

    options = params.extract_options!.symbolize_keys 
    if object = options.delete(:object) 
     objects = [object].flatten 
    else 
     objects = params.collect {|object_name| instance_variable_get("@#{object_name}") }.compact 
    end 
    count = objects.inject(0) {|sum, this| sum + this.errors.count } 
    unless count.zero? 
     html = {} 
     [:id, :class].each do |key| 
     if options.include?(key) 
      value = options[key] 
      html[key] = value unless value.blank? 
     else 
      html[key] = 'errorExplanation' 
     end 
     end 
     options[:object_name] ||= params.first 
     options[:header_message] = "#{pluralize(count, 'error')} prohibited this #{options[:object_name].to_s.gsub('_', ' ')} from being saved" unless options.include?(:header_message) && !options[:header_messag].nil? 
     options[:message] ||= 'There were problems with the following fields:' unless options.include?(:message) && !options[:message].nil? 
     error_messages = objects.sum {|this| this.errors.full_messages.map {|msg| content_tag(:li, msg) } }.join 

     contents = '' 
     contents << content_tag(options[:header_tag] || :h2, options[:header_message]) unless options[:header_message].blank? 
     contents << content_tag(:p, options[:message]) unless options[:message].blank? 
     contents << content_tag(:ul, error_messages) 

     content_tag(:div, contents, html) 
    else 
             '' 
    end 

    end 

    def my_error_msg_for(params) 
    _error_msg_test :object_name => params[:object].class.name.gsub(/([a-z])([A-Z])/,'\1 \2').gsub(/_/, " "), 
    :object => params[:object], :header_message => params[:header_message], :message => params[:message] 
    end 
+0

po prostu notatka, metoda add_to_base została usunięta z torów 3. Zamiast tego należy użyć błędów [: base] << "error". – damoiser

4

Obawiam się, że nie wiem nic o Beast, ale mówiąc ogólnie, wszystko przepada, kiedy przekierowujesz. To jest nowe żądanie strony i wszystko jest resetowane, chyba że gdzieś zostało zapisane (zazwyczaj baza danych lub sesja).

Normalny przepływ, jaki widzisz w formularzach, to przekierowanie, jeśli obiekt jest zapisany, ale renderowanie jeśli zapis nie powiedzie się. Plik widoku może następnie pobrać dowolne zmienne, które zostały ustawione w kontrolerze - zwykle zawiera to obiekt, który nie został zapisany, oraz komunikaty sprawdzania poprawności.

Niestety, nie rozwiązuje to Twojego problemu, ale mam nadzieję, że może dać ci wskazówki.

+0

Dzięki za wyjaśnienie. Dostaję, jak to zwykle działa, ale kiedy masz formularz dla postów na stronie tematu pokazu (co jest dość normalne), nie możesz naprawdę renderować: action => new na kontrolerze postów, ponieważ nie będziesz miał dostępu do obiektów dostępne w temacie show, chyba że go powielisz i dodasz dodatkowy widok do /posts/new.erb.html. Byłoby dobrze, gdyby można było renderować: action => "topics/show" w kontrolerze postów. Dzięki za pomoc. – sebastyuiop

2

My answer do a very similar question pisał niedawno tutaj na StackOverflow obejmuje szereg zalet i wad do redirect_to vs. render debata. Chciałbym usłyszeć, czy ktoś ma jakieś plusy/minusy do dodania do dyskusji.

+0

Próbowałem render. Działa, proste i głupie rozwiązanie. – workdreamer

Powiązane problemy