【问题标题】:How do I handle too long index names in a Ruby on Rails ActiveRecord migration?如何在 Ruby on Rails ActiveRecord 迁移中处理过长的索引名称?
【发布时间】:2011-07-23 13:24:42
【问题描述】:

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

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 个字符

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

【问题讨论】:

    标签: ruby-on-rails migration


    【解决方案1】:

    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 }
    

    【讨论】:

    • 根据 APIdock,名称必须是字符串,而不是符号
    • 向下语法是remove_index :studies, :name => 'my_index',供任何需要的人使用
    • On Rails 4.2.6index: { name: :my_index } 一起使用。只有name 不起作用。
    【解决方案2】:

    您还可以更改 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"} 的名称间隔表上创建多态引用时,这对我很有帮助,在这种情况下,索引实际上是一个多列(searchable_id 和 searchable_type),并且在生成的名称中添加命名空间变得很长。
    • 对我来说很好,紧凑的解决方案。谢谢!
    • 还应该有foreign_key: true 顺便说一句,这是一个很好的解决方案,因为当您使用rails 生成器model:references 格式创建迁移文件时,它是最容易使用的
    【解决方案3】:

    在 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
    • 字母顺序

    这通常是做什么的。

    【讨论】:

    • 感谢分享。如果您可以链接 Postgres 文档以了解限制事实,那就太好了。
    • 我们是否需要索引名中的表名,因为索引无论如何都属于该表?只是好奇这是否对我没见过的地方有益。
    • 您可以为索引命名您想要的任何名称,但我认为索引名称中的表名有助于保持索引名称的唯一性(这是强制性的),良好的范围并提高了一些错误消息的可读性。
    【解决方案4】:

    你也可以这样做

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

    Ruby on Rails API

    【讨论】:

      【解决方案5】:

      与上一个答案类似:只需在常规 add_index 行中使用“名称”键即可:

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

      【讨论】:

        【解决方案6】:

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

        【讨论】:

          【解决方案7】:

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

          【讨论】:

            【解决方案8】:

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

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

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

            【讨论】:

              【解决方案9】:

              create_table :you_table_name 做 |t| t.references :studant, index: { name: 'name_for_studant_index' } t.references :teacher, index: { name: 'name_for_teacher_index' } 结束

              【讨论】:

                猜你喜欢
                • 2020-04-10
                • 2012-01-18
                • 2011-10-12
                • 1970-01-01
                • 2019-02-13
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多