为什么“ render'new'”更改我的URL?(Ruby On Rails)

Flo*_*fia 6 ruby ruby-on-rails

我有一个名为视图new.html.erb在客户端localhost:3000/clients/new。我验证它的错误。如果有错误,我将再次渲染新视图以显示所有错误。问题是它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 %>
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

routes.rb

  root to: "mainpages#index"

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

  resources :clients
  resources :planes
Run Code Online (Sandbox Code Playgroud)

client.rb

class Client < ApplicationRecord
    validates :name, presence: true
end
Run Code Online (Sandbox Code Playgroud)

max*_*max 12

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

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

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

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

其实render 'new'只是一个捷径render 'app/views/clients/new.html.erb'。两个端点共享一个视图 - 没有别的。

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

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

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

这会在我刷新页面时出现问题,因为我没有“索引”视图并且它触发了错误而不是按预期显示“新”视图。

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

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


3li*_*t0r 5

/clients提交无效数据后显示URL的原因是,如果您使用Rails默认值,那么/clients/new表单将提交在clients#create其下注册的请求POST /clients

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

如果您在提交无效数据后尝试刷新页面,浏览器应询问类似“您是否要重新提交表单?”之类的内容。如果您单击“是”,则页面将刷新,并且不应该被点击GET /clients(通常会路由到clients#index)。如果您手动单击您的Web浏览器的地址栏和命中Enter一个GET /clients请求,而不是发送,从而登陆你的错误的网页上。

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