提问人:JJD 提问时间:3/27/2011 最后编辑:Jai Kumar RajputJJD 更新时间:9/27/2022 访问量:137139
如何处理 Ruby on Rails ActiveRecord 迁移中过长的索引名称?
How do I handle too long index names in a Ruby on Rails ActiveRecord migration?
问:
我正在尝试添加一个唯一的索引,该索引是从四个相关表的外键创建的:
add_index :studies,
["user_id", "university_id", "subject_name_id", "subject_type_id"],
:unique => true
数据库对索引名称的限制会导致迁移失败。错误消息如下:
表“studies”上的索引名称“index_studies_on_user_id_and_university_id_and_subject_name_id_and_subject_type_id”太长;限制为 64 个字符
我该如何处理?我可以指定不同的索引名称吗?
答:
提供add_index
选项,例如::name
add_index :studies,
["user_id", "university_id", "subject_name_id", "subject_type_id"],
unique: true,
name: 'my_index'
如果对块中的引用
使用该选项,则它采用与其值相同的选项哈希值::index
create_table
add_index
t.references :long_name, index: { name: :my_index }
评论
remove_index :studies, :name => 'my_index'
4.2.6
index: { name: :my_index }
name
与上一个答案类似:只需将“name”键与常规add_index行一起使用:
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 中,默认限制为 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
评论
create_table
t.references :searchable, polymorphic:true, index: {:name => "index_searches_on_searchable"}
foreign_key: true
model:references
我有这个问题,但有这个功能。它自动生成一个超过 63 个字符限制的updated_at索引:timestamps
def change
create_table :toooooooooo_loooooooooooooooooooooooooooooong do |t|
t.timestamps
end
end
表“toooooooooo_loooooooooooooooooooooooooooooong”上的索引名称“index_toooooooooo_loooooooooooooooooooooooooooooong_on_updated_at”太长;限制为 63 个字符
我尝试用于指定索引名称:timestamps
def change
create_table :toooooooooo_loooooooooooooooooooooooooooooong do |t|
t.timestamps index: { name: 'too_loooooooooooooooooooooooooooooong_updated_at' }
end
end
但是,这会尝试将索引名称应用于 and 字段:updated_at
created_at
表“toooooooooo_loooooooooooooooooooooooooooooong”上的索引名称“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 :studant, index: { name: 'name_for_studant_index' } t.references :teacher, index: { name: 'name_for_teacher_index' } 结束
恐怕这些解决方案都不适合我。也许是因为我在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
它会创建索引,如果它仍然太长,则将其截断为 63 个字符。如果表名很长,这仍然是非唯一的,但您可以添加复杂功能,例如将表名与列名分开缩短或实际检查唯一性。ix_assignments_on_case_id__project_id
请注意,这是来自 Rails 5.2 项目;如果您决定这样做,请从您的版本复制源代码。
评论