2009-10-08 48 views
7

Tôi đang thử diễn đàn beast được viết bằng đường ray và sẽ sử dụng điều này làm ví dụ về sự cố mà tôi tiếp tục gặp phải.Xác thực đường ray qua chuyển hướng

Diễn đàn có một chủ đề/hiển thị hành động và xem với biểu mẫu ở dưới cùng để tạo bài đăng mới trong chủ đề.

Gửi biểu mẫu đến bài đăng/tạo và nếu xác thực chuyển hướng trở lại chủ đề/chương trình và hoạt động tốt, tuy nhiên nếu xác thực không thành công (rời khỏi trường nội dung), bạn sẽ được chuyển hướng đến cùng một chủ đề/chương trình và trở lại biểu mẫu, không có lỗi xác thực ... bình thường nếu xác thực không thành công, bạn còn lại trên bất kỳ/tạo bằng render: action => new.

Các xác thực có bị mất trong chuyển hướng hay không và phương pháp nào tốt nhất để làm việc đó?

Xem mã bên dưới:

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 

chủ đề/chương trình xem

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

Rất cám ơn.

+0

Luồng công việc có vẻ lạ lùng – Chirantan

+0

Ý của bạn là gì? Tôi có thể đã yêu cầu nó đơn giản hơn mà không có ví dụ. Về cơ bản, điều gì sẽ xảy ra với các thông báo lỗi nếu bạn chuyển hướng thay vì hiển thị và chúng có thể được truy cập ở đâu? – sebastyuiop

Trả lời

12

Tôi nghĩ bạn có hai vấn đề ở đây.

  1. Giữ lỗi xác nhận thông qua một chuyển hướng
  2. Repopulating các trường mẫu vì vậy người dùng không cần phải nhập tất cả các thông tin một lần nữa.

Cả hai thứ này đều được kết nối.

Lỗi xác thực thường được hiển thị thông qua phương pháp error_msg_for hoạt động trên đối tượng. Thường được cung cấp bởi bộ điều khiển như là một biến thể hiện của đối tượng không thể lưu được. Biến mẫu tương tự được sử dụng để tái biểu mẫu.

Trong khi chuyển hướng, bộ điều khiển thường sẽ khởi tạo biến mẫu bằng cách sử dụng hàm băm params. Vì vậy, bất kỳ thông tin được sử dụng để xác định lý do tại sao một lưu thất bại bị mất. Tài nguyên thông thường sẽ hiển thị khi lưu lỗi và chuyển hướng thành công, điều này sẽ khiến hai điều xảy ra.

  1. Ví dụ của đối tượng được chuyển đến error_msg_for tạo hộp lỗi thống nhất đẹp.
  2. Ví dụ của đối tượng được sử dụng để điền vào các trường của biểu mẫu, cho phép người dùng của bạn chỉ chỉnh sửa những gì cần thiết.

Tôi không biết Beast thật tốt, vì vậy tôi không chắc liệu biểu mẫu tạo chủ đề có phải là mô hình bản ghi hoạt động hay không. Nhưng sau đây sẽ cung cấp cho bạn một ý tưởng làm thế nào để làm việc xung quanh vấn đề của bạn. Nó sẽ liên quan đến việc sửa đổi bản sao địa phương của bạn của các plugin Beast, vì vậy nếu bạn đang sử dụng một công cụ để giữ cho nó được cập nhật, thay đổi của bạn có thể bị mất.

Tôi đã sử dụng các phương pháp sau đây để khắc phục sự cố xác thực của bạn. Giả sử biểu mẫu bạn đang nói đến dựa trên một nmodel, chúng sẽ cung cấp cho bạn mọi thứ bạn cần để tái tạo lại một biểu mẫu.

Về cơ bản, bạn lưu bản sao nông của đối tượng có lỗi trong băm flash, sử dụng clone_with_errors. Bạn phải sử dụng bản sao nông hoặc nếu không bạn sẽ gặp sự cố khi hiển thị lỗi cho các bản ghi có nhiều liên kết.

Sau đó, tôi sử dụng my_error_msg_for có các tùy chọn giống như error_msg_for chuẩn để tạo thông báo lỗi html. Tôi chỉ viết nó bởi vì vì lý do nào đó, phương thức error_msg_for tiêu chuẩn không làm việc với các đối tượng được lưu trữ trong băm. Nó gần như giống hệt với phiên bản nguồn chính thức của error_msg_for gây phiền toái.

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

Dưới đây là đoạn code bạn cần để làm cho nó tất cả công việc.

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

chỉ là một lưu ý, phương thức add_to_base đã bị xóa khỏi đường ray 3. Thay vào đó, bạn nên sử dụng lỗi [: base] << "error. – damoiser

4

Tôi sợ tôi không biết gì về Beast, nhưng nói chung, mọi thứ đều mất đi khi bạn chuyển hướng. Đó là một yêu cầu trang mới và mọi thứ được đặt lại trừ khi nó được lưu trữ ở đâu đó (cơ sở dữ liệu hoặc phiên làm việc đó, bình thường.)

Luồng bình thường bạn có thể thấy với biểu mẫu là chuyển hướng nếu đối tượng được lưu, nhưng để hiển thị nếu lưu không thành công. Sau đó, tệp xem có thể chọn bất kỳ biến nào đã được đặt trong bộ điều khiển - thường sẽ bao gồm đối tượng không lưu và thông báo xác thực của nó.

Rất tiếc, không giải quyết được sự cố của bạn, nhưng hy vọng nó có thể cung cấp cho bạn một số manh mối.

+0

Cảm ơn lời giải thích. Tôi nhận được nó hoạt động bình thường như thế nào, nhưng khi bạn có một form cho các bài viết trên một trang chủ đề hiển thị (điều này khá bình thường), bạn không thể thực hiện render: action => new trên controller controller vì bạn sẽ không có quyền truy cập vào các đối tượng có sẵn trên hành động chủ đề của chương trình trừ khi bạn sao chép và thêm chế độ xem bổ sung cho /posts/new.erb.html. Sẽ tốt nếu bạn có thể hiển thị: action => "topics/show" trong trình điều khiển bài đăng. Cảm ơn bạn đã giúp đỡ. – sebastyuiop

2

My answer để a very similar question đăng gần đây hơn ở đây trên StackOverflow bao gồm một số ưu và nhược điểm để các redirect_to vs render tranh luận. Tôi rất muốn nghe nếu có ai có bất kỳ ưu điểm/khuyết điểm nào khác để thêm vào cuộc thảo luận.

+0

Tôi đã thử hiển thị. Nó hoạt động, giải pháp đơn giản và ngu ngốc. – workdreamer

Các vấn đề liên quan