【问题标题】:Why is "render 'new' " changing my URL? (Ruby On Rails)为什么“render 'new'”会改变我的 URL? (Ruby On Rails)
【发布时间】:2020-01-22 09:38:16
【问题描述】:

我为localhost:3000/clients/new 的客户提供了一个名为new.html.erb 的视图。我验证它是否有错误。如果出现错误,我会再次渲染新视图以显示所有错误。问题是它在我的浏览器中显示为localhost:3000/clients,而不是localhost:3000/clients/new。这是为什么? “渲染”不应该不改变 URL 的任何内容吗?这会在我刷新页面时出现问题,因为我没有“索引”视图并且它触发了错误,而不是按预期显示“新”视图。

new.html.erb

<% if @client.errors.any? %>
    <div class="alert alert-danger">
        <h4 class="alert-heading">Error</h4>
            <% @client.errors.full_messages.each do |msg| %>
                <p><%= msg %></p>
            <% end %>
     </div>
<% end %>

<%= form_for @client, url: clients_path, remote: false do |f| %>
    <div class="form-group  row"><label class="col-sm-2 col-form-label">*Name</label>
        <div class="col-sm-3">
            <%= f.text_field :name, class:"form-control" %>
                <% if @client.errors[:name].any? %>
                    <script>$('#client_name').css('border-color', 'red');</script>
                <% end %>
         </div>
</div>

<div class="col-sm-4 col-sm-offset-2">
    <%= f.submit "Submit", id:"submit", class: 'btn btn-primary btn-sm'%>
    <%= link_to "Cancel", controller:"mainpages", action:"index", :html=>{:class=> "btn btn-primary btn-sm"}%>
</div>
<% end %>

clients_controller.rb

def new
    @client = Client.new
  end

  def create
    @client = Client.new(client_params)

      if @client.save 
        return redirect_to :root
      end
      render 'new'
  end

routes.rb

  root to: "mainpages#index"

  get '/mainpages', controller: 'mainpages', action: 'index'
  get '/planes', controller: 'planes', action: 'planes'

  resources :clients
  resources :planes

client.rb

class Client < ApplicationRecord
    validates :name, presence: true
end

【问题讨论】:

    标签: ruby-on-rails ruby


    【解决方案1】:

    您的期望完全错误,但在 Rails 初学者中很常见。

    Rails flavor RESTGET /clients/new 中只是一个包含用于创建新资源的表单的页面。因为它是一个 GET 请求,所以它是 idempotent - 这意味着它是无状态的,并且对于所有访问者来说都是一样的。

    当您提交表单时,您的浏览器会向/clients 发送 POST 请求。同样在 Rails 风格的 REST 中,这就是您创建资源的方式。

    如果验证失败,rails 只会呈现包含表单的响应。这不应该重定向用户,因为您看到的是非幂等 POST 请求的结果。这与GET /clients/new 不是同一个资源。

    实际上render 'new' 只是render 'app/views/clients/new.html.erb' 的快捷方式。两个端点共享一个视图——没有别的。

    这是为什么呢? “渲染”不应该不会改变 URL 的任何内容吗?

    你完全错了。 render 不会更改 URL。之前提交表单会更改浏览器中的 URL。渲染只是渲染视图并将其作为响应的主体返回。如果您想了解客户端和服务器之间的交换实际是如何工作的,请查看 Rails 应用程序的日志。

    您可以将此与 redirect_to 进行对比,后者会返回一个 location 标头以及将浏览器重定向到新位置的正确响应代码 (302)。

    这会在我刷新页面时出现问题,因为我没有“索引” 视图,它会触发错误,而不是将“新”视图显示为 应该的。

    要解决此问题,您需要添加一个索引操作,该操作可以是简单的重定向到/clients/new。当您重新加载页面时,您将向 /clients 发送 GET 请求,该请求应呈现索引。

    我真的建议您尝试创建一个脚手架式 Rails 应用程序,以便在开始实施自己的想法之前了解 Rails 约定如何执行简单的 CRUD 操作。

    【讨论】:

      【解决方案2】:

      提交无效数据后URL显示/clients的原因是/clients/new表单将请求提交给clients#create,如果您使用Rails默认设置,POST /clients注册。

      如果您的数据有效,Rails 会将用户重定向到根路径GET /。如果您的数据无效,它将render :new 作为对POST /clients 的响应,在您的浏览器中显示为/clients

      如果您在提交无效数据后尝试刷新页面,浏览器应该会询问类似“您要重新提交表单吗?”。如果单击“是”,页面将刷新,并且不应点击GET /clients(通常路由到clients#index)。如果您手动单击 Web 浏览器的 URL 栏并点击 Enter,则会发送 GET /clients 请求,从而使您进入错误的页面。

      您可以通过运行rails routes 命令查看所有路由,包括请求类型。

      【讨论】:

      • 那么,如果我想在使用无效数据刷新页面时重新提交表单,我应该在路由中添加什么?
      • @FlowMafia 它目前按原样工作。如果您遇到麻烦,我猜您只是在刷新页面错误。大多数网络浏览器允许通过按F5Ctrl + R 或单击↻ 图标进行刷新。
      • 这就是我尝试刷新它的方式 (F5),但是浏览器发送请求以加载“索引”,正如我之前提到的,我没有查看它,因为我的意图是重新发送表格:/(rails 5,如果该信息相关)
      • @FlowMafia 您使用的是什么网络浏览器 + 版本?据我所知,所有现代浏览器都会使用 POST 请求重新加载页面。
      • 歌剧版本:63.0.3368.88
      【解决方案3】:

      当您提交此表单时,它会使用 post 方法转到 /client URL。当你调用 render 方法以防出错时, 让我们了解“渲染”的工作原理和作用(以及它与“重定向”的不同之处):

      render:将返回给浏览器的内容渲染为响应体。

      Render 告诉 Rails 向用户显示哪个视图或资产,而不会失去对控制器操作中定义的任何变量的访问权限。

      重定向不同。 redirect_to 方法告诉您的浏览器向另一个 URL 发送请求。由于请求完全不同,您重定向到的视图将无法访问控制器中定义的任何变量。

      所以在这种情况下,如果您重定向,您将丢失您提交的数据,因为这将是一个全新且独立的请求。

      有一些方法(在下面的 URL 中描述)您也可以通过渲染更改 URL(但这些不是 Rails 和 Rest 方法。)

      Render template and change url string in browser?

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2014-05-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-07-20
        • 2017-07-04
        • 2020-06-30
        相关资源
        最近更新 更多