首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Rails 5 find_or_create仍在创建重复项

Rails 5 find_or_create仍在创建重复项
EN

Stack Overflow用户
提问于 2018-03-05 20:12:05
回答 3查看 921关注 0票数 1

我有一个'gin‘模型,允许嵌套属性’名称‘在’酒厂‘模型。嵌套表单运行良好,但我意识到我正在创建“复制”酒厂条目。看来'find_or_create_by‘应该可以防止这一点,,但我不能让它不创建一个副本.

因为这是一个嵌套的表单,所以我也不确定应该放置哪个控制器。

这是我到目前为止所拥有的,正如前面提到的,这将继续为一家酿酒厂创造多种记录。我没有任何错误。

gins_controller.rb

代码语言:javascript
复制
class GinsController < ApplicationController

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

distillery_controller.rb

代码语言:javascript
复制
class DistilleriesController < ApplicationController
 ...
  def new
    @distillery = Distillery.find_or_create_by(name: 'name')
  end

gins_form

代码语言:javascript
复制
<%= 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中,但它没有解决这个问题:

代码语言:javascript
复制
  def new
    @gin = Gin.new
    @gin.build_distillery
    @distillery = Distillery.find_or_create_by(name: 'name')
  end
EN

回答 3

Stack Overflow用户

发布于 2018-03-06 01:53:09

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

您应该在create方法中使用,在该方法中,记录实际上是创建一个保存的。

另一种方法是将酿酒厂名称定义为一个独特的字段,因此不能创建重复的酿酒厂。

第三种选择是使用select字段以形式选择酒厂(这要求在创建杜松子酒之前创建酿酒厂)。一般来说,这应该是最好的方法:如果Gin belongs_to :蒸馏器(我假设),最好选择酿酒厂,而不是在字段中输入名称。如果您做了一个错误,您将创建一个新的酿酒厂,而不是使用一个现有的。

票数 2
EN

Stack Overflow用户

发布于 2018-03-06 03:40:53

我同意巴勃罗的看法。下面是如何实现新/创建方法的一个想法--如果您想让大部分代码保持不变

代码语言:javascript
复制
 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
票数 0
EN

Stack Overflow用户

发布于 2018-03-18 10:46:28

由于您没有具体说明这一点,我假设您的协会如下所示:

代码语言:javascript
复制
class Gin
  belongs_to :distillery 

class Distillery
  has_many :gins 

一般来说,在这种情况下,你要做的就是从下拉列表中选择一个酿酒厂。因此,我们将直接设置链接(distillery_id),因此在模型Gin中不需要accepts_nested_attributes_for

如果您使用的是简单形式的宝石,这就像使用简单的宝石一样简单。

代码语言:javascript
复制
 f.association :distillery 

或者使用普通形式,您可以编写如下内容

代码语言:javascript
复制
f.collection_select :distillery_id, Distillery.all, :id, :name, {include_blank: true}

到目前为止,您不需要在控制器端做任何特别的事情:当保存表单时,它会设置酿酒厂id,这将创建链接。但它也假设酿酒厂已经存在(在大多数情况下都是如此)。

当你想要连接到一个现有的酒厂或者以一种形式创建一个新的酒厂时,它会变得更加复杂。

要解决这个问题,一个非常简单的解决方案是按以下方式编写表单:

代码语言:javascript
复制
= f.collection_select :distillery_id, Distillery.all, :id, :name, {include_blank: true}
= text_field_tag :distillery_name  

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

然后在你的控制器里你可以做一些类似的事情

代码语言:javascript
复制
def create
  if params[:gin][:distillery_id].blank? && params[:distillery_name].present?
    @distillery = Distillery.find_or_create_by(name: params[:distillery_name])
    params[:gin][:distillery_id] = @distillery.id 
  end 
  gin = Gin.build(gin_params) 
  [... the rest of your create method as before ...]

因此,简而言之:

  • 我们检查用户是否从下拉列表中选择了一个酿酒厂(如果是,只需使用它),并给出一个新的名称。
  • 使用给定的名称,尝试找到酿酒厂或创建一个新的酒厂。
  • 在表格中填写酒厂的标识。
  • 然后像以前一样保存表单数据。
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/49118664

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档