Skip to content

About

An invitation strategy for devise

Topics

Resources

Stars

2.7k stars

Watchers

35 watching

Forks

Repository files navigation

DeviseInvitable

It adds support to Devise for sending invitations by email (it requires to be authenticated) and accept the invitation setting the password.

Requirements

The latest version of DeviseInvitable requires Ruby >= 2.7, Rails >= 7.0, and Devise >= 5.0.

Use DeviseInvitable 2.x with Devise 4.6 through 4.9. For earlier Devise 4 releases, use DeviseInvitable 1.7.5.

Installation

Install DeviseInvitable gem:

gem install devise_invitable

Add DeviseInvitable to your Gemfile:

gem 'devise_invitable', '~> 3.0'

Automatic installation

Run the following generator to add DeviseInvitable’s configuration option in the Devise configuration file (config/initializers/devise.rb):

rails generate devise_invitable:install

When you are done, you are ready to add DeviseInvitable to any of your Devise models using the following generator:

rails generate devise_invitable MODEL

Replace MODEL by the class name you want to add DeviseInvitable, like User, Admin, etc. This will add the :invitable flag to your model's Devise modules. The shared invitations table is created by the install generator, so the model generator does not create a migration.

Manual installation

Follow the walkthrough for Devise and after it's done, follow this walkthrough.

Devise Configuration

Add :invitable to the devise call in your model (we’re assuming here you already have a User model with some Devise modules):

class User < ActiveRecord::Base
  devise :database_authenticatable, :confirmable, :invitable
end

Active Record schema

Invitations are stored in the shared devise_invitations table generated by devise_invitable:install. It contains the token and lifecycle timestamps, the configured invite keys, and polymorphic invitable and invited_by associations. Invitation columns are not added to each Devise model.

Run the generated migration:

rails db:migrate

Upgrading from resource-backed invitation columns

Generate one upgrade migration for every model that already uses :invitable:

rails generate devise_invitable:upgrade User
rails db:migrate

Pass every configured invite key when it is not just email:

rails generate devise_invitable:upgrade User --invite-keys email username

The generated migration creates the shared table if necessary, copies existing invitation data, and removes the old invitation lifecycle and invited_by columns. It intentionally leaves invitation_limit and invitations_count alone because those describe inviters rather than individual invitations. Its down direction is irreversible because multiple invitations cannot be moved losslessly back onto one resource row.

Mongoid

Mongoid fields and indexes for DeviseInvitable::Invitation are defined by the gem. Create the indexes after deployment:

rake db:mongoid:create_indexes

To migrate legacy embedded invitation fields for a model, run:

rails devise_invitable:migrate_invitations[User]

Model configuration

DeviseInvitable adds some new configuration options:

  • invite_for: The period the generated invitation token is valid. After this period, the invited resource won't be able to accept the invitation. When invite_for is 0 (the default), the invitation won't expire.

You can set this configuration option in the Devise initializer as follow:

# ==> Configuration for :invitable
# The period the generated invitation token is valid.
# After this period, the invited resource won't be able to accept the invitation.
# When invite_for is 0 (the default), the invitation won't expire.
# config.invite_for = 2.weeks

or directly as parameters to the devise method:

devise :database_authenticatable, :confirmable, :invitable, invite_for: 2.weeks
  • invitation_limit: The number of invitations users can send. The default value of nil means users can send as many invites as they want, there is no limit for any user, invitation_limit column is not used. A setting of 0 means they can't send invitations. A setting n > 0 means they can send n invitations. You can change invitation_limit column for some users so they can send more or less invitations, even with global invitation_limit = 0. This setting controls how many invitations an inviter may send; use authenticate_inviter! for authorization and other application-specific conditions.

  • invite_key: The key to be used to check existing users when sending an invitation. You can use multiple keys. This value must be a hash with the invite key as hash keys, and values that respond to the === operator (including procs and regexes). The default value is looking for users by email and validating with Devise.email_regexp.

  • validate_on_invite: with placeholder creation enabled, force the resource to be valid before it is invited. Deferred invitations validate their invite keys because no resource is persisted yet.

  • resend_invitation: resend invitation if user with invited status is invited again. Enabled by default.

  • invited_by_class_name and invited_by_foreign_key are deprecated and have no effect. This applies to both initializer configuration and options passed to devise :invitable on a model. Invitations always use the polymorphic invited_by_id and invited_by_type columns in the shared invitations table.

  • create_resource_on_invitation: create a placeholder resource when the invitation is sent. It is disabled by default, so only the invitation record is persisted while invite keys remain in the encrypted acceptance token. Enable it when the application needs an addressable resource before signup or needs to store additional permitted resource attributes from the invitation form. Arbitrary resource attributes are rejected when this is disabled.

  • store_invite_keys_until_delivery: temporarily store invite keys in the invitation record so a skipped, resource-less invitation can be loaded and delivered later. It is disabled by default. Stored keys are cleared after successful delivery, when they are available in the encrypted acceptance token.

  • deliver_invitation_later: enqueue invitation emails with the configured invitation delivery job. It is disabled by default, preserving the normal send_devise_notification hook.

  • invitation_delivery_job: job class used by Invitation#deliver_later. It may be a class or class name and must respond to perform_later. The default is DeviseInvitable::InvitationDeliveryJob.

  • invitation_delivery_queue_name: queue used by the default invitation delivery job. The default is :mailers.

  • supersede_other_invitations_on_accept: supersede other pending invitations for the same invite keys when one is accepted. Enabled by default. Disable it only when each invitation carries independently acceptable application context. Remaining invitations are linked to the provisioned resource and their tokens stay valid; accepting them does not require or change the resource's password.

  • invited_by_counter_cache: the column name used for counter_cache column. If this is nil (default value), the invited_by association is declared without counter_cache.

  • allow_insecure_sign_in_after_accept: automatically sign in the user after they set a password. Enabled by default.

  • require_password_on_accepting: require password when user accepts the invitation. Enabled by default. Disable if you don't want to ask or enforce to set password while accepting, because is set when user is invited or it will be set later.

For more details, see config/initializers/devise.rb (after you invoked the devise_invitable:install generator described above).

Configuring views

All the views are packaged inside the gem. If you'd like to customize the views, invoke the following generator and it will copy all the views to your application:

rails generate devise_invitable:views

You can also use the generator to generate scoped views:

rails generate devise_invitable:views users

Then turn scoped views on in config/initializers/devise.rb:

config.scoped_views = true

Please refer to Devise's README for more information about views.

Configuring controllers

To change the controller's behavior, create a controller that inherits from Devise::InvitationsController. The available methods are: new, create, edit, and update. Refer to the original controllers source before editing any of these actions. Your controller might now look something like this:

class Users::InvitationsController < Devise::InvitationsController
  def update
    if some_condition
      redirect_to root_path
    else
      super
    end
  end
end

Now just tell Devise that you want to use your controller, the controller above is 'users/invitations', so our routes.rb would have this line:

devise_for :users, controllers: { invitations: 'users/invitations' }

The invitations controller prepends its authentication, invitation-limit, and token-loading callbacks. These callbacks may render or redirect and halt the callback chain before an ordinary callback inherited from ApplicationController runs. If application context must be available even when one of these guards halts the request, prepend that setup in the custom invitations controller. For example, an around callback can set and restore the locale so flash messages created by the guards use the requested locale:

class Users::InvitationsController < Devise::InvitationsController
  prepend_around_action :use_locale

  private

    def use_locale(&action)
      I18n.with_locale(locale_from_request, &action)
    end

    def locale_from_request
      params[:locale].presence_in(I18n.available_locales.map(&:to_s)) ||
        I18n.default_locale
    end
end

The same ordering rule applies to tenant selection, request tracing, and other setup that must run before Devise Invitable's controller guards.

be sure that you generate the views and put them into the controller that you generated, so for this example it would be:

rails generate devise_invitable:views users

To change behaviour of inviting or accepting users, you can simply override two methods:

class Users::InvitationsController < Devise::InvitationsController
  private

    # This is called when creating invitation.
    # It should return an instance of resource class.
    def invite_resource
      # skip sending emails on invite
      super { |user| user.skip_invitation = true }
    end

    # This is called when accepting invitation.
    # It should return an instance of resource class.
    def accept_resource
      resource = resource_class.accept_invitation!(update_resource_params)
      # Report accepting invitation to analytics
      Analytics.report('invite.accept', resource.id)
      resource
    end
end

Strong Parameters

When you customize your own views, you may end up adding new attributes to forms. Rails 4 moved the parameter sanitization from the model to the controller, causing DeviseInvitable to handle this concern at the controller as well. Read about it in Devise README

There are just two actions in DeviseInvitable that allows any set of parameters to be passed down to the model, therefore requiring sanitization. Their names and the permited parameters by default are:

  • invite (Devise::InvitationsController#create) - Permits only the authentication keys (like email)
  • accept_invitation (Devise::InvitationsController#update) - Permits invitation_token plus password and password_confirmation.

Here is an example of the steps needed to add a first_name, last_name and role to invited Users.

Caution: Adding roles requires additional security measures, such as preventing a standard user from inviting an administrator. Implement appropriate access controls to ensure system security.

Configuring your application controller to accept :first_name, :last_name, and :role for a User

Note: These modifications can be applied directly in the InvitationsController if not needed for other Devise actions.

  before_action :configure_permitted_parameters, if: :devise_controller?

  protected

  # Permit the new params here.
  def configure_permitted_parameters
    devise_parameter_sanitizer.permit(:invite, keys: [:first_name, :last_name, :role])
  end

Define your roles in the User model

class User < ApplicationRecord
  has_many :models

  enum role: {Role 1 Name: 0, Role 2 Name: 1, Role 3 Name: 2, etc...}
end

In the Invitation view

<h2><%= t "devise.invitations.new.header" %></h2>

<%= form_for(resource, as: resource_name, url: invitation_path(resource_name), html: { method: :post }) do |f| %>
  <%= render "devise/shared/error_messages", resource: resource %>
  <% resource.class.invite_key_fields.each do |field| -%>
    <div class="field">
      <%= f.label field %><br />
      <%= f.text_field field %>
    </div>
  <% end %>

  <div class="field">
    <%= f.label :first_name %>
    <%= f.text_field :first_name %>
  </div>

  <div class="field">
    <%= f.label :last_name %>
    <%= f.text_field :last_name %>
  </div>

  <div class="field">
    <%= f.label :role %>
    <%= f.select :role, options_for_select(User.roles.map { |key, value| [key.humanize, key] }), {prompt: "Select Role"} %>
  </div>

  <div class="actions">
    <%= f.submit t("devise.invitations.new.submit_button") %>
  </div>
<% end %>

Usage

Send an invitation

To send an invitation to a user, use the invite! class method. :email must be present in the parameters hash. By default this stores an invitation without creating a user. Set create_resource_on_invitation: true on the Devise model to create a placeholder user immediately and allow other resource attributes.

User.invite!(email: 'new_user@example.com')
# => an invitation email will be sent to new_user@example.com

To persist additional resource attributes, enable placeholders:

class User < ApplicationRecord
  devise :database_authenticatable, :invitable,
    create_resource_on_invitation: true
end

User.invite!(email: 'new_user@example.com', name: 'John Doe')

Multiple invitations can be sent for the same invite keys. Accepting one marks that invitation accepted and supersedes the others. If the invitee registers directly, all matching pending invitations are superseded rather than marked accepted.

Pass application context with an invitation

Small application-specific values can be carried in the encrypted acceptance token with the invitation_data option:

User.invite!(
  { email: 'new_user@example.com' },
  current_user,
  invitation_data: { organization_id: organization.id, role: 'member' }
)

invitation_data must be a JSON-compatible hash whose serialized form is no larger than 1,024 bytes. It is deliberately not persisted by devise_invitable. After token decoding, JSON object keys are strings. The data is available as current_invitation.invitation_data in invitation callbacks and controller code. For example:

after_invitation_created do |user|
  InvitationContext.create!(
    devise_invitation: user.current_invitation,
    data: user.current_invitation.invitation_data
  )
end

after_invitation_accepted do |user|
  organization_id = user.current_invitation.invitation_data['organization_id']
  user.memberships.find_or_create_by!(organization_id: organization_id)
end

Persist the context in an application model when it must survive independently of the email link, be processed after another invitation is accepted, or be combined with other invitations. Keep it URL-only when each invitation should be accepted separately. To preserve the other links in that case:

class User < ApplicationRecord
  devise :database_authenticatable, :invitable,
    supersede_other_invitations_on_accept: false
end

The first accepted invitation provisions the resource normally. Later invitations run the acceptance callbacks with their own invitation_data, but cannot replace or require the existing password and do not automatically sign the resource in. Invitation data is a bearer credential; applications must re-check referenced resources, authorization, and current roles when accepting it.

Placeholder resources expose invitation_pending?. Pending placeholders are rejected by both Devise's password validation and active_for_authentication? checks until an invitation is accepted or the resource is claimed by direct registration.

Privacy and data retention

Invitation keys commonly contain personal data such as an email address. With the default create_resource_on_invitation: false, no resource row is created, and new invitations do not persist the invite-key values in the devise_invitations.invite_key JSON column. The values are carried in the encrypted and authenticated acceptance token and restored only when the link is accepted. invite_key_digest is stored so the values in the token can be verified against the invitation record. Invitations created before this change may still have plaintext invite keys; their existing links remain supported.

With create_resource_on_invitation: true, the resource and any additional attributes or associations supplied to invite! are persisted immediately. Choose this mode only when the application needs a placeholder and its privacy policy permits storing that data before acceptance. An application may clear the placeholder's invite-key attributes after delivery, for example in an after_invitation_created callback; the encrypted acceptance token restores them during acceptance. The application is responsible for allowing the blank placeholder attributes and persisting the cleanup.

invite_for limits token validity but does not delete invitation or resource records. Applications are responsible for choosing a lawful basis for processing, disclosing that processing where required, limiting invited data, restricting access, protecting it at rest, and deleting pending, revoked, superseded, and accepted invitation data according to their retention policy. Consent is one possible lawful basis under GDPR, but it is not the only one. See the European Commission GDPR principles and obtain appropriate legal advice for the application.

The acceptance token is a bearer credential: avoid logging it or exposing it to third parties. Its encryption key is derived from the Rails application's key generator, so changing secret_key_base invalidates outstanding encrypted invitation links.

If you want to create the invitation but not send it, you can set skip_invitation to true.

user = User.invite!(email: 'new_user@example.com') do |u|
  u.skip_invitation = true
end
# => the invitation will be stored, but its email will not be sent

When generating the accept_user_invitation_url yourself, you must use the raw_invitation_token. For new invitations this is an encrypted, authenticated envelope containing the underlying Devise token and invite keys. It is temporarily available on the object that creates the invitation and is not persisted in plaintext.

accept_user_invitation_url(invitation_token: user.raw_invitation_token)

When skip_invitation is used, the resulting invitation remains pending with an unset invitation_sent_at. Deliver it later by calling deliver on the invitation:

For resource-less invitations, first enable temporary invite-key storage:

devise :invitable, store_invite_keys_until_delivery: true
invitation = user.current_invitation
invitation.deliver

This works for placeholder-backed invitations without additional configuration. For a resource-less invitation, deliver reconstructs the resource from the temporarily stored invite key. It generates a fresh encrypted acceptance token, sends the email, clears the stored invite key, and sets invitation_sent_at. Calling it again after successful delivery does nothing.

For example, an approval workflow can find unsent pending invitations and deliver an approved one after applying its own authorization policy:

invitations = DeviseInvitable::Invitation.pending.where(invitation_sent_at: nil)
invitation = invitations.find(approved_invitation_id)
invitation.deliver

Invitation validity starts at invitation_sent_at, so time spent awaiting approval does not reduce the configured invite_for period.

You can add :skip_invitation to attributes hash if skip_invitation is added to attr_accessible.

User.invite!(email: 'new_user@example.com', skip_invitation: true)
# => the invitation will be stored, but its email will not be sent

skip_invitation skips sending the email but still creates a pending DeviseInvitable::Invitation. With placeholders enabled, invited_to_sign_up? and invitation_pending? return true on the resource.

Background delivery

Devise Invitable includes a lazily loaded Active Job for background invitation delivery. To use it for the normal invitation flow, enable it in the Devise initializer:

config.deliver_invitation_later = true
User.invite!(email: 'new_user@example.com')

It can also enqueue an invitation that was created without sending its email:

user = User.invite!(email: 'new_user@example.com', skip_invitation: true)
user.current_invitation.deliver_later

The default job runs on the mailers queue. It reconstructs a resource-less invitee from the encrypted acceptance token and calls deliver_now on the configured Devise mailer because it is already executing inside a background job. It retains invitation_sent_at after successful delivery and leaves failed invitations retryable by clearing that timestamp if delivery raises.

The example above does not require store_invite_keys_until_delivery because the invitation is enqueued while its acceptance token is still available. If an invitation will be reloaded and approved before it is enqueued, enable temporary invite-key storage:

class User < ApplicationRecord
  devise :invitable, store_invite_keys_until_delivery: true
end

invitation = DeviseInvitable::Invitation.find(approved_invitation_id)
invitation.deliver_later

Stored invite keys are cleared after successful delivery. Placeholder-backed invitations do not need this setting because their persisted resource contains the delivery address.

Configure the default queue in the Devise initializer:

config.invitation_delivery_queue_name = :critical_mailers

To inherit from the application's ApplicationJob, add retries or callbacks, or use another compatible job implementation, configure a custom job class:

class ApplicationInvitationDeliveryJob < ApplicationJob
  queue_as :mailers
  retry_on MailProviderError

  def perform(invitation, acceptance_token = nil, options = {})
    DeviseInvitable::InvitationDelivery.deliver_now(
      invitation,
      acceptance_token: acceptance_token,
      options: options
    )
  end
end
config.invitation_delivery_job = 'ApplicationInvitationDeliveryJob'

By default, the normal invitation flow and synchronous Invitation#deliver continue to use send_devise_notification. This is compatible with Devise's documented model override that calls Action Mailer's deliver_later, including for persisted placeholder resources. Action Mailer cannot enqueue an unpersisted, resource-less invitee, so enable deliver_invitation_later when create_resource_on_invitation is disabled. Enabling the setting or calling Invitation#deliver_later gives the invitation job ownership of the queue boundary. Inside that job, the gem calls the configured Devise mailer directly with deliver_now, so a send_devise_notification override does not create a second job. Other Devise notifications continue to use that override normally.

Applications without Active Job can leave deliver_invitation_later disabled and continue to use synchronous delivery, or configure any compatible job class that responds to perform_later.

For immediate resource-less background delivery, the encrypted acceptance token is a job argument. Treat the queue as sensitive storage and configure job logging so bearer tokens are not exposed. Mail options must also be serializable.

To check if a particular user is created by invitation, irrespective to state of invitation one can use created_by_invite?

You can also set invited_by when using the invite! class method:

User.invite!({ email: 'new_user@example.com' }, current_user) # current_user will be set as invited_by

Sending an invitation after user creation

You can send an invitation to an existing user if your workflow creates them separately:

user = User.find(42)
user.invite!(current_user)  # current user is optional to set the invited_by attribute

Whenever possible, prefer the User.invite! class method described above. The instance method creates another invitation and does not perform the class method's checks for an existing registered account. Only call it from a trusted, authorized workflow after verifying that the user is eligible to be invited. In particular, do not expose it through an unauthenticated endpoint, as doing so could allow an attacker to disrupt or take over an existing account.

Find by invitation token

To find by invitation token use the find_by_invitation_token class method.

user = User.find_by_invitation_token(params[:invitation_token], true)

Accept an invitation

To accept an invitation with a token use the accept_invitation! class method. :invitation_token must be present in the parameters hash. You can also include other attributes in the hash.

User.accept_invitation!(invitation_token: params[:invitation_token], password: 'ad97nwj3o2', name: 'John Doe')

Callbacks

A callback event is fired before and after an invitation is created (User#invite!) or accepted (User#accept_invitation!). For example, in your resource model you can add:

# Note: callbacks should be placed after devise: :invitable is specified.
before_invitation_created :email_admins
after_invitation_accepted :email_invited_by

def email_admins
  # ...
end

def email_invited_by
  # ...
end

The callbacks support all options and arguments available to the standard callbacks provided by ActiveRecord.

Scopes

A pair of scopes to find those users that have accepted, and those that have not accepted, invitations are defined:

User.invitation_accepted     # => resources with at least one accepted invitation
User.invitation_not_accepted # => resources provisioned by a pending invitation
User.created_by_invite       # => resources created through the invitation workflow

Integration in a Rails application

Since the invitations controller takes care of all the creation/acceptation of an invitation, in most cases you wouldn't call the invite! and accept_invitation! methods directly. Instead, in your views, put a link to new_user_invitation_path or new_invitation_path(:user) or even /users/invitation/new to prepare and send an invitation (to a user in this example).

After an invitation is created and sent, the inviter will be redirected to after_invite_path_for(inviter, invitee), which is the same path as signed_in_root_path by default.

After an invitation is accepted, the invitee will be redirected to after_accept_path_for(resource), which is the same path as signed_in_root_path by default. If you want to override the path, override invitations controller and define after_accept_path_for method. This is useful in the common case that a user is invited to a specific location in your application. More on Devise's README, "Controller filters and helpers" section.

The invitation email includes a link to accept the invitation that looks like this: /users/invitation/accept?invitation_token=abcd123. When clicked, the invited must set a password in order to accept its invitation. Note that if the invitation_token is not present or not valid, the invited is redirected to invalid_token_path_for(resource_name), which by default is after_sign_out_path_for(resource_name).

The controller sets the invitation's polymorphic invited_by association to the current user. This keeps every inviter when the same address is invited more than once.

Controller filter

InvitationsController uses authenticate_inviter! filter to restrict who can send invitations. You can override this method in your ApplicationController.

Default behavior requires authentication of the same resource as the invited one. For example, if your model User is invitable, it will allow all authenticated users to send invitations to other users.

You would have a User model which is configured as invitable and an Admin model which is not. If you want to allow only admins to send invitations, simply overwrite the authenticate_inviter! method as follow:

class ApplicationController < ActionController::Base
  protected

    def authenticate_inviter!
      authenticate_admin!(force: true)
    end
end

And include DeviseInvitable::Inviter module into Admin model:

class Admin < ActiveRecord::Base
  devise :database_authenticatable, :validatable
  include DeviseInvitable::Inviter
end

Restricting or disabling invitation endpoints

authenticate_inviter! may enforce any application-specific condition, not only authentication. For example, it can check roles, permissions, relationships, tenant membership, or whether an application workflow has been completed.

The filter protects only the invitation controller's new and create actions. Calling User.invite! from an authorized application service, controller, callback, or background job is unaffected.

To prevent invitations from being sent through the standard invitation form while still allowing controlled application workflows, override the filter in a custom invitations controller:

class Users::InvitationsController < Devise::InvitationsController
  protected

    def authenticate_inviter!
      redirect_to root_path, alert: "Invitations cannot be sent from this page."
    end
end

Configure Devise to use the controller:

devise_for :users, controllers: { invitations: "users/invitations" }

The application can then create invitations from its authorized workflow:

User.invite!(email: email)

When the standard form should remain available to some users, call super and apply the additional policy:

class Users::InvitationsController < Devise::InvitationsController
  protected

    def authenticate_inviter!
      super
      return if performed?
      return if current_user.allowed_to_invite_users?

      redirect_to root_path, alert: "You are not allowed to send invitations."
    end
end

Has many invitations

The DeviseInvitable::Inviter module defines a sent_invitations association containing every invitation sent by the resource:

current_user.sent_invitations
current_admin.sent_invitations

Deleting an inviter preserves its sent invitations and clears their invited_by association.

I18n

DeviseInvitable uses flash messages with I18n with the flash keys :send_instructions, :invitation_token_invalid and :updated. To customize your app, you can modify the generated locale file:

en:
  devise:
    invitations:
      send_instructions: 'An invitation email has been sent to %{email}.'
      invitation_token_invalid: 'The invitation token provided is not valid!'
      updated: 'Your password was set successfully. You are now signed in.'
      updated_not_active: 'Your password was set successfully.'

You can also create distinct messages based on the resource you've configured using the singular name given in routes:

en:
  devise:
    invitations:
      user:
        send_instructions: 'A new user invitation has been sent to %{email}.'
        invitation_token_invalid: 'Your invitation token is not valid!'
        updated: 'Welcome on board! You are now signed in.'
        updated_not_active: 'Welcome on board! Sign in to continue.'

The DeviseInvitable mailer uses the same pattern as Devise to create mail subject messages:

en:
  devise:
    mailer:
      invitation_instructions:
        subject: 'You got an invitation!'
        user_subject: 'You got a user invitation!'

Take a look at the generated locale file to check all available messages.

Check out wiki for translations.

Use with sub schema

If you are using sub schema in you application, you need to make sure that you are prioritizing your sub schema scheme over Warden in Rack. For instance, if you are using the Apartment gem go inside your config/application.rb file, add the following lines:

module YourSite
  class Application < Rails::Application
    ...
    Rails.application.config.middleware.insert_before Warden::Manager, Apartment::Elevators::Subdomain
  end
end

Other ORMs

DeviseInvitable supports ActiveRecord and Mongoid, like Devise.

Wiki

It's possible to find additional information about DeviseInvitable on the Wiki:

https://github.com/scambra/devise_invitable/wiki

Testing

To run tests:

bundle install
bundle exec rake test

Contributors

Check them all at:

https://github.com/scambra/devise_invitable/contributors

Special thanks to rymai for the Rails 3 support, his fork was a great help.

Note on Patches/Pull Requests

  • Fork the project.
  • Make your feature addition or bug fix.
  • Add tests for it. This is important so I don't break it in a future version unintentionally.
  • Commit, do not mess with rakefile, version, or history. (if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
  • Send me a pull request. Bonus points for topic branches.

Copyright

Copyright (c) 2019 Sergio Cambra. See LICENSE for details.

About

An invitation strategy for devise

Topics

Resources

Stars

2.7k stars

Watchers

35 watching

Forks

Releases

Packages

Used by

Contributors

Languages