Making your Rails web app invite only using devise_invitable

by Andrew Gertig on March 27, 2011

There are many sites and applications that begin their lives as “invite only.” This can be a very effective method of creating a sense of scarcity and at the same time build in a certain amount of curation to your user base. A good current example of a site that is still invite only is Dribble, a site for designers to share their work. The QA site Quora began as an invite only application but recently opened its doors to all comers.

In the Ruby on Rails world the current User authorization hotness is Devise, a gem created by José Valim of Plataformatec (see his great new book here: Crafting Rails Applications). Devise has a great community around it and is built to be modular, only use what you need. One of the pieces that it does not include is a method for sending invitations to new users and this is where the gem devise_invitable by Sergio Cambra comes in with the save.

One of the features that is really useful in an invite only world is to set how many invitations a User is allowed to send. In the Readme on github devise_invitable says that it accomplishes this with the invitation_limit field, the only problem with this piece of documentation is that it refers to something that is not in the current stable release of the devise_invitable gem, which is v0.3.6. To get the added capability of using invitation_limit, invited_by_id, validate_on_invite and invite_key you need to use at least v0.4.rc5. This release candidate currently relies on Devise v1.2.0 so your Gemfile should include the following:
If you are installing Devise for the first time then you should follow the instructions in the Readme here to get it setup, but before you run “rake db:migrate” you should add the line t.invitable to the ####_devise_create_users.rb migration. If you are adding devise_invitable to an app that already has Devise configured then you will need to create a migration that will add the missing fields to your Model. This migration would look like this:

Before you run this migration you should know how the invitation_limit is set in case you decide to handle things differently. To set the default number of invitations that a User can send you will uncomment/add the line config.invitation_limit = 5 to the initializers/devise.rb file (don’t forget to restart your server when in development to apply changes to config). The only drawback to this method by itself is that the number of invitations a User has is not set until they send their first invitation. This means that if you want to display how many invitations a User has left before they send their first one by referencing current_user.invitation_limit it will not display anything until after they have sent their first invitation at which point this would now be equal to 4. If you want to avoid this inconvenience you can change the line in the migration to add a default number for the invitation_limit when a user is created.

t.integer :invitation_limit, :default => 5

If you use this method then you still need to uncomment/add the config.invitation_limit line to your devise.rb initializer but it does not matter what number you set it to as long as it is greater than zero.

Now go invite some people to your web app.

  • Neo

    I spent all evening yesterday searching why devise invitable didn’t set the inveited by property for me and today you wrote about this! Now all I have to do is to test if this is the solution.

  • http://andrewgertig.com Andrew Gertig

    I am glad that I could be of service

  • Anonymous

    Great write up Andrew, I appreciate your taking the time to write this. I’m looking to make it so that only one user in my app can send an unlimited amount of invites, but no one else can. Do you have any ideas as to how I may accomplish this? I was thinking of keeping the default of 0 which I take to mean unlimited, but then that means that everyone else would as well. Maybe setting the rest to -1?

    Also, if I use the database column invitation_limit, do I still have to add the same line in the devise initializer?

    Thanks again!

  • http://andrewgertig.com Andrew Gertig

    Thank you sir.

    Yes, even if you use the column “invitation_limit” you still have to set
    config.invitation_limit = ? in your initializer. I have tried it both ways.

    The way that devise_invitable handles limits is like this:
    :invitation_limit = nil means can send Infinity
    :invitation_limit = 0 means can’t send any invitations
    :invitation_limit = n means can send n invitations

    To accomplish what you are referring to I would suggest setting
    config.invitation_limit => 1 in your devise.rb initializer so that it
    assumes that everyone can send invitations. Then in a migration file like
    the one I show above, set :default => 0, so that every new User that is
    created gets a default of 0 which mean they have “finished” all their
    invitations and can’t send any more. Then whichever User you wish to be able
    to send Infinity I would set their :invitation_limit to nil from the
    console. (Assuming the user_id you care about is 1).

  • Anonymous

    Thanks for the response Andrew.

    I set it up the way you said, config.invitation_limit = 1 in the initializer and applied a migration to set the default to 0. Then I manually did updated_attribute of the specific user I want to have unlimited invites. All new users do correctly get 0 as their invitation limit, however, everytime my gifted user with unlimited invites sends an invite, it still decrements to 0.

    I’m trying to look into a solution, but figured I’d let you know in case we can brainstorm.

  • Anonymous

    Poking around the gem led me to this test: https://gist.github.com/895617

    So if the user’s invitation_limit is nil, it defaults to the config.invitation_limit, I believe. So I’m gonna try setting that to nil, since I already have the table column default to 0 anyways.

  • Anonymous

    I believe I figured out the problem. The migration that set the default to 0 was not letting me set the column to NULL for the gifted user. I fixed this by doing the following:

    ActiveRecord::Base.connection.execute(“update users set invitation_limit = NULL where id = 2″)

    It works fine now, if only there were a way to do it without direct sql but at least it works now. Thanks

  • http://andrewgertig.com Andrew Gertig

    I was just drafting some really hackey solution to this problem in my head
    so I’m really glad your solved it with a fairly normal solution! Thanks for
    letting me know.

  • bennyfreshness

    can you still sign up through the standard “/users/sign_up” route or does devise_invitable disable this 

  • http://andrewgertig.com Andrew Gertig

    Sorry for the late response. Yes you can still use that route, devise_invitable does not disable that. You can manually disable that in your models/user.rb file (assuming that is the name of your model).

  • http://www.facebook.com/tim.koelkebeck Tim Koelkebeck

    You can still sign up this way.

    Andrew – I was hoping this would describe a good way to make the app invite only.  Using invitable in the way you described enables invitations, but anyone can still sign up.

  • http://andrewgertig.com Andrew Gertig

    Hey Tim and Benny, sorry for not catching this question earlier. The way to disable a user from being to walk up to the site and sign up is to remove :registerable from the user model.

    devise :database_authenticatable, :registerable, :recoverable, :rememberable, :trackable, :validatable, :confirmable, :invitable

    becomes

    devise :database_authenticatable, :recoverable, :rememberable, :trackable, :validatable, :confirmable, :invitable

    Everything else should work normally.

Previous post:

Next post: