Railsvalidation重定向
我正在尝试用rails编写的野兽论坛,并将此作为我一直面临的问题的一个例子。
论坛有一个主题/节目动作和视图,底部有一个表单,可以在主题中创建一个新post。
提交表单会发布到post/创建,如果validation通过重定向回主题/显示并且工作正常,但是如果validation失败(不包括正文字段),您将被重定向到相同的主题/显示并返回到表单,没有validation错误…通常如果validation失败,你就会留在任何/ create with render:action => new。
validation是否在重定向中丢失,以及使其运行的最佳方法是什么?
见下面的代码:
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
主题/节目视图
forum_topic_posts_path(@forum, @topic, :page => @topic.last_page) do |f| %> 8 %> "posts/formatting" %> 'Save reply') %>
非常感谢。
我觉得你有两个问题。
- 通过重定向保持validation错误
- 重新填充表单字段,以便用户不必再次输入所有信息。
这两件事都是相互关联的。
validation错误通常通过作用于对象的error_msg_for方法显示。 通常由控制器提供,作为无法保存的对象的实例变量。 该相同的实例变量用于重新填充表单。
在重定向期间,控制器通常使用params散列实例化实例变量。 因此,用于确定保存失败原因的任何信息都将丢失。 正常资源将在保存失败时呈现,并在成功时重定向,这会导致两件事情发生。
- 对象的实例传递给error_msg_for,以创建漂亮的统一错误框。
- 该对象的实例用于填充表单的字段,允许您的用户仅编辑必要的内容。
我不太了解Beast,所以我不确定创建线程的表单是否是一个活跃的记录模型。 但以下内容将让您了解如何解决您的问题。 它将涉及修改Beast插件的本地副本,因此如果您使用工具来更新它,您的更改可能会丢失。
我一直在使用以下方法来解决您的validation问题。 假设您所谈论的表单基于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
<% if flash[:errors] && !flash[:errors].empty? then -%> <%= my_error_msg_for flash[:errors] %>
<% end -%> ...
以下是使一切正常运行所需的代码。
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(/([az])([AZ])/,'\1 \2').gsub(/_/, " "), :object => params[:object], :header_message => params[:header_message], :message => params[:message] end
我害怕我对野兽一无所知,但一般来说,当你重定向时,一切都会丢失。 这是一个新的页面请求,一切都被重置,除非它被存储在某个地方(通常是数据库或会话)。
您倾向于使用表单看到的正常流程是在保存对象时重定向,但在保存失败时进行渲染。 然后,视图文件可以获取控制器中设置的任何变量 – 通常包括未保存的对象及其validation消息。
抱歉,这不能解决您的问题,但希望它可能会给您一些线索。
我最近在StackOverflow上发布的一个非常相似的问题的 答案涵盖了redirect_to
与render
辩论的一些优缺点。 我很想知道是否有任何其他优点/缺点可以添加到讨论中。
- 安排事件,并使事件跨越午夜
- Rails + Postgres迁移 – 为什么我收到错误“PG :: UndefinedFunction:ERROR:function gen_random_uuid()不存在”?
- 在私有控制器方法中返回redirect_to
- 在Rails 3中没有尾随斜杠的情况下重定向到规范路由
- 没有SQL查询的Web应用程序用于当前用户身份验
- 使用Rails 5在Heroku,PostgreSQL上运行迁移时出错
- ActiveRecord :: StatementInvalid:PG ::错误:错误:无法在Heroku中的只读事务错误中执行UPDATE
- 一旦启用了动作缓存,format.js就不会操作dom
- Django中的cache.fetch?