### Generate DeviseInvitable Installation Configuration Source: https://github.com/scambra/devise_invitable/blob/master/README.md Generates the necessary configuration file for DeviseInvitable. This command integrates DeviseInvitable's setup into the main Devise initializer (`config/initializers/devise.rb`). ```shell rails generate devise_invitable:install ``` -------------------------------- ### Install DeviseInvitable Gem Source: https://github.com/scambra/devise_invitable/blob/master/README.md Installs the DeviseInvitable gem using the RubyGems package manager. This is the first step to integrating invitation functionality into a Rails application. ```shell gem install devise_invitable ``` -------------------------------- ### Run Devise Invitable Tests (Shell) Source: https://github.com/scambra/devise_invitable/blob/master/README.md Provides the shell commands to install dependencies and run the tests for Devise Invitable. Ensures the development environment is set up correctly for testing. ```shell bundle install bundle exec rake test ``` -------------------------------- ### Example Invitation Form with Custom Fields (ERB) Source: https://context7.com/scambra/devise_invitable/llms.txt An example ERB template for the new invitation form (`new.html.erb`) that includes custom fields such as first name, last name, role selection, and department. These fields correspond to the parameters permitted in `configure_permitted_parameters`. ```erb # app/views/devise/invitations/new.html.erb <%= form_for(resource, as: resource_name, url: invitation_path(resource_name), html: { method: :post }) do |f| %> <%= f.text_field :email, required: true %> <%= f.text_field :first_name %> <%= f.text_field :last_name %> <%= f.select :role, options_for_select(User.roles.keys.map { |k| [k.humanize, k] }), { prompt: "Select Role" } %> <%= f.text_field :department %> <%= f.submit "Send Invitation" %> <% end %> ``` -------------------------------- ### Devise Invitable Callbacks (Ruby) Source: https://github.com/scambra/devise_invitable/blob/master/README.md This example illustrates how to define callbacks for invitation creation and acceptance events. Callbacks like `before_invitation_created` and `after_invitation_accepted` can be used to trigger custom logic. These callbacks support standard ActiveRecord callback options and arguments. ```ruby # 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 ``` -------------------------------- ### Example Acceptance Form with Custom Fields (ERB) Source: https://context7.com/scambra/devise_invitable/llms.txt An example ERB template for the invitation acceptance form (`edit.html.erb`) that includes custom fields for password, password confirmation, first name, last name, phone, and terms acceptance. These fields are permitted via `devise_parameter_sanitizer.permit(:accept_invitation)`. ```erb # app/views/devise/invitations/edit.html.erb <%= form_for(resource, as: resource_name, url: invitation_path(resource_name), html: { method: :put }) do |f| %> <%= f.hidden_field :invitation_token %> <%= f.password_field :password, required: true %> <%= f.password_field :password_confirmation, required: true %> <%= f.text_field :first_name %> <%= f.text_field :last_name %> <%= f.telephone_field :phone %> <%= f.check_box :terms_accepted, required: true %> <%= f.label :terms_accepted, "I accept the terms and conditions" %> <%= f.submit "Accept Invitation" %> <% end %> ``` -------------------------------- ### Devise Invitable Mailer Views Structure Source: https://github.com/scambra/devise_invitable/wiki/Integration-with-postmark-rails-(-or-any-ActionMailer-adapter-) This example illustrates the expected file structure for Devise Invitable mailer views when using a custom mailer class. It shows how to organize the `invitation_instructions.html.erb` and invitation-related views within the custom mailer's directory. ```text app/views/my_custom_mailer_klass/ app/views/my_custom_mailer_klass/invitation_instructions.html.erb app/views/my_custom_mailer_klass/invitations/edit.html.erb app/views/my_custom_mailer_klass/invitations/new.html.erb ``` -------------------------------- ### Customize Devise Invitations Controller in Rails Source: https://github.com/scambra/devise_invitable/blob/master/README.md This example shows how to create a custom controller that inherits from Devise::InvitationsController to override specific actions like 'update'. You then need to configure your routes to use this custom controller. ```ruby class Users::InvitationsController < Devise::InvitationsController def update if some_condition redirect_to root_path else super end end end ``` ```ruby devise_for :users, controllers: { invitations: 'users/invitations' } ``` -------------------------------- ### Check and Manage Invitation Limits (Ruby) Source: https://context7.com/scambra/devise_invitable/llms.txt This code example explains how to use the `has_invitations_left?` method to check if a user has remaining invitations to send. It covers sending new invitations if limits allow and displaying messages when the limit is reached. The snippet also details how to check the current invitation limit for a user and how to configure global and per-user limits, including setting unlimited invitations. ```ruby # Check if user can send invitations current_user = User.find(1) if current_user.has_invitations_left? # User can send invitation User.invite!({email: 'new@example.com'}, current_user) else # User reached invitation limit flash[:alert] = "You've reached your invitation limit" end # Check current limit puts "Invitations remaining: #{current_user.invitation_limit}" # => Prints remaining count or nil if unlimited # Configure global limit in config/initializers/devise.rb # config.invitation_limit = 5 # Set per-user limits current_user.update(invitation_limit: 10) # => Give this user 10 invitations # Unlimited invitations for specific user admin.update(invitation_limit: nil) # => nil means unlimited # Invitation limits auto-decrement when invitations sent user = User.find(1) # invitation_limit = 5 User.invite!({email: 'someone@example.com'}, user) user.reload # => invitation_limit is now 4 ``` -------------------------------- ### Add DeviseInvitable to Gemfile Source: https://github.com/scambra/devise_invitable/blob/master/README.md Adds the DeviseInvitable gem dependency to a Rails application's Gemfile, specifying the version to be used. This ensures the gem is included during the bundle install process. ```ruby gem 'devise_invitable', '~> 2.0.0' ``` -------------------------------- ### Define has_many Invitations Association (Ruby) Source: https://context7.com/scambra/devise_invitable/llms.txt Define a `has_many` association in the `User` model to track all users invited by a specific user. This setup uses the `invited_by` association and `as: :invited_by` for polymorphism, enabling features like invitation tracking and referral analytics. ```ruby # For standard polymorphic invited_by class User < ApplicationRecord devise :database_authenticatable, :invitable # Track users this user has invited has_many :invitations, class_name: 'User', as: :invited_by, dependent: :nullify # Optional: track with counter cache # Add invitations_count integer column to users table end # Usage examples user = User.find(1) # Get all users invited by this user invited_users = user.invitations # => [, , ] # Count invitations sent user.invitations.count # => 3 # Get accepted invitations user.invitations.invitation_accepted.count # => 2 # Get pending invitations user.invitations.invitation_not_accepted.count # => 1 ``` -------------------------------- ### Query Invitation Status (Ruby) Source: https://context7.com/scambra/devise_invitable/llms.txt This section explains how to use ActiveRecord scopes provided by Devise Invitable to filter users based on their invitation status. It covers finding users who have accepted invitations, those with pending invitations, and all users created via invitation. Examples include combining scopes and finding expired pending invitations. ```ruby # Find all users who accepted their invitations accepted_users = User.invitation_accepted # => SELECT * FROM users WHERE invitation_accepted_at IS NOT NULL # Find users with pending invitations pending_users = User.invitation_not_accepted # => SELECT * FROM users WHERE invitation_token IS NOT NULL # AND invitation_accepted_at IS NULL # Find all users created via invitation (regardless of acceptance) invited_users = User.created_by_invite # => SELECT * FROM users WHERE invitation_created_at IS NOT NULL # Combine with other scopes recent_pending = User.invitation_not_accepted .where('invitation_sent_at > ?', 7.days.ago) .order(invitation_sent_at: :desc) # => Pending invitations from last 7 days # Find expired pending invitations (if invite_for is configured) if User.invite_for > 0 expired = User.invitation_not_accepted.select do |user| !user.invitation_period_valid? end end ``` -------------------------------- ### Configure Sub-Schema Prioritization with Apartment (Ruby) Source: https://github.com/scambra/devise_invitable/blob/master/README.md Demonstrates how to configure middleware in `config/application.rb` to prioritize a sub-schema strategy (like Apartment's Subdomain elevator) over Warden, essential for applications using multi-tenancy. ```ruby module YourSite class Application < Rails::Application ... Rails.application.config.middleware.insert_before Warden::Manager, Apartment::Elevators::Subdomain end end ``` -------------------------------- ### Manage Invitation Token and Delivery (Ruby) Source: https://github.com/scambra/devise_invitable/blob/master/README.md This Ruby code addresses the management of invitation tokens and email delivery within Devise Invitable. It shows how to construct the `accept_user_invitation_url` using the `raw_invitation_token` which is temporarily available. It also explains the importance of setting `invitation_sent_at` when `skip_invitation` is used, and provides the `deliver_invitation` method to send the email and set the timestamp. A warning is included about `raw_invitation_token` being instance-specific and not persisted. ```ruby accept_user_invitation_url(invitation_token: user.raw_invitation_token) user.deliver_invitation User.invite!({ email: 'new_user@example.com' }, current_user) # current_user will be set as invited_by ``` -------------------------------- ### Create Mongoid Indexes in MongoDB Source: https://github.com/scambra/devise_invitable/blob/master/README.md Executes a Rake task to create the defined indexes within the MongoDB database. This command is crucial for efficient querying of invitation-related data. ```shell rake db:mongoid:create_indexes ``` -------------------------------- ### Send Invitation After User Creation (Ruby) Source: https://github.com/scambra/devise_invitable/blob/master/README.md This snippet demonstrates how to send an invitation to an existing user using the `invite!` method. It requires the User model to be set up with Devise Invitable. The `current_user` is optional and is used to set the `invited_by` attribute. ```ruby user = User.find(42) user.invite!(current_user) # current user is optional to set the invited_by attribute ``` -------------------------------- ### Send User Invitation with DeviseInvitable (Ruby) Source: https://context7.com/scambra/devise_invitable/llms.txt Creates a new user record and sends an invitation email using User.invite!. It supports basic invitations, tracking the inviter, and skipping email delivery for custom workflows. The method returns the created user instance. ```ruby User.invite!(email: 'newuser@example.com', name: 'John Doe') current_user = User.find(1) invited_user = User.invite!({email: 'colleague@example.com'}, current_user) user = User.invite!(email: 'delayed@example.com', name: 'Jane Smith') do |u| u.skip_invitation = true end user.deliver_invitation user = User.invite!(email: 'custom@example.com') { |u| u.skip_invitation = true } invitation_url = accept_user_invitation_url(invitation_token: user.raw_invitation_token) ``` -------------------------------- ### Accept Invitation with Token and Attributes (Ruby) Source: https://github.com/scambra/devise_invitable/blob/master/README.md This method allows a user to accept an invitation by providing their invitation token and any other necessary attributes, such as a password and name. It uses the `accept_invitation!` class method, expecting the `invitation_token` to be present in the parameters. ```ruby User.accept_invitation!(invitation_token: params[:invitation_token], password: 'ad97nwj3o2', name: 'John Doe') ``` -------------------------------- ### Generate DeviseInvitable Model Integration Source: https://github.com/scambra/devise_invitable/blob/master/README.md Generates DeviseInvitable integration for a specific model. This command adds the ':invitable' module to the Devise configuration for the specified model and creates a migration file if the ORM supports it. ```shell rails generate devise_invitable MODEL ``` -------------------------------- ### Override Invitation and Acceptance Logic in Rails Source: https://github.com/scambra/devise_invitable/blob/master/README.md This snippet illustrates how to override private methods within a custom Devise::InvitationsController to modify the behavior of inviting and accepting invitations. For example, you can skip sending emails on invite or report invitation acceptance to an analytics service. ```ruby 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 ``` -------------------------------- ### Send Invitation with Custom Attributes (Ruby) Source: https://github.com/scambra/devise_invitable/blob/master/README.md This Ruby code demonstrates how to send an invitation to a new user using the `invite!` class method provided by Devise Invitable. It shows how to pass additional attributes like `name` (and by extension, `first_name`, `last_name`, `role` if configured) directly in the parameters hash. This method creates the user record and sends an invitation email. It also illustrates how to skip sending the email by setting `skip_invitation` to true, allowing for manual control over the invitation process. ```ruby User.invite!(email: 'new_user@example.com', name: 'John Doe') # => an invitation email will be sent to new_user@example.com user = User.invite!(email: 'new_user@example.com', name: 'John Doe') do |u| u.skip_invitation = true end # => the record will be created, but the invitation email will not be sent User.invite!(email: 'new_user@example.com', name: 'John Doe', skip_invitation: true) # => the record will be created, but the invitation email will not be sent ``` -------------------------------- ### Generate Devise Invitable Views in Rails Source: https://github.com/scambra/devise_invitable/blob/master/README.md These commands demonstrate how to generate the necessary views for Devise Invitable. You can generate all views or specific views for a scoped model, such as 'users'. ```shell rails generate devise_invitable:views ``` ```shell rails generate devise_invitable:views users ``` -------------------------------- ### Accept User Invitation with DeviseInvitable (Ruby) Source: https://context7.com/scambra/devise_invitable/llms.txt Accepts a pending invitation by setting the user's password and marking the invitation as accepted using User.accept_invitation!. This method finds the user by invitation token, sets their password, and can optionally confirm the account. It returns the user instance, with errors if validation fails. ```ruby user = User.accept_invitation!( invitation_token: 'abc123def456', password: 'SecurePass123!', password_confirmation: 'SecurePass123!' ) if user.errors.empty? puts "Welcome #{user.email}!" else puts user.errors.full_messages.join(", ") end user = User.accept_invitation!( invitation_token: params[:invitation_token], password: 'NewPassword123!', password_confirmation: 'NewPassword123!', name: 'Updated Name', phone: '555-1234' ) ``` -------------------------------- ### Create Custom Devise Invitable Mailer (Ruby) Source: https://github.com/scambra/devise_invitable/wiki/Customizing-for-different-Invite-use-cases-(emails-etc.) This Ruby code defines a custom mailer class that inherits from Devise::Mailer. It overrides the `invitation_instructions` method to allow for dynamic selection of email templates based on the `invitation_instructions` attribute set on the record. This is crucial for sending different invitation emails. It requires Devise and Devise Invitable. ```ruby class InviteMailer < Devise::Mailer def invitation_instructions(record, token, opts={}) @token = token # Use the custom instruction or default to :invitation_instructions devise_mail(record, record.invitation_instructions || :invitation_instructions, opts) end end ``` -------------------------------- ### Generate Devise Invitable Views Source: https://github.com/scambra/devise_invitable/wiki/How-To:-Allow-updating-additional-attributes-when-accepting-invitation This command generates the necessary view files for Devise Invitable, allowing for customization of the invitation-related views, particularly the invitation edit template. ```bash rails g devise_invitable:views ``` -------------------------------- ### User.invite! - Send Invitation Source: https://context7.com/scambra/devise_invitable/llms.txt This method creates a new user record and sends an invitation email. It is the primary way to invite new users to the application. It accepts user attributes, an optional inviter, and a block for customization. ```APIDOC ## User.invite! - Send Invitation ### Description Creates a new user record and sends an invitation email. This is the primary method for inviting users to the application. The method accepts user attributes (email required), an optional inviter, and a block for additional customization. Returns the created user instance. ### Method `User.invite!` ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body - **email** (string) - Required - The email address of the user to invite. - **name** (string) - Optional - The name of the user to invite. - **inviter** (User object) - Optional - The user who is sending the invitation. - **block** (Proc) - Optional - A block for additional customization (e.g., `skip_invitation = true`). ### Request Example ```ruby # Basic invitation user = User.invite!(email: 'newuser@example.com', name: 'John Doe') # Invitation with inviter tracking current_user = User.find(1) invited_user = User.invite!({email: 'colleague@example.com'}, current_user) # Skip sending email immediately user = User.invite!(email: 'delayed@example.com', name: 'Jane Smith') do |u| u.skip_invitation = true end ``` ### Response #### Success Response (200) - **user** (User object) - The newly created user instance with an invitation token set. #### Response Example ```json { "id": 1, "email": "newuser@example.com", "name": "John Doe", "invitation_token": "some_token", "invitation_sent_at": "2023-10-27T10:00:00Z" } ``` ### Additional Notes - `user.deliver_invitation` can be called later if `skip_invitation` was set to true. - `user.raw_invitation_token` can be accessed to generate custom invitation URLs. ``` -------------------------------- ### Include Devise Invitable Inviter Module (Ruby) Source: https://github.com/scambra/devise_invitable/blob/master/README.md This snippet shows how to include the `DeviseInvitable::Inviter` module in a model, such as `Admin`, to enable it to send invitations. This is typically done alongside other Devise modules like `:database_authenticatable` and `:validatable`. ```ruby class Admin < ActiveRecord::Base devise :database_authenticatable, :validatable include DeviseInvitable::Inviter end ``` -------------------------------- ### Per-Controller Override for Invitation Authentication Source: https://context7.com/scambra/devise_invitable/llms.txt Demonstrates overriding `authenticate_inviter!` within a specific controller (`Users::InvitationsController`) for more granular control over invitation creation. ```ruby # Per-controller override class Users::InvitationsController < Devise::InvitationsController protected def authenticate_inviter! if params[:action] == 'create' # Strict checking for creating invitations authenticate_user!(force: true) redirect_to root_path unless current_user.verified_email? else super end end end ``` -------------------------------- ### Check User Invitation Status (Ruby) Source: https://context7.com/scambra/devise_invitable/llms.txt This snippet shows how to use the `invited_to_sign_up?` method to determine if a user has a pending invitation. It also demonstrates checking if the invitation can still be accepted (`valid_invitation?`) and how to handle expired invitations by re-sending them. The code further illustrates checking if a user was accepted or created directly. ```ruby user = User.find_by(email: 'invited@example.com') if user.invited_to_sign_up? # User has pending invitation puts "Invitation sent at: #{user.invitation_sent_at}" puts "Invitation expires at: #{user.invitation_due_at}" if user.invitation_due_at # Check if can still accept if user.valid_invitation? # Can accept invitation else # Invitation expired, need to resend user.invite!(current_user) end elsif user.invitation_accepted? # User already accepted invitation puts "Accepted at: #{user.invitation_accepted_at}" else # User not invited (created directly) puts "Regular user account" end # Check if user was ever invited if user.created_by_invite? puts "This user was originally invited" end ``` -------------------------------- ### Configure Permitted Parameters for Devise Invitable Invite Action (Ruby) Source: https://github.com/scambra/devise_invitable/blob/master/README.md This Ruby code snippet configures the Devise Invitable controller to permit additional parameters, such as first_name, last_name, and role, for the 'invite' action. It uses a `before_action` filter to call a protected method that utilizes `devise_parameter_sanitizer.permit` to specify the allowed keys. This ensures that custom attributes are correctly processed when inviting new users. It's typically placed in your `ApplicationController` or a specific `InvitationsController`. ```ruby 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 ``` -------------------------------- ### Find User by Invitation Token (Ruby) Source: https://github.com/scambra/devise_invitable/blob/master/README.md This code shows how to locate a user record using their unique invitation token. It utilizes the `find_by_invitation_token` class method provided by Devise Invitable. The second argument, `true`, typically indicates whether to look for unscoped records. ```ruby user = User.find_by_invitation_token(params[:invitation_token], true) ``` -------------------------------- ### User.accept_invitation! - Accept Invitation Source: https://context7.com/scambra/devise_invitable/llms.txt This class method accepts a pending invitation by setting the user's password and marking the invitation as accepted. It finds the user by invitation token, sets their password, and confirms the account if Devise's confirmable module is used. ```APIDOC ## User.accept_invitation! - Accept Invitation ### Description Accepts a pending invitation by setting the user's password and marking the invitation as accepted. This class method finds the user by invitation token, sets their password, and automatically confirms the account if using Devise's confirmable module. Returns the user instance with errors if validation fails. ### Method `User.accept_invitation!` ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body - **invitation_token** (string) - Required - The token received in the invitation email. - **password** (string) - Required - The desired password for the new user. - **password_confirmation** (string) - Required - The confirmation of the desired password. - **additional attributes** (any) - Optional - Any other user attributes to set during acceptance (e.g., name, phone). ### Request Example ```ruby user = User.accept_invitation!( invitation_token: 'abc123def456', password: 'SecurePass123!', password_confirmation: 'SecurePass123!', name: 'Updated Name' ) if user.errors.empty? puts "Welcome #{user.email}!" else puts user.errors.full_messages.join(", ") end ``` ### Response #### Success Response (200) - **user** (User object) - The user instance with their password set and invitation accepted. `invitation_accepted_at` is set, `invitation_token` is cleared, and `confirmed_at` is set if confirmable. #### Response Example ```json { "id": 2, "email": "newuser@example.com", "name": "Updated Name", "invitation_accepted_at": "2023-10-27T10:30:00Z", "invitation_token": null, "confirmed_at": "2023-10-27T10:30:00Z" } ``` #### Error Response (422) - **user** (User object) - The user instance with validation errors if the token is invalid or passwords do not match. ``` -------------------------------- ### Invitation Lifecycle Callbacks in Ruby Source: https://context7.com/scambra/devise_invitable/llms.txt Defines callback methods in a Rails User model that execute at various stages of the invitation process, such as before and after an invitation is created or accepted. These allow for custom logic like sending emails, tracking analytics, or performing validations. ```ruby class User < ApplicationRecord devise :database_authenticatable, :confirmable, :invitable # Callbacks must be defined after devise declaration before_invitation_created :setup_invitation after_invitation_created :notify_admins before_invitation_accepted :check_requirements after_invitation_accepted :send_welcome_email private def setup_invitation # Runs before invitation is created self.role ||= 'member' logger.info "Setting up invitation for #{email}" end def notify_admins # Runs after invitation created and saved AdminMailer.new_invitation(self, invited_by).deliver_later Analytics.track('invitation.sent', user_id: id, invited_by: invited_by_id) end def check_requirements # Runs before invitation is accepted # Can add custom validations unless company.active? errors.add(:base, "Company must be active") throw(:abort) # Prevents acceptance end end def send_welcome_email # Runs after invitation accepted WelcomeMailer.welcome(self).deliver_later Slack.notify_channel("#team", "#{name} joined the team!") # Track conversion Analytics.track('invitation.accepted', { user_id: id, invited_by: invited_by_id, accepted_at: invitation_accepted_at }) end end # All standard ActiveRecord callback options supported after_invitation_accepted :track_conversion, if: :invited_by_marketing? before_invitation_created :validate_domain, unless: :admin? ``` -------------------------------- ### Define Mongoid Fields and Indexes for Invitable Model Source: https://github.com/scambra/devise_invitable/blob/master/README.md Specifies the necessary fields and indexes for DeviseInvitable when using Mongoid as the ODM. These definitions ensure that invitation data is correctly stored and retrievable in MongoDB. ```ruby field :invitation_token, type: String field :invitation_created_at, type: Time field :invitation_sent_at, type: Time field :invitation_accepted_at, type: Time field :invitation_limit, type: Integer index( { invitation_token: 1 }, { background: true} ) index( { invitation_by_id: 1 }, { background: true} ) ``` -------------------------------- ### Count and Retrieve Inviter for User Source: https://context7.com/scambra/devise_invitable/llms.txt Demonstrates usage for counting invitations sent by an admin and retrieving the inviter of a user. ```ruby # Usage admin = Admin.find(1) admin.invitations.count # => Number of users invited by this admin user = User.find(5) user.invited_by # => Admin instance who invited this user ``` -------------------------------- ### Configure Mongoid Polymorphic Association for Inviter Source: https://github.com/scambra/devise_invitable/blob/master/README.md Illustrates how Mongoid handles the polymorphic association for the 'invited_by' relationship within DeviseInvitable. This association allows an invitation to be associated with different types of users or entities. ```ruby belongs_to :invited_by, polymorphic: true ``` -------------------------------- ### Devise Invitable Scopes (Ruby) Source: https://github.com/scambra/devise_invitable/blob/master/README.md This snippet shows predefined scopes for querying users based on their invitation status. `invitation_accepted` returns users who have accepted, `invitation_not_accepted` returns those who haven't, and `created_by_invite` returns users created via invitations. ```ruby User.invitation_accepted # => returns all Users for whom the invitation_accepted_at attribute is not nil User.invitation_not_accepted # => returns all Users for whom the invitation_accepted_at attribute is nil User.created_by_invite # => returns all Users who are created by invitations, irrespective to invitation status ``` -------------------------------- ### Customize DeviseInvitable invite_resource for Existing Users (Ruby) Source: https://github.com/scambra/devise_invitable/wiki/Invite-a-Resource-(or-User)-that-Has-Already-Signed-Up-without-Invitation This Ruby code snippet demonstrates how to override the `invite_resource` method in a custom `InvitationsController` to handle inviting users who already exist in the system. It checks for existing users, prevents self-invitations, and ensures the method returns a `User` instance, matching the expected return type of DeviseInvitable's `invite_resource`. ```ruby class Users::InvitationsController < Devise::InvitationsController protected # invite_resource is called when creating invitation # should return an instance of resource class # this is devise_invitable's implementation # def invite_resource(&block) # resource_class.invite!(invite_params, current_inviter, &block) # end def invite_resource(&block) @user = User.find_by(email: invite_params[:email]) # @user is an instance or nil if @user && @user.email != current_user.email # invite! instance method returns a Mail::Message instance @user.invite!(current_user) # return the user instance to match expected return type @user else # invite! class method returns invitable var, which is a User instance resource_class.invite!(invite_params, current_inviter, &block) end end end ``` -------------------------------- ### Devise Invitable Global Configuration in Ruby Source: https://context7.com/scambra/devise_invitable/llms.txt Configures DeviseInvitable settings globally within a Rails application's initializer file. It controls aspects like invitation token expiration, validation behavior, invitation limits, and auto-login after acceptance. ```ruby # config/initializers/devise.rb Devise.setup do |config| # Invitation expiration period (default: 0 = never expires) config.invite_for = 2.weeks # After 2 weeks, invitation token becomes invalid # Validate user before sending invitation (default: false) config.validate_on_invite = true # Runs full validations on user record before creating invitation # Global invitation limit per user (default: nil = unlimited) config.invitation_limit = 10 # Each user can send 10 invitations maximum # Resend invitation if user is invited again (default: true) config.resend_invitation = true # Sending invitation to already invited user resends email # Auto sign-in after accepting invitation (default: true) config.allow_insecure_sign_in_after_accept = true # User is automatically logged in after setting password # Require password when accepting (default: true) config.require_password_on_accepting = true # User must set password to accept invitation # Custom invite key matching (default: email with regex) config.invite_key = { email: Devise.email_regexp, username: /\A[a-zA-Z0-9_]+\z/ } # Allow inviting by email OR username # Polymorphic invited_by (default: nil = polymorphic) config.invited_by_class_name = 'User' # Sets specific class for invited_by instead of polymorphic # Counter cache for invitations sent config.invited_by_counter_cache = :invitations_count # Adds counter_cache to invited_by association end ``` -------------------------------- ### Create Custom Invitation Message with Ruby Source: https://github.com/scambra/devise_invitable/wiki/Customizing-for-different-Invite-use-cases-(emails-etc.) This Ruby code demonstrates how to customize Devise Invitable's invitation messages. It involves creating a custom `InvitationsController` to intercept the invitation process and a `NotificationMailer` to send a personalized email. Placeholders in the email content are replaced with actual user data. This approach bypasses Devise's default email sending. ```ruby class User < ActiveRecord::Base attr_reader :raw_invitation_token end class InvitationsController < Devise::InvitationsController def create @from = params[:from] @subject = params[:invite_subject] @content = params[:invite_content] @user = User.invite!(params[:user], current_user) do |u| u.skip_invitation = true end NotificationMailer.invite_message(@user, @from, @subject, @content).deliver if @user.errors.empty? if @user.errors.empty? @user.update_column :invitation_sent_at, Time.now.utc # mark invitation as delivered flash[:notice] = "successfully sent invite to #{@user.email}" respond_with @user, :location => root_path else render :new end end end class NotificationMailer < ActionMailer::Base def invite_message(user, from, subject, content) @user = user @token = user.raw_invitation_token invitation_link = accept_user_invitation_url(:invitation_token => @token) mail(:from => from, :bcc => from, :to => @user.email, :subject => subject) do |format| content = content.gsub '{{first_name}}', user.first_name content = content.gsub '{{last_name}}', user.first_name content = content.gsub '{{full_name}}', user.full_name content = content.gsub('{{invitation_link}}', invitation_link) format.text do render :text => content end end end end ``` -------------------------------- ### Configure Devise Model with Invitable Module Source: https://github.com/scambra/devise_invitable/blob/master/README.md Manually adds the ':invitable' module to a Devise model's configuration. This enables invitation-related functionalities for the model, such as generating invitation tokens and managing invitations. ```ruby class User < ActiveRecord::Base devise :database_authenticatable, :confirmable, :invitable end ``` -------------------------------- ### Add Invitable Columns to Existing ActiveRecord Table Source: https://github.com/scambra/devise_invitable/blob/master/README.md Adds the required columns for DeviseInvitable to an existing database table using a Rails migration. This includes invitation token, timestamps, limits, and references to the inviter. ```ruby def change add_column :users, :invitation_token, :string add_column :users, :invitation_created_at, :datetime add_column :users, :invitation_sent_at, :datetime add_column :users, :invitation_accepted_at, :datetime add_column :users, :invitation_limit, :integer add_column :users, :invited_by_id, :integer add_column :users, :invited_by_type, :string add_index :users, :invitation_token, unique: true end ``` -------------------------------- ### Resend or Update Invitation with DeviseInvitable (Ruby) Source: https://context7.com/scambra/devise_invitable/llms.txt Manages invitations for an existing user instance using the `invite!` method. This can be used to resend an invitation, update the inviter, or create an invitation token without sending an email, providing flexibility in invitation management. ```ruby existing_user = User.find(42) existing_user.invite!(current_user) user = User.find_by(email: 'pending@example.com') user.invite!(User.find(5)) user = User.create!(email: 'manual@example.com', name: 'Manual User') user.invite!(current_user) do |u| u.skip_invitation = true end ``` -------------------------------- ### Customize Devise Invitable Mailer Subjects (YAML) Source: https://github.com/scambra/devise_invitable/blob/master/README.md Configures I18n for Devise Invitable mailer subjects. Supports general subjects and resource-specific subjects (e.g., 'user_subject'). ```yaml en: devise: mailer: invitation_instructions: subject: 'You got an invitation!' user_subject: 'You got a user invitation!' ``` -------------------------------- ### Include DeviseInvitable::Mailer in Custom Mailer Source: https://github.com/scambra/devise_invitable/wiki/Integration-with-postmark-rails-(-or-any-ActionMailer-adapter-) This Ruby code snippet demonstrates how to correctly include `DeviseInvitable::Mailer` in a custom Action Mailer class to resolve `NoMethodError` issues with Devise Invitable. Ensure `Devise::Mailers::Helpers` is also included for full functionality. ```ruby class MyCustomMailerKlass < ActionMailer::Base include Devise::Mailers::Helpers # this is the important line for devise_invitable functionality include DeviseInvitable::Mailer def weekly_mail ... end end ``` -------------------------------- ### Define Custom Invitation Types in Devise Model (Ruby) Source: https://github.com/scambra/devise_invitable/wiki/Customizing-for-different-Invite-use-cases-(emails-etc.) This Ruby code snippet demonstrates how to define custom invitation methods within your Devise model. It allows you to set specific invitation instructions based on the type of invitation (e.g., 'guest' or 'friend'), enabling different email flows. It requires the Devise gem and its invitable extension to be configured. ```ruby class User < ActiveRecord::Base # ... other devise configurations ... attr_accessor :invitation_instructions def self.invite_guest!(attributes={}, invited_by=nil) self.invite!(attributes, invited_by) do |invitable| invitable.invitation_instructions = :guest_invitation_instructions end end def self.invite_friend!(attributes={}, invited_by=nil) self.invite!(attributes, invited_by) do |invitable| invitable.invitation_instructions = :friend_invitation_instructions end end end ``` -------------------------------- ### Invitation Form with Custom Fields (HTML ERB) Source: https://github.com/scambra/devise_invitable/blob/master/README.md This HTML ERB template defines the form used for inviting new users with Devise Invitable. It includes standard invitation fields (like email) and custom fields for first name, last name, and role selection. The `f.select` helper is used to create a dropdown for role selection, populated from the User model's `enum` definition. This form integrates seamlessly with the controller's strong parameter configuration. ```erb

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

<%= 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| -%>
<%= f.label field %>
<%= f.text_field field %>
<% end %>
<%= f.label :first_name %> <%= f.text_field :first_name %>
<%= f.label :last_name %> <%= f.text_field :last_name %>
<%= f.label :role %> <%= f.select :role, options_for_select(User.roles.map { |key, value| [key.humanize, key] }), {prompt: "Select Role"} %>
<%= f.submit t("devise.invitations.new.submit_button") %>
<% end %> ``` -------------------------------- ### Check Invitation Status (Ruby) Source: https://github.com/scambra/devise_invitable/blob/master/README.md This Ruby code snippet shows how to check if a user record was created via an invitation, regardless of the invitation's current state. The `created_by_invite?` method returns a boolean indicating this. It also mentions `invited_to_sign_up?`, which checks if the user has an invitation token and can therefore sign up. These methods are useful for conditional logic or displaying specific information based on how a user account was initiated. ```ruby # Assuming 'user' is an instance of User user.created_by_invite? user.invited_to_sign_up? ``` -------------------------------- ### Configure Devise Routes for Custom Invitations Controller (Ruby) Source: https://context7.com/scambra/devise_invitable/llms.txt Update `config/routes.rb` to direct Devise's invitation routes to your custom `Users::InvitationsController`. This ensures that all invitation-related actions are handled by your overridden controller. ```ruby # Update routes to use custom controller # config/routes.rb devise_for :users, controllers: { invitations: 'users/invitations' } ``` -------------------------------- ### Configure Custom Mailer in Devise Initializer (Ruby) Source: https://github.com/scambra/devise_invitable/wiki/Customizing-for-different-Invite-use-cases-(emails-etc.) This Ruby snippet shows how to configure Devise to use your custom mailer class (`InviteMailer`) as the default for sending Devise-related emails, specifically invitations. This configuration is placed in the `config/initializers/devise.rb` file. It ensures that your custom `InviteMailer` is used instead of the default Devise mailer, while other Devise emails remain unaffected. Requires Devise. ```ruby # config/initializers/devise.rb Devise.setup do |config| # ... other devise configurations ... config.mailer = "InviteMailer" end ``` -------------------------------- ### Find User by Invitation Token (Ruby) Source: https://context7.com/scambra/devise_invitable/llms.txt Retrieves a user record based on their invitation token using `User.find_by_invitation_token`. It allows for optional validation of the invitation's expiration status, returning either a user instance or a new user with errors if not found or invalid. ```ruby token = params[:invitation_token] user = User.find_by_invitation_token(token, false) ``` -------------------------------- ### Customize Devise Invitable Controller Logic (Ruby) Source: https://context7.com/scambra/devise_invitable/llms.txt Override `InvitationsController` to add custom logic before and after invitation creation and acceptance. This includes authorization checks, analytics tracking, and custom service calls. It leverages Devise's callbacks and `super` calls to integrate with the default behavior. ```ruby class Users::InvitationsController < Devise::InvitationsController before_action :check_admin, only: [:new, :create] # Override create to add custom logic def create # Custom pre-invitation logic authorize_invitation! # Call parent create super do |user| # Runs after invitation created if user.errors.empty? Analytics.track('invitation_sent', user_id: user.id) end end end # Override update to add custom acceptance logic def update super do |user| # Runs after invitation accepted if user.errors.empty? WelcomeService.new(user).call end end end protected # Override invite_resource to customize invitation process def invite_resource(&block) # Skip email for bulk invitations super do |user| user.skip_invitation = true if params[:bulk_invite] block.call(user) if block_given? end end # Override accept_resource to customize acceptance def accept_resource resource = resource_class.accept_invitation!(update_resource_params) # Custom post-acceptance logic OnboardingService.new(resource).start if resource.errors.empty? resource end # Customize redirect after invite sent def after_invite_path_for(inviter, invitee) if invitee.errors.empty? flash[:success] = "Invitation sent to #{invitee.email}" users_path else new_user_invitation_path end end # Customize redirect after invitation accepted def after_accept_path_for(resource) onboarding_path end private def check_admin redirect_to root_path unless current_user.admin? end def authorize_invitation! unless current_user.can_invite? flash[:error] = "You don't have permission to invite users" redirect_to root_path end end end ``` -------------------------------- ### Customize Devise Invitable Locale Messages by Resource (YAML) Source: https://github.com/scambra/devise_invitable/blob/master/README.md Allows for resource-specific I18n messages in Devise Invitable. This enables distinct messages based on the singular name of the resource configured in your routes. ```yaml 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.' ``` -------------------------------- ### Configure Devise Invitable Module in Rails Source: https://github.com/scambra/devise_invitable/blob/master/README.md This snippet shows how to include the Devise Invitable module in your Devise configuration. You can set global invitation periods or configure specific parameters directly within the devise method in your model. ```ruby config.invite_for = 2.weeks ``` ```ruby devise :database_authenticatable, :confirmable, :invitable, invite_for: 2.weeks ``` -------------------------------- ### user.invite! - Resend or Update Invitation Source: https://context7.com/scambra/devise_invitable/llms.txt This instance method can be used to resend an invitation to an existing user or update their invitation status, including the inviter. It's useful for re-inviting users or when users are created separately from the invitation process. ```APIDOC ## user.invite! - Resend or Update Invitation ### Description Instance method to resend an invitation to an existing user or update invitation status. Useful when you need to re-invite a user who hasn't accepted yet or when creating users separately from the invitation process. ### Method `user.invite!` ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body - **inviter** (User object) - Optional - The user who is sending the invitation. If not provided, the inviter remains unchanged. - **block** (Proc) - Optional - A block for additional customization (e.g., `skip_invitation = true`). ### Request Example ```ruby # Resend invitation to existing user existing_user = User.find(42) existing_user.invite!(current_user) # Update invitation with new inviter user = User.find_by(email: 'pending@example.com') user.invite!(User.find(5)) # Invite existing user without sending email user = User.create!(email: 'manual@example.com', name: 'Manual User') user.invite!(current_user) do |u| u.skip_invitation = true end ``` ### Response #### Success Response (200) - **user** (User object) - The user instance with potentially a new `invitation_token` and updated `invited_by` association. The `invitation_sent_at` timestamp is updated upon email delivery. #### Response Example ```json { "id": 42, "email": "existinguser@example.com", "invitation_token": "new_token_abc", "invited_by_id": 5, "invitation_sent_at": "2023-10-27T11:00:00Z" } ``` ```