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

时间:2019-09-21 19:23:43

标签: ruby-on-rails ruby

对于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 %>

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

3 个答案:

答案 0 :(得分:5)

提交无效数据后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命令,您可以查看所有路由,包括请求类型。

答案 1 :(得分:3)

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

Rails flavor REST中,GET /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返回一个/clients/new标头和正确的响应代码(302),它将浏览器重定向到新位置。

  

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

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

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

答案 2 :(得分:0)

提交此表单时,它将通过post方法转到/ client URL。当您在发生错误的情况下调用render方法时, 让我们了解一下“渲染”的工作原理以及它的功能(以及它与“重定向”的区别):

render:渲染将作为响应正文返回到浏览器的内容。

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

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

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

您还可以通过某些方式(在下面的URL中进行描述)来更改渲染的URL(但这不​​是Rails and Rest的方式。)

Render template and change url string in browser?