Search code examples
ruby-on-railspostgresqluserid

Rails 4 Secondary ID For Users With STI


In a Rails 4 App users can be of 2 different types, regular or premium, stored with PostgreSQL, using Single Table Inheritance because they have very similar attributes.

When a user (regular) signs up to premium, I would like to be able to keep track of his ":premium_user_id" which would basically be a second :id column in the user table:

  • If user with :id 25 is the first user to sign up to premium, his :premium_user_id is 1
  • If user with :id 57 is the second user to sign up to premium, his :premium_user_id is 2

and so on.

I could add a :premium_user_id column in the User table with an index, and in the premium sign up action call increment that id like so:

current_user.update_attribute :premium_user_id, User.maximum("premium_user_id") + 1

I am not so sure about the fact that this solution needs a DB call each time, but I can't think of a place to store that Max Premium Id to avoid the db call.

Any idea for a better way to implement this?

In particular by implementing this on the Database Level through migrations and SQL statements.

Thank you for your suggestions.


Solution

  • Add migration

    def up
      add_column :users, :premium_user_id, :integer
      execute <<-SQL
        CREATE SEQUENCE premium_user_id_seq START 1;
        ALTER SEQUENCE premium_user_id_seq OWNED BY users.premium_user_id;
        ALTER TABLE users ALTER COLUMN premium_user_id SET DEFAULT nextval('premium_user_id_seq');
      SQL
    end
    
    
    def down
      remove_column :users, :premium_user_id
      execute <<-SQL
        DROP SEQUENCE premium_user_id_seq;
      SQL
    end
    

    Add callback

    class User < ActiveRecord::Base
      after_commit do
        unless read_attribute(:type) == 'premium'
          update_column :premium_user_id, nil
        end
      end
    end