Rails 5 find_or_create仍在创建重复项

时间:2018-03-05 20:12:06

标签: ruby-on-rails nested-forms

我有一个'gin'模型,它允许'酿酒'模型中'name'的嵌套属性。嵌套表单运行良好,但我意识到我正在创建“重复”的酿酒厂条目。似乎'find_or_create_by'应该阻止这个,但是我不能让它不能创建副本。

由于这是一个嵌套的形式,我也不确定应该放置哪个控制器。

这是我到目前为止所提到的,如上所述,这继续为酿酒厂创造多个记录。我没有任何错误。

gins_controller.rb

class GinsController < ApplicationController

...
  def new
    @gin = Gin.new
    @gin.build_distillery
  end

distillery_controller.rb

class DistilleriesController < ApplicationController
 ...
  def new
    @distillery = Distillery.find_or_create_by(name: 'name')
  end

gins_form

<%= form.fields_for :distillery do |distillery_form| %>
  <p>
    <%= distillery_form.label :distillery, class: "block text-grey-darker text-sm font-bold mb-2" %>
    <%= distillery_form.text_field :name, class:"lg:w-2/5 w-full shadow appearance-none border rounded py-2 px-3 mb-6 text-grey-darker" %>
  </p>
<% end %>

更新

已将其移至gins_controller但未解决此问题:

  def new
    @gin = Gin.new
    @gin.build_distillery
    @distillery = Distillery.find_or_create_by(name: 'name')
  end

3 个答案:

答案 0 :(得分:2)

new方法用于创建要在视图中显示的新对象(用于在数据库中创建记录的输入数据的表单)。但new方法不会将对象保存到数据库。因此,在new方法中使用 find_or_create 是没有意义的。只需使用构建

您应该在创建方法中使用find_or_create,其中记录实际上已创建为已保存。

另一种方法是将酿酒厂名称定义为唯一字段,因此您无法创建重复的酿酒厂。

第三个选项是您使用选择字段选择表单中的酿酒库(这要求在创建杜松子酒之前创建酿酒厂)。一般来说,这应该是最好的方法:如果Gin belongs_to:酒厂(我假设),最好选择酿酒厂而不是在田间输入名称。如果你打错了,你将创建一个新的酿酒厂,而不是使用现有的酿酒厂。

答案 1 :(得分:0)

我同意巴勃罗的观点。 如果您要将大部分代码保持相同

,请了解如何实现new / create方法
 def new
    @gin = Gin.new
    @gin.build_distillery
 end
 def create
    @gin = Gin.new(gin_params)
    @gin.distillery = Distillery.find_or_create_by(name: distillery_name)
    @gin.save! # oversimplification - you probably have respond blocks
 end

 def distillery_name
   params[:distillery][:name] # or however it really is
 end

答案 2 :(得分:0)

由于您没有指定,我假设您的关联如下:

=SUM(N(MMULT(N(A1:E5="Y"),TRANSPOSE(COLUMN(A1:E5)^0))=0))

现在一般来说,在这种情况下你要做的只是从下拉列表中选择一个酿酒厂。因此,我们会直接设置链接(class Gin belongs_to :distillery class Distillery has_many :gins ),因此我们在模型distillery_id中不需要accepts_nested_attributes_for

如果你使用简单形式的宝石,这就像

一样简单
Gin

或使用普通表格,您可以写一些类似

的内容
 f.association :distillery 

到目前为止,您不必在控制器端执行任何特殊操作:保存表单时,它会设置酒厂ID,这将创建链接。但它也假设酿酒厂已经存在(在大多数情况下都是如此)。

当您希望能够链接到现有的酿酒厂以一种形式创建新的酿酒厂时,它会变得更加复杂。

一个非常简单的解决方案是按如下方式编写表单:

f.collection_select :distillery_id, Distillery.all, :id, :name, {include_blank: true}

(为了获得最佳用户体验,您需要添加一些js洒,以确保用户可以从下拉列表中选择内容或填写名称)

然后在您的控制器中,您可以执行类似

的操作
= f.collection_select :distillery_id, Distillery.all, :id, :name, {include_blank: true}
= text_field_tag :distillery_name  

简而言之:

  • 我们检查用户是否从下拉列表中选择了一个酿酒厂(如果是,只需使用它)已经给出了一个新名称
  • 使用给定的名称,尝试找到酿酒厂或创建一个新的
  • 的形式填写酒厂ID
  • 然后只需保存表单数据