How to add sequences to a migration and use them in a model?

Hiasinho picture Hiasinho · Sep 30, 2011 · Viewed 7.3k times · Source

I want to have a "Customer" Model with a normal primary key and another column to store a custom "Customer Number". In addition, I want the db to handle default Customer Numbers. I think, defining a sequence is the best way to do that. I use PostgreSQL. Have a look at my migration:

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

If you know a better "rails-like" approach to add sequences, would be awesome to let me know.

Now, if I do something like

cust = Accounts::Customer.new
cust.save

the field customer_no is not pre filled with the next value of the sequence (should be 1002).

Do you know a good way to integrate sequences? Or is there a good plugin? Cheers to all answers!

Answer

roboles picture roboles · Sep 30, 2011

I have no suggestions for a more 'rails way' of handling custom sequences, but I can tell you why the customer_no field appears not to be being populated after a save.

When ActiveRecord saves a new record, the SQL statement will only return the ID of the new record, not all of its fields, you can see where this happens in the current rails source here https://github.com/rails/rails/blob/cf013a62686b5156336d57d57cb12e9e17b5d462/activerecord/lib/active_record/persistence.rb#L313

In order to see the value you will need to reload the object...

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

If you always want to do this, consider adding an after_create hook in to your model class...

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