2

我在以下关系中有两个模型:Client has_many products 和 Product belongs_to client。在客户端显示视图中,我展示了一个用于创建新产品的表单,该新产品自动属于当前客户端。客户端控制器中的 show 方法

def show
  @client    = Client.find(params[:id])
  @products  = @client.products.paginate(page: params[:page])
  @product = @client.products.new
  @product.client_id = @client.id
end

并且显示视图呈现部分

    <h1>New Product:</h1>
    <%= render 'shared/product_form' %>

这有效,产品被正确创建。

当发生验证错误时,我在产品创建方法中设置了一个 flash 并重定向到客户端显示页面。在那里,我丢失了已正确填写的数据。我尝试保存 @product 实例变量,其中包含所有数据(包括错误的字段)

render client_path(client) 

来自产品控制器,但这会产生错误

缺少模板 /clients/17

地址是

http://localhost:3000/products

我说错了吗?我知道渲染通常会渲染同一个控制器的动作。我可以从产品控制器以某种方式呈现 Client::show 吗?是否有另一种方法来保存用户输入的数据?

4

3 回答 3

5

如果发生验证错误,您应该重定向回产生验证错误的页面。即:如果用户在products/new提交表单时正在,那么您的products#create操作应该render :new以再次呈现产品表单结束。

如果您的products#create操作是从 接收表单clients#show,那么您确实希望呈现clients#show验证错误。在这种情况下,表格中填写的所有信息都将在 中可用params[:product],就像在 中一样products#create

您可能想看看我最近写的另一个答案,以了解控制器之间的流程。

具体而言,您的案例中的误解如下:

当您遇到验证错误时,记录将不会保存,因此您无法“返回该数据”,因为您的应用程序没有将其保存在任何地方。提交的数据的唯一副本在请求中。

如果您 REDIRECT 您没有转发请求,则您通过向不同的 url 发出新请求来响应初始 POST 请求(其中包括所有表单信息作为 params[:product])。这就是您要使用 RENDER 的原因。

但是,如果您尝试这样做render clients_path(client),Ruby 将首先评估clients_path(client)字符串clients/(client.id),或者在您给出的示例中,clients/17.

然后 render 尝试调用render 'clients/17',您没有模板。它正在寻找一个名为clients/17.html.erb. 这就是为什么你会得到你得到的错误。

因此,再次总结一下 - 您的products#create操作接收从表单发送的信息为params[:products]. 该信息在此控制器操作之外不可用。因此,如果出现验证错误,而不是创建产品,此控制器操作应该呈现用户最初(通常)来自的同一页面,products/new以便他们可以看到他们刚刚拥有的表单(将信息填回其中如果您使用的是表单生成器),还会看到阻止保存的错误。

我希望这是有道理的,请随时提出后续问题。

于 2013-04-21T15:44:59.837 回答
0

安德鲁的好答案加上这个:
在模型验证失败时在哪里渲染 Rails 中的评论控制器?
使解决方案更加清晰。

您的具体示例:请注意您create在其中的操作ProductsController具有它需要的所有实例变量render 'clients/show'

于 2014-01-24T14:46:56.423 回答
0

是的,你说错了。

存在三个问题:

  1. render应该呈现一个模板名称,比如client/newshared/form等等。参数不能是路径或变量。变量由控制器传递给视图,与render.

  2. 您不应将render其用于保存失败。即使您使用#1 提到的模板名称,您最终也会得到一个错误的 URL,例如products/create客户端页面。这是不可接受的。

    我的建议是始终redirect用于保存失败。

  3. 小问题。在控制器中,如果您使用过@product = @client.products.new,则该@product对象的所有属性都将为空,但具有有效的客户端 ID。因此,您无需再次分配客户端 ID @product.client_id = @client.id。但这不会影响结果。

于 2013-04-21T16:35:14.943 回答