我想要一个带有普通主键的“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)。
您知道整合序列的好方法吗?还是有一个好的插件? 欢呼所有答案!
答案 0 :(得分:11)
我没有关于处理自定义序列的更多“轨道方式”的建议,但我可以告诉您为什么在保存后不会填充customer_no字段。
当ActiveRecord保存新记录时,SQL语句将只返回新记录的ID,而不是其所有字段,您可以在此处查看当前rails源中发生这种情况的位置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
答案 1 :(得分:3)
我相信roboles的答案是不正确的。
我尝试在我的应用程序上实现这个(完全相同的env:RoR + PostgreSQL),我发现当在具有空属性的对象的RoR上发出save
时,它会尝试执行INSERT在数据库中提到所有VALUES都应设置为NULL。问题是PostgreSQL处理NULL的方式:在这种情况下,将创建新行,但所有值都为空,即DEFAULT将被忽略。如果save
仅在RoR上填写的INSERT语句属性上写入,则可以正常工作。
换句话说,只关注上面提到的type
和customer_no
属性,这就是PostgreSQL的行为方式:
情况1:
INSERT INTO accounts_customers (type, customer_no) VALUES (NULL, NULL);
(这是Rails'save
的工作原理)
结果:一个空行type
且空customer_no
情况2:
INSERT INTO accounts_customers (type) VALUES (NULL);
结果:一个空行type
和customer_no
的新行填充了序列的NEXTVAL
我有一个关于此事的线索,请查看:
答案 2 :(得分:2)
我遇到了类似的问题,但我也将:null => false
置于字段跳跃状态,以便自动填充nextval。
好吧,就我而言,如果请求中没有提供任何属性,AR仍然会尝试插入NULL
,这会导致非空约束违规的异常。
这是我的解决方法。我刚从@attributes
和@changed_attributes
删除了此属性键,在这种情况下,postgres正确地将期望的序列设置为nextval。
我把它放在模型中:
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 / Postgres 9.1
答案 3 :(得分:2)
如果您正在使用PostgreSQL,请查看我写的gem,pg_sequencer:
https://github.com/code42/pg_sequencer
它提供了一个DSL,用于在ActiveRecord迁移中创建,删除和更改序列。