2

我有一个有 2 个字段的模型 => :name 和 :age

我需要做一个迁移,添加一个列 :position 需要自动递增并从 0(零)开始。

我尝试了这些方式:

class AddPosition < ActiveRecord::Migration
  def up
    add_column :clientes, :position, :integer, :default => 0, :null => false
    execute "ALTER TABLE clientes ADD PRIMARY KEY (position);"
  end

但它不起作用,因为它不会自动递增。如果我尝试使用主键作为类型:

class AddPosition < ActiveRecord::Migration
  def up
    add_column :clientes, :position, :primary_key, :default => 0, :null => false
  end
end

rake db:migrate 不运行,因为有多个值。

任何人都可以解释一种在带有 Rails 3.2 的主键上设置零和自动增量的方法吗?

4

1 回答 1

2

以下是在 PostgreSQL 中设置自动增量列的方法:

# in migration:
def up
  execute <<-SQL
    CREATE SEQUENCE clients_position_seq START WITH 0 MINVALUE 0;
    ALTER TABLE clients ADD COLUMN position INTEGER NOT NULL DEFAULT nextval('clients_position_seq');
  SQL
end

但不幸的是,它可能不是您所需要的。如果您clients使用 SQL 将值插入到表中,则上述方法将起作用:INSERT INTO clients(name, age) VALUES('Joe', 21),并且 rails 不能以这种方式工作。

第一个问题是 rails 期望调用主键id。虽然您可以覆盖此约定,但它会导致比它解决的问题更多的问题。如果要将位置绑定到主键值,更好的选择是向模型添加虚拟属性,方法如下:

def position
  id.nil? ? nil : id - 1
end

但是让我们假设您已经拥有常规的主键id并想要添加position字段,以便您可以在创建客户端后重新排序客户端,而无需更改其 ID(这始终是一个好主意)。第二个问题出现了:rails 不会识别和尊重DEFAULT nextval('clients_position_seq'),即它不会从 PG 支持的序列中提取值,并且会尝试NULL默认输入position

我想建议将acts_as_list gem视为更好的选择。这将使数据库序列操作变得不必要。不幸的是,它1用作初始值,position但可以通过设置列表位置字段的自定义名称和定义方法来解决,如上所示。

于 2012-09-04T09:18:15.273 回答