Module: Plutonium::Invites::Concerns::InviteToken

Extended by:
ActiveSupport::Concern
Defined in:
lib/plutonium/invites/concerns/invite_token.rb

Overview

InviteToken provides core invite functionality for models.

This concern handles:

  • Token generation and validation

  • State machine (pending, accepted, expired, cancelled)

  • Email constraint validation

  • Invite acceptance flow

Examples:

Basic usage

class UserInvite < ApplicationRecord
  include Plutonium::Resource::Record
  include Plutonium::Invites::Concerns::InviteToken

  belongs_to :entity
  belongs_to :invited_by, polymorphic: true
  belongs_to :user, optional: true
  belongs_to :invitable, polymorphic: true, optional: true

  enum :role, member: 0, admin: 1

  def invitation_mailer
    UserInviteMailer
  end

  def create_membership_for(user)
    EntityMembership.create!(entity: entity, user: user, role: role)
  end
end

Instance Method Summary collapse

Instance Method Details

#accept_for_user!(user) ⇒ Object

Accept the invitation for a user.

This method:

  1. Validates email constraints

  2. Marks the invite as accepted

  3. Creates the entity membership

  4. Notifies the invitable (if present)

Parameters:

  • user (Object)

    the user accepting the invitation

Raises:

  • (ActiveRecord::RecordInvalid)

    if acceptance fails



123
124
125
126
127
128
129
130
131
132
133
134
135
136
# File 'lib/plutonium/invites/concerns/invite_token.rb', line 123

def accept_for_user!(user)
  validate_email_constraints!(user.email)

  transaction do
    update!(
      state: :accepted,
      accepted_at: Time.current,
      user: user
    )

    create_membership_for(user)
    notify_invitable(user)
  end
end

#create_membership_for(user) ⇒ Object

Override this method to create the entity membership.

Parameters:

  • user (Object)

    the user who accepted the invitation

Raises:

  • (NotImplementedError)

    if not overridden



150
151
152
# File 'lib/plutonium/invites/concerns/invite_token.rb', line 150

def create_membership_for(user)
  raise NotImplementedError, "#{self.class}#create_membership_for must be implemented to create the membership record"
end

#enforce_domainString?

Override in subclass to enforce email domain matching.

Returns:

  • (String, nil)

    the domain to enforce, or nil to skip domain check



82
83
84
# File 'lib/plutonium/invites/concerns/invite_token.rb', line 82

def enforce_domain
  nil
end

#enforce_email?Boolean

Override in subclass to require exact email match.

Returns:

  • (Boolean)

    true to require exact email match



89
90
91
# File 'lib/plutonium/invites/concerns/invite_token.rb', line 89

def enforce_email?
  true
end

#invitation_mailerClass

Override this method to specify the mailer class.

Returns:

  • (Class)

    the mailer class for sending invitation emails

Raises:

  • (NotImplementedError)

    if not overridden



142
143
144
# File 'lib/plutonium/invites/concerns/invite_token.rb', line 142

def invitation_mailer
  raise NotImplementedError, "#{self.class}#invitation_mailer must be implemented to return the mailer class"
end

#validate_email_constraints!(user_email) ⇒ Object

Validate email constraints against the accepting user’s email.

Parameters:

  • user_email (String)

    the email of the user accepting the invite

Raises:

  • (ActiveRecord::RecordInvalid)

    if constraints are violated



97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
# File 'lib/plutonium/invites/concerns/invite_token.rb', line 97

def validate_email_constraints!(user_email)
  if enforce_email? && user_email.downcase != email.downcase
    errors.add(:base, "This invitation is for #{email}. You must use an account with that email address.")
    raise ActiveRecord::RecordInvalid.new(self)
  end

  if (required_domain = enforce_domain)
    user_domain = extract_domain(user_email)

    if user_domain != required_domain
      errors.add(:base, "This invitation requires an email from the #{required_domain} domain.")
      raise ActiveRecord::RecordInvalid.new(self)
    end
  end
end