ruby-on-rails 在Rails 7中表单提交后呈现视图不能正常工作

bjg7j2ky  于 2022-11-19  发布在  Ruby
关注(0)|答案(2)|浏览(203)

我已经按照Rails 7指南中的描述建立了一个无表模型:

class ContactForm
    include ActiveModel::Model
  
    attr_accessor :name, :email, :message
    validates :name, :email, :message, presence: true

end

我已经设置了一个操作来检查提交的内容是否有效,如果有效,则发送电子邮件:

def contact_process 
    @contact_form = ContactForm.new(contact_form_params)
    
    if @contact_form.valid?
      UserMailer.with(@contact_form).contact_form.deliver_later 
      redirect_to contact_path
    else  
      render :contact
    end 
  end

当出现错误并再次呈现联系人模板时,@contact_form似乎是一个空白的ContactForm示例,例如@contact_form.errors.count返回0,即使它在呈现命令之前在控制台中打印了正确的数字。

1tu0hz3e

1tu0hz3e1#

问题是由于尝试在表单提交后呈现带有 200 而不是 4xx5xx 代码的页面。可以按如下方式添加422代码,并且建议在模型出现问题时使用该代码:

render 'contact', status: :unprocessable_entity

Rails 7附带了Turbo。它预期表单提交后会有一个303代码重定向,一个例外是当你需要渲染验证错误时。下面是它如何处理表单提交,以及为什么渲染命令本身不起作用,你可能只会得到上一页的某个版本:
Turbo Drive处理表单提交的方式类似于链接点击。主要区别在于表单提交可以使用HTTP POST方法发出有状态请求,而链接点击只会发出无状态HTTP GET请求。
在表单提交的有状态请求之后,Turbo Drive期望服务器返回HTTP 303重定向响应,然后它将遵循该响应并使用该响应来导航和更新页面,而无需重新加载。
此规则的例外情况是,当响应呈现为4xx或5xx状态代码时。这允许呈现表单验证错误,方法是让服务器响应“422不可处理的实体”,并在出现“500内部服务器错误”时,使服务器崩溃以显示“出错”屏幕。
Turbo不允许在200上进行常规渲染的原因是浏览器有一个内置的行为来处理POST访问时的重新加载,在重新加载时会显示一个Turbo无法复制的“你确定要再次提交此表单吗?”对话框。相反,Turbo会在提交表单时停留在当前的URL上,而不是将其更改为表单操作。因为重载将针对操作URL发出GET,而操作URL可能根本不存在。

2w2cym1i

2w2cym1i2#

上面的解决方案将完美地工作,但如果我们使用上面的Devise将增加大量的工作,因为Devise使用内部渲染,我们需要在任何地方自定义。
除了上述问题,另一个永久性的解决办法就在这里。
创建turbo控制器:

class TurboController < ApplicationController
  class Responder < ActionController::Responder
    def to_turbo_stream
      controller.render(options.merge(formats: :html))
    rescue ActionView::MissingTemplate => error
      if get?
        raise error
      elsif has_errors? && default_action
        render rendering_options.merge(formats: :html, status: :unprocessable_entity)
      else
        redirect_to navigation_location
      end
    end
  end

  self.responder = Responder
  respond_to :html, :turbo_stream
end

initializers/devise.rb中使用以下代码:

config.parent_controller = 'TurboController'

如果是另一个控制器,则可以继承此控制器。
Rails 7使用Turbo和激励框架来提高前端性能。
你需要安装涡轮和刺激。

相关问题