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

时间:2011-03-26 16:47:06

标签: ruby-on-rails migration

我正在尝试添加一个从四个关联表的外键创建的唯一索引:

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

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

  

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

我该如何处理?我可以指定不同的索引名称吗?

9 个答案:

答案 0 :(得分:512)

add_index提供:name选项,例如:

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

如果在:index块中的references上使用create_table选项,则其值add_index的哈希值与t.references :long_name, index: { name: :my_index } 相同:

{{1}}

答案 1 :(得分:156)

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

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

答案 2 :(得分:32)

在PostgreSQL中,the default limit is 63 characters。因为索引名称必须是唯一的,所以有一点约定是很好的。我使用(我调整了示例来解释更复杂的结构):

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
  • 按字母顺序排列

这通常可以胜任。

答案 3 :(得分:19)

您也可以

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

,如Ruby on Rails API

答案 4 :(得分:5)

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

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

答案 5 :(得分:4)

恐怕这些解决方案都不对我有用。可能是因为我在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

此代码DID对我有用:

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问答:https://stackoverflow.com/a/30366460/3258059

答案 6 :(得分:2)

我有一个项目,该项目大量使用生成器,并且需要自动生成,因此我从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项目;如果您决定这样做,请从您的版本中复制源代码。

答案 7 :(得分:1)

我遇到了这个问题,但是使用了timestamps函数。它是在updated_at上自动生成超过63个字符限制的索引:

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

表“ toooooooooo_loooooooooooooooooooooooooooooooooong”上的索引名“ index_toooooooooo_loooooooooooooooooooooooooooooooong_on_updated_at”太长;限制为63个字符

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

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

但是,这尝试将索引名称同时应用于updated_atcreated_at字段:

  

表“ toooooooooo_loooooooooooooooooooooooooooooooooong”上的索引名称“ 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方法是否可行!

答案 8 :(得分:1)

create_table:you_table_name做| t | t.references:studant,index:{名称:'name_for_studant_index'} t.references:老师,索引:{名称:'name_for_teacher_index'} 结束