ruby-on-rails – 重定向的Rails验证

前端之家收集整理的这篇文章主要介绍了ruby-on-rails – 重定向的Rails验证前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我正在尝试用rails编写的 beast论坛,并将此作为我一直面临的问题的一个例子.

论坛有一个主题/节目动作和视图,底部有一个表单,可以在主题中创建一个新帖子.

提交表单会发布到帖子/创建,如果验证通过重定向主题/显示并且工作正常,但是如果验证失败(遗漏了正文字段),您将被重定向到相同的主题/显示并返回到表单,没有验证错误…通常如果验证失败,你就会留下什么/使用render创建:action =>新.

验证是否在重定向中丢失,以及使其运行的最佳方法是什么?

见下面的代码

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,@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

主题/节目视图

<% form_for :post,:url => forum_topic_posts_path(@forum,: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 %>

非常感谢.

解决方法

我觉得你有两个问题.

>通过重定向保持验证错误
>重新填充表单字段,以便用户不必再次输入所有信息.

这两件事都是相互关联的.

验证错误通常通过作用于对象的error_msg_for方法显示.通常由控制器提供,作为无法保存的对象的实例变量.该相同的实例变量用于重新填充表单.

重定向期间,控制器通常使用params散列实例化实例变量.因此,用于确定保存失败原因的任何信息都将丢失.正常资源将在保存失败时呈现,并在成功时重定向,这会导致两件事情发生.

>将对象的实例传递给error_msg_for,以创建漂亮的统一错误框.
>对象的实例用于填充表单的字段,允许用户仅编辑必要的内容.

我不太了解Beast,所以我不确定创建线程的表单是否是一个活跃的记录模型.但以下内容将让您了解如何解决您的问题.它将涉及修改Beast插件的本地副本,因此如果您使用工具来更新它,您的更改可能会丢失.

我一直在使用以下方法解决您的验证问题.假设您所谈论的表单基于nmodel,它们应该为您提供重新填充表单所需的一切.

基本上,您使用clone_with_errors在闪存哈希中存储错误的对象的浅表副本.您必须使用浅拷贝,否则在为具有多个关联的记录显示错误时会遇到问题.

然后我使用my_error_msg_for,它采用与标准error_msg_for相同的选项来构建错误消息html.我只写它,因为由于某种原因,标准的error_msg_for方法不适用于存储在哈希中的对象.它与error_msg_for的官方源版本几乎完全相同,令人不安.

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

以下是使一切正常运行所需的代码.

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

猜你在找的Ruby相关文章