如何将序列添加到迁移并在模型中使用它们?

问题描述:

我想要一个带有正常主键的“Customer”型号,另一列用于存储自定义的“客户编号”。另外,我希望db能够处理默认的客户编号。我认为,定义一个序列是最好的方法。我使用PostgreSQL。看看我的移民:如何将序列添加到迁移并在模型中使用它们?

class CreateAccountsCustomers < ActiveRecord::Migration 
    def up 

    say "Creating sequenze for customer number starting at 1002" 
    execute 'CREATE SEQUENCE customer_no_seq START 1002;' 

    create_table :accounts_customers do |t| 
     t.string :type 
     t.integer :customer_no, :unique => true 
     t.integer :salutation, :limit => 1 
     t.string :cp_name_1 
     t.string :cp_name_2 
     t.string :cp_name_3 
     t.string :cp_name_4 
     t.string :name_first, :limit => 55 
     t.string :name_last, :limit => 55 
     t.timestamps 
    end 

    say "Adding NEXTVAL('customer_no_seq') to column cust_id" 
    execute "ALTER TABLE accounts_customers ALTER COLUMN customer_no SET DEFAULT NEXTVAL('customer_no_seq');" 

    end 

    def down 
    drop_table :accounts_customers 
    execute 'DROP SEQUENCE IF EXISTS customer_no_seq;' 
    end 

end 

如果你知道一个更好的“轨道式”的方法来添加序列,将是真棒,让我知道。现在

,如果我这样做

cust = Accounts::Customer.new 
cust.save 

领域customer_no没有预先填充序列的下一个值(应为1002)。

你知道整合序列的好方法吗?还是有一个很好的插件? 欢呼到所有答案!

我对处理自定义序列的'rails方式'没有任何建议,但我可以告诉你为什么customer_no字段在保存后看起来没有被填充。

当ActiveRecord的节省了一个新的记录,SQL语句只会返回新记录的ID,而不是它的所有领域,你可以看到这个在这里https://github.com/rails/rails/blob/cf013a62686b5156336d57d57cb12e9e17b5d462/activerecord/lib/active_record/persistence.rb#L313

发生在目前的轨道源为了看到价值,你将需要重新加载对象...

cust = Accounts::Customer.new 
cust.save 
cust.reload 

如果你总是希望做到这一点,考虑到您的模型类添加after_create钩...

class Accounts::Customer < ActiveRecord::Base 
    after_create :reload 
end 
+0

太棒了!为我工作。 – Hiasinho

我相信roboles的回答是不正确的。

我试图在我的应用程序(完全相同的env:RoR + PostgreSQL)上实现这一点,我发现当在RoR上发布save时,对象具有空属性,它会尝试对数据库执行INSERT提到所有的VALUES都应该设置为NULL。问题是PostgreSQL处理NULL的方式:在这种情况下,新行将被创建,但所有值都是空的,即DEFAULT将被忽略。如果save只写在RoR上填充的INSERT语句属性上,这将工作正常。

换句话说,只有着眼于上述typecustomer_no属性,这是PostgreSQL的行为的方式:

情况1:

INSERT INTO accounts_customers (type, customer_no) VALUES (NULL, NULL);

(这是如何的Rails 'save作品)

结果:一个空的新行typecustomer_no

情况2:

INSERT INTO accounts_customers (type) VALUES (NULL);

结果:一个新行空typecustomer_no填充序列的NEXTVAL

我有一个线程去上这个,查看:

Ruby on Rails+PostgreSQL: usage of custom sequences

+0

嗯,你说得对。我的错!我为你的帖子添加了书签。让我们看看,会发生什么。 – Hiasinho

+0

我相信这是一个Rails的bug,而Rails 4+就不再是这种情况了(https://github.com/rails/rails/issues/5529) – nfm

我遇到了类似的问题,但我也把:null => false放在场跳中,它会被nextval自动填充。

那么,在我的情况下,AR仍然试图插入NULL如果请求中没有提供任何属性,并且这导致非空约束违例的异常。

这是我的解决方法。我刚刚从@attributes@changed_attributes中删除了该属性键,在这种情况下,postgres正确地将预期序列置于nextval。

我已经把这个模型:如果你正在使用PostgreSQL

before_save do 
    if (@attributes["customer_no"].nil? || @attributes["customer_no"].to_i == 0) 
    @attributes.delete("customer_no") 
    @changed_attributes.delete("customer_no") 
    end 
end 

的Rails 3.2/9.1的Postgres

+0

肮脏的黑客,但工程。 – freemanoid

,看看我写的宝石,pg_sequencer:

https://github.com/code42/pg_sequencer

它提供了一个用于在ActiveRecord迁移中创建,删除和更改序列的DSL。

+0

好的宝石,但不是答案。 – freemanoid