【问题标题】:HABTM avoid dupe in join tableHABTM 避免在连接表中被欺骗
【发布时间】:2015-01-27 17:17:28
【问题描述】:

我已阅读此问题:has_and_belongs_to_many, avoiding dupes in the join table 但我无法解决我的问题;

我有一个班级TypeProduit,里面有很多ExtensionFichier

class TypeProduit < ActiveRecord::Base
    has_and_belongs_to_many :extension_fichiers
end

和:

class ExtensionFichier < ActiveRecord::Base
  has_and_belongs_to_many :type_produits
end

他们是相关的,感谢

class LinkExtensionFichiers < ActiveRecord::Migration
  def change
     create_join_table :extension_fichiers, :type_produits
  end
end

编辑:

这是[正确的]控制器:

class TypeProduitsController < ApplicationController
before_action :set_type_produit, only: [:show, :edit, :update, :destroy]

# GET /type_produits
# GET /type_produits.json
def index
  @type_produits = TypeProduit.all
end

# GET /type_produits/1
# GET /type_produits/1.json
def show
end

# GET /type_produits/new
def new
  @type_produit = TypeProduit.new
end

# GET /type_produits/1/edit
def edit
end

# POST /type_produits
# POST /type_produits.json
def create
  @type_produit = TypeProduit.new(type_produit_params)

  puts "------extension_fichier_params------"
  puts extension_fichier_params

  #@type_produit.extension_fichier_ids = extension_fichier_params

  @type_produit.extension_fichiers << ExtensionFichier.find_by(:id => extension_fichier_params)

  respond_to do |format|
    if @type_produit.save
      format.html { redirect_to @type_produit, notice: 'Type produit was successfully created.' }
      format.json { render :show, status: :created, location: @type_produit }
    else
      format.html { render :new }
      format.json { render json: @type_produit.errors, status: :unprocessable_entity }
    end
  end
end

# PATCH/PUT /type_produits/1
# PATCH/PUT /type_produits/1.json
def update
  respond_to do |format|
    if @type_produit.update(type_produit_params)
      format.html { redirect_to @type_produit, notice: 'Type produit was successfully updated.' }
      format.json { render :show, status: :ok, location: @type_produit }
    else
      format.html { render :edit }
      format.json { render json: @type_produit.errors, status: :unprocessable_entity }
    end
  end
end

# DELETE /type_produits/1
# DELETE /type_produits/1.json
def destroy
  @type_produit.destroy
  respond_to do |format|
    format.html { redirect_to type_produits_url, notice: 'Type produit was successfully destroyed.' }
    format.json { head :no_content }
  end
end

private
  # Use callbacks to share common setup or constraints between actions.
  def set_type_produit
    @type_produit = TypeProduit.find(params[:id])
  end

  def extension_fichier_params
    @type_produit.extension_fichier_ids
  end

  # Never trust parameters from the scary internet, only allow the white list through.
  def type_produit_params
    params.require(:type_produit).permit(:nom, :extension_fichier_ids => [])
  end
end

这是 Rails 服务器输出:

Started POST "/type_produits" for 127.0.0.1 at 2015-01-27 17:55:15 +0100
Processing by TypeProduitsController#create as HTML
  Parameters: {"utf8"=>"✓", "authenticity_token"=>"4LBhwTvGjXOq+3qzO+loGUV/oBCYjW66aVDeE1Zj/AM=", "type_produit"=>{"nom"=>"qsdfqsdf", "extension_fichier_ids"=>["1", "2", ""]}, "commit"=>"Create Type produit"}
  ExtensionFichier Load (0.4ms)  SELECT "extension_fichiers".* FROM "extension_fichiers"  WHERE "extension_fichiers"."id" IN (1, 2)
------extension_fichier_params------
1
2
  ExtensionFichier Load (0.2ms)  SELECT  "extension_fichiers".* FROM "extension_fichiers"  WHERE "extension_fichiers"."id" IN (1, 2) LIMIT 1
   (0.1ms)  begin transaction
  TypeProduit Exists (0.1ms)  SELECT  1 AS one FROM "type_produits"  WHERE "type_produits"."nom" = 'qsdfqsdf' LIMIT 1
  SQL (0.4ms)  INSERT INTO "type_produits" ("created_at", "nom", "updated_at") VALUES (?, ?, ?)  [["created_at", "2015-01-27 16:55:15.923132"], ["nom", "qsdfqsdf"], ["updated_at", "2015-01-27 16:55:15.923132"]]
  SQL (0.1ms)  INSERT INTO "extension_fichiers_type_produits" ("extension_fichier_id", "type_produit_id") VALUES (?, ?)  [["extension_fichier_id", 1], ["type_produit_id", 8]]
  SQL (0.1ms)  INSERT INTO "extension_fichiers_type_produits" ("extension_fichier_id", "type_produit_id") VALUES (?, ?)  [["extension_fichier_id", 2], ["type_produit_id", 8]]
  SQL (0.0ms)  INSERT INTO "extension_fichiers_type_produits" ("extension_fichier_id", "type_produit_id") VALUES (?, ?)  [["extension_fichier_id", 1], ["type_produit_id", 8]]
   (0.5ms)  commit transaction

为什么只有 2 个对象的 rails 会插入 3 个对象

【问题讨论】:

  • 您正在显示用于创建 TypeProduit 对象的模型和日志,但您的控制器是用于创建 Produit 对象的代码。要正确诊断此问题,我们需要查看 TypeProduitsController
  • @smathy 你是对的,愚蠢的复制/粘贴。现在已经修复了
  • 您的代码看起来正确,您应该检查一下您的 extension_fichiers 表中 id 1 是否没有重复记录:ExtensionFichier.find_by(:id =&gt; [1,2]) 不过这似乎不太可能。
  • @ThomasGuillory 在数据库中没有欺骗:/

标签: ruby-on-rails ruby


【解决方案1】:

您的控制器代码中有一个非常明显的错误。让我们逐步完成您的create 操作。

您从type_produit_params 创建一个新的TypeProduit,其中包括:nom :extension_fichier_ids。然后你输出extension_fichier_params 的值,它本身就是@type_produit.extension_fichier_ids,你得到"1\n2\n",所以你的@type_produit 已经附加了这两个extension_fichiers。

然后将ExtensionFichier.find_by(:id =&gt; extension_fichier_params) 附加到@type_produit.extension_fichier_ids。现在 find_by 基本上是 where().first 所以它只得到第一个,即。身份证=1。所以现在在您的@type_produit.extension_fichiers 数组中,您又拥有了 1、2 和 1 的 ID。 IE。三个对象。

然后您保存TypeProduit,所有这三个关联都与三个INSERTs 一起保存。

是的,对此的整体解决方案(除了修复您不必要的 &lt;&lt; 代码或添加 1 和 2 的模型或视图)是将 -&gt; { uniq } 范围添加到您的 habtm 关联中每https://stackoverflow.com/a/20226630/152786

【讨论】:

    【解决方案2】:

    您是否尝试过using-uniq-in-a-has-and-belongs-to-many-relationship-in-rails-4 建议的解决方案(也许还按照has-and-belongs-to-many-avoiding-dupes-in-the-join-table 的建议添加索引?)

    【讨论】:

    • 第二个链接是我在问题中谈到的那个,uniq: true 不起作用,但谢谢!
    猜你喜欢
    • 2010-11-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-02-22
    • 2018-07-27
    • 2021-05-25
    相关资源
    最近更新 更多