如何在Ruby on Rails ActiveRecord迁移中处理太长的索引名称?

JJD*_*JJD 369 migration ruby-on-rails

我试图添加一个从四个相关表的外键创建的唯一索引:

add_index :studies,
  ["user_id", "university_id", "subject_name_id", "subject_type_id"],
  :unique => true
Run Code Online (Sandbox Code Playgroud)

数据库对索引名称的限制会导致迁移失败.这是错误消息:

表'研究'上的索引名称'index_studies_on_user_id_and_university_id_and_subject_name_id_and_subject_type_id'太长; 限制为64个字符

我怎么处理这个?我可以指定不同的索引名称吗?

fl0*_*00r 560

提供:name选项add_index,例如:

add_index :studies,
  ["user_id", "university_id", "subject_name_id", "subject_type_id"], 
  :unique => true,
  :name => 'my_index'
Run Code Online (Sandbox Code Playgroud)

如果在块中使用:index选项on ,则它采用与其值相同的选项hash :referencescreate_tableadd_index

t.references :long_name, index: { name: :my_index }
Run Code Online (Sandbox Code Playgroud)

  • 这也适用于Postgres的63个字符限制. (7认同)
  • 对于需要此功能的人,向下语法为`remove_index:studies,:name =>'my_index'`。 (6认同)
  • 也将在ruby 4中使用`name:'my_index'` (3认同)
  • 根据APIdock,名称必须是字符串,而不是符号 (2认同)

Cra*_*ker 168

您还可以更改create_table块中列定义中的索引名称(例如,您从迁移生成器获取).

create_table :studies do |t|
  t.references :user, index: {:name => "index_my_shorter_name"}
end
Run Code Online (Sandbox Code Playgroud)

  • 当我试图在名称间隔表上创建一个多态参考时,这有助于我使用索引`t.references:searchable,polymorphic:true,index:{:name =>"index_searches_on_searchable"}`在这种情况下索引是在事实上,一个多列(searchable_id和searchable_type)以及在生成的名称中添加名称空间变得非常长. (6认同)
  • 请注意,这不会从原始问题创建多列索引; 它只是演示如何从`create_table`缩短长索引名称 (5认同)
  • 也应该有`foreign_key:true`顺便说一下,这是一个很好的解决方案,因为当你使用rails生成器`model:references`格式创建一个迁移文件时,它是最容易使用的 (3认同)

eco*_*gic 36

在PostgreSQL,默认情况下限制为63个字符.因为索引名称必须是唯一的,所以有一点约定是很好的.我使用(我调整了示例来解释更复杂的结构):

def change
  add_index :studies, [:professor_id, :user_id], name: :idx_study_professor_user
end
Run Code Online (Sandbox Code Playgroud)

正常指数应该是:

:index_studies_on_professor_id_and_user_id
Run Code Online (Sandbox Code Playgroud)

逻辑是:

  • indexidx
  • 单数表名称
  • 没有加入的话
  • 没有 _id
  • 按字母顺序

通常这项工作.


tom*_*rad 21

你也可以

t.index([:branch_id, :party_id], unique: true, name: 'by_branch_party')
Run Code Online (Sandbox Code Playgroud)

就像在Ruby on Rails API中一样.


wha*_*ver 6

恐怕这些解决方案都不适合我。也许是因为我belongs_to在 create_table 迁移中使用了多态关联。

我将在下面添加我的代码和解决方案的链接,以防其他人在搜索与多态关联相关的“索引名称太长”时偶然发现。

以下代码对我不起作用:

def change
  create_table :item_references do |t|
    t.text :item_unique_id
    t.belongs_to :referenceable, polymorphic: true
    t.timestamps
  end
  add_index :item_references, [:referenceable_id, :referenceable_type], name: 'idx_item_refs'
end
Run Code Online (Sandbox Code Playgroud)

这段代码对我有用:

def change
  create_table :item_references do |t|
    t.text :item_unique_id
    t.belongs_to :referenceable, polymorphic: true, index: { name: 'idx_item_refs' }

    t.timestamps
  end
end
Run Code Online (Sandbox Code Playgroud)

这是帮助我的 SO Q&A:https : //stackoverflow.com/a/30366460/3258059


Nad*_*sin 5

与上一个答案类似:只需在常规add_index行中使用'name'键:

def change
  add_index :studies, :user_id, name: 'my_index'
end
Run Code Online (Sandbox Code Playgroud)


Jer*_*rph 5

我有一个经常使用生成器的项目,并且需要它是自动的,所以我index_name从 Rails 源复制了该函数来覆盖它。我将其添加到config/initializers/generated_index_name.rb

# make indexes shorter for postgres
require "active_record/connection_adapters/abstract/schema_statements"
module ActiveRecord
  module ConnectionAdapters # :nodoc:
    module SchemaStatements
      def index_name(table_name, options) #:nodoc:
        if Hash === options
          if options[:column]
            "ix_#{table_name}_on_#{Array(options[:column]) * '__'}".slice(0,63)
          elsif options[:name]
            options[:name]
          else
            raise ArgumentError, "You must specify the index name"
          end
        else
          index_name(table_name, index_name_options(options))
        end
      end
    end
  end
end
Run Code Online (Sandbox Code Playgroud)

它会创建类似的索引ix_assignments_on_case_id__project_id,如果仍然太长,则将其截断为 63 个字符。如果表名很长,这仍然是不唯一的,但是您可以添加复杂性,例如与列名分开缩短表名或实际检查唯一性。

注意,这是来自 Rails 5.2 项目;如果您决定这样做,请从您的版本中复制源代码。