【问题标题】:Rails changing table name in has_and_belongs_to_manyRails 在 has_and_belongs_to_many 中更改表名
【发布时间】:2017-02-07 02:57:38
【问题描述】:

我有两个型号StageBatchStageItem

class StageItem < ApplicationRecord
  has_and_belongs_to_many :stage_batches
end

class StageBatch < ApplicationRecord
  has_and_belongs_to_many :stage_items
end

使用以下迁移:

class CreateStageBatchesAndStageItems < ActiveRecord::Migration[5.0]
  def change
    create_table :stage_items do |t|
      t.string :name
      t.timestamps
    end

    create_table :stage_batches do |t|
      t.timestamps
    end

    create_table :stage_batches_and_stage_items, id: false do |t|
      t.belongs_to :stage_item, index: true
      t.belongs_to :stage_batch, index: true
    end
  end
end

当我尝试访问 stage_batches stage_items 时,出现以下错误:

irb(main):002:0> StageBatch.first.stage_items
  StageBatch Load (0.2ms)  SELECT  "stage_batches".* FROM "stage_batches" ORDER BY "stage_batches"."id" ASC LIMIT ?  [["LIMIT", 1]]
  StageItem Load (0.4ms)  SELECT "stage_items".* FROM "stage_items" INNER JOIN "stage_batches_items" ON "stage_items"."id" = "stage_batches_items"."stage_item_id" WHERE "stage_batches_items"."stage_batch_id" = ?  [["stage_batch_id", 1]]
ActiveRecord::StatementInvalid: SQLite3::SQLException: no such table: stage_batches_items: SELECT "stage_items".* FROM "stage_items" INNER JOIN "stage_batches_items" ON "stage_items"."id" = "stage_batches_items"."stage_item_id" WHERE "stage_batches_items"."stage_batch_id" = ?
  • 我的迁移有问题吗?
  • 命名约定有问题吗?
  • 为什么我的表的名称似乎从 stage_batches_and_stage_items 更改为 ` 我的迁移有问题吗?
  • 命名约定有问题吗?为什么我的表的名称似乎从 stage_batches_and_stage_items 更改为 stage_batches_items

【问题讨论】:

    标签: ruby-on-rails activerecord sqlite


    【解决方案1】:

    在使用has_and_belongs_to_many 时,您必须遵循Rails 命名约定来命名连接表。或者,您可以使用 join_table 选项指定连接表名称。

    在您的特定情况下,将stage_batches_and_stage_items 的名称更改为stage_batches_stage_items。默认情况下,连接表的两个表名(复数形式)按词法顺序排列。

    来自Rails guide [Section 3.3.2]

    如果你创建了一个 has_and_belongs_to_many 关联,你需要 显式创建连接表。除非连接表的名称 使用 :join_table 选项显式指定,Active Record 通过使用类名的词汇书创建名称。所以一个 作者和书籍模型之间的连接将给出默认的连接表 “authors_books”的名称,因为“a”在词汇排序上优于“b”。

    我建议避免使用has_and_belongs_to_many,如果这不是硬性要求,因为它的限制(例如,您不能在此连接表中添加任何额外的列。)而是使用has_many :through 关联。在这种情况下,您可以轻松自定义连接表名称。此外,您可以根据需要向连接表添加额外的列。

    下面是使用has_many :through关联的代码:

    class StageItem < ApplicationRecord
      has_many :stage_item_batches
      has_many :stage_batches, through: :stage_item_batches
    end
    
    # joining model
    class StageItemBatch < ApplicationRecord
      belongs_to :stage_item
      belongs_to :stage_batch
    end
    
    class StageBatch < ApplicationRecord
      has_many :stage_item_batches
      has_many :stage_items, through: :stage_item_batches
    end
    

    原始两个模型的迁移将保持不变。您只需要迁移加入模型:

    rails g model StageItemBatch stage_item:references stage_batch:references
    

    【讨论】:

    • +1 以获得清晰的解释、有用的链接和有关前进的有用建议。也希望使用has_many :through 的示例实现
    • 将很快用has_many :through 示例更新我的答案。
    • 能否也包括相关的迁移?
    • 当然。原始两个模型的迁移将保持不变。您只需要迁移加入模型:rails g model StageItemBatch stage_item:references stage_batch:references
    • 是命名它StageItemBatch而不是StageItemStageBatch的约定?
    猜你喜欢
    • 2014-02-28
    • 1970-01-01
    • 1970-01-01
    • 2012-01-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-21
    • 2010-10-21
    相关资源
    最近更新 更多