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

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

add_index :studies,
["user_id", "university_id", "subject_name_id", "subject_type_id"],
:unique => true

数据库对索引名的限制导致迁移失败。下面是错误信息:

索引名' index_studes_on_user_id_and_university_id_and_subject_name_id_and_subject_type_id '表'studies'太长;限制为64个字符

我该怎么处理呢?我可以指定不同的索引名吗?

125964 次浏览

add_index提供:name选项,例如:

add_index :studies,
["user_id", "university_id", "subject_name_id", "subject_type_id"],
unique: true,
name: 'my_index'

如果在create_table块中使用references上的:index选项,它的值将采用与add_index相同的选项散列:

t.references :long_name, index: { name: :my_index }

类似于前面的答案:只需在常规add_index行中使用'name'键:

def change
add_index :studies, :user_id, name: 'my_index'
end

你也可以

t.index([:branch_id, :party_id], unique: true, name: 'by_branch_party')

Ruby on Rails API

在PostgreSQL中,default限制为63个字符。因为索引名必须是唯一的,所以有一点约定是很好的。我使用(我调整了这个例子来解释更复杂的结构):

def change
add_index :studies, [:professor_id, :user_id], name: :idx_study_professor_user
end

正常指数应该是:

:index_studies_on_professor_id_and_user_id

逻辑是:

  • index变成idx
  • 单表名
  • 无连词
  • 没有_id
  • 字母顺序排列

这通常是可行的。

你可以在create_table块中的列定义中更改索引名(比如你从迁移生成器中获得的)。

create_table :studies do |t|
t.references :user, index: {:name => "index_my_shorter_name"}
end

我有这个问题,但与timestamps函数。它在updated_at上自动生成一个超过63个字符限制的索引:

def change
create_table :toooooooooo_loooooooooooooooooooooooooooooong do |t|
t.timestamps
end
end

索引名' index_toooooooooooo_ooooooooooooooooooooooooooooong_on_updated_at '表' toooooooooo_ooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong '太长;限制为63个字符

我尝试使用timestamps来指定索引名:

def change
create_table :toooooooooo_loooooooooooooooooooooooooooooong do |t|
t.timestamps index: { name: 'too_loooooooooooooooooooooooooooooong_updated_at' }
end
end

然而,这尝试将索引名应用于updated_atcreated_at字段:

表“toooooooooo_ooooooooooooooooooooooooooooooooooooong”上的索引名“too_long_updated_at”已经存在

最后,我放弃了timestamps,只创建了时间戳:

def change
create_table :toooooooooo_loooooooooooooooooooooooooooooong do |t|
t.datetime :updated_at, index: { name: 'too_long_on_updated_at' }
t.datetime :created_at, index: { name: 'too_long_on_created_at' }
end
end

这是可行的,但我很想知道它是否可能与timestamps方法!

create_table:you_table_name do |t| T.references: student, index: {name: 'name_for_studant_index'} T.references:teacher, index: {name: 'name_for_teacher_index'} < / p >结束

恐怕这些方法对我都不起作用。也许是因为我在create_table迁移中使用了belongs_to来进行多态关联。

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

下面的代码没有为我工作:

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

这段代码确实为我工作:

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

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

我有一个经常使用生成器的项目,需要它是自动的,所以我从rails源代码复制了index_name函数来覆盖它。我在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

它会创建像ix_assignments_on_case_id__project_id这样的索引,如果仍然太长,它会将其截断为63个字符。如果表名很长,这仍然是非唯一的,但你可以增加一些复杂的东西,比如分别缩短表名和列名,或者检查唯一性。

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