对于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
答案 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的方式。)