devise_invitable 2.0.9 → 2.0.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b8ff92d4a82378780e01c6d3cfe57ff0808b08d49a619e3a899e94a86e7ec46c
4
- data.tar.gz: 174e7982212230032987ad9b6b1ed572b98fda73fc0652e095ae71c1b6282436
3
+ metadata.gz: 94a7a6c97740cee117769b3da7d5769285d9dbcee99acb9a3404c54abea3b874
4
+ data.tar.gz: ec293f695b7b9d00ce916be1be62857e136da944027f7252fa8e418bef237e13
5
5
  SHA512:
6
- metadata.gz: 25a25c7ec4df1183ef43d399f73cb7a4b661cc33df172d660dd551f658bebce01ac552c837608affeac59aeaaa85b137ad56247278fbe5a436ea15d03131b1e3
7
- data.tar.gz: 07a394b356fb623ab7a8ca48486acd935ea5c69b86969ccae667d414bc6d7319ec2e5fe90c0cdc8ff2a9f46eace35bfd517df659fc445088f4e43a0f6536590c
6
+ metadata.gz: d2570b24683524af46291458cd31f95c7a234da0888668c133ec646461496bab5ad130965f849d6b82b2581f00a12acf3b2b3af832dbc492ddbe9689e17d0080
7
+ data.tar.gz: 3d7d809fc6982af1177df06ad8a34bd0a982974cabbbd202210412a717d87c691e18f77a8cc5ef2257a3a178242aaba846980cd19c1ef8d1652834e3e29cd71f
data/CHANGELOG.md CHANGED
@@ -1,3 +1,5 @@
1
+ - Use invited_by_class_name and invited_by_foreign_key settings from the model
2
+
1
3
  ## 2.0.9
2
4
  - Do not accept expired invitation on password reset ([#897](https://github.com/scambra/devise_invitable/pull/897))
3
5
 
data/README.md ADDED
@@ -0,0 +1,696 @@
1
+ # DeviseInvitable
2
+ [<img src="https://badge.fury.io/rb/devise_invitable.svg"/>](http://badge.fury.io/rb/devise_invitable) [<img
3
+ src="https://github.com/scambra/devise_invitable/actions/workflows/ci.yml/badg
4
+ e.svg"/>](https://github.com/scambra/devise_invitable/actions/workflows/ci.yml
5
+ ) [<img
6
+ src="https://codeclimate.com/github/scambra/devise_invitable/badges/gpa.svg"/>
7
+ ](https://codeclimate.com/github/scambra/devise_invitable)
8
+
9
+ It adds support to [Devise](https://github.com/plataformatec/devise) for
10
+ sending invitations by email (it requires to be authenticated) and accept the
11
+ invitation setting the password.
12
+
13
+ ## Requirements
14
+
15
+ The latest version of DeviseInvitable works with Devise >= 4.6.
16
+
17
+ If you want to use devise_invitable with earlier Devise releases (4.0 <= x <
18
+ 4.6), use version 1.7.5.
19
+
20
+ ## Installation
21
+
22
+ Install DeviseInvitable gem:
23
+
24
+ ```shell
25
+ gem install devise_invitable
26
+ ```
27
+
28
+ Add DeviseInvitable to your Gemfile:
29
+
30
+ ```ruby
31
+ gem 'devise_invitable', '~> 2.0.0'
32
+ ```
33
+
34
+ ### Automatic installation
35
+
36
+ Run the following generator to add DeviseInvitable’s configuration option in
37
+ the Devise configuration file (`config/initializers/devise.rb`):
38
+
39
+ ```shell
40
+ rails generate devise_invitable:install
41
+ ```
42
+
43
+ When you are done, you are ready to add DeviseInvitable to any of your Devise
44
+ models using the following generator:
45
+
46
+ ```shell
47
+ rails generate devise_invitable MODEL
48
+ ```
49
+
50
+ Replace MODEL by the class name you want to add DeviseInvitable, like `User`,
51
+ `Admin`, etc. This will add the `:invitable` flag to your model's Devise
52
+ modules. The generator will also create a migration file (if your ORM supports
53
+ them).
54
+
55
+ ### Manual installation
56
+
57
+ Follow the walkthrough for Devise and after it's done, follow this
58
+ walkthrough.
59
+
60
+ #### Devise Configuration
61
+ Add `:invitable` to the `devise` call in your model (we’re assuming here you
62
+ already have a User model with some Devise modules):
63
+
64
+ ```ruby
65
+ class User < ActiveRecord::Base
66
+ devise :database_authenticatable, :confirmable, :invitable
67
+ end
68
+ ```
69
+
70
+ #### ActiveRecord Migration
71
+ Add `t.invitable` to your Devise model migration:
72
+
73
+ ```ruby
74
+ create_table :users do
75
+ ...
76
+ ## Invitable
77
+ t.string :invitation_token
78
+ t.datetime :invitation_created_at
79
+ t.datetime :invitation_sent_at
80
+ t.datetime :invitation_accepted_at
81
+ t.integer :invitation_limit
82
+ t.integer :invited_by_id
83
+ t.string :invited_by_type
84
+ ...
85
+ end
86
+ add_index :users, :invitation_token, unique: true
87
+ ```
88
+
89
+ or for a model that already exists, define a migration to add DeviseInvitable
90
+ to your model:
91
+
92
+ ```ruby
93
+ def change
94
+ add_column :users, :invitation_token, :string
95
+ add_column :users, :invitation_created_at, :datetime
96
+ add_column :users, :invitation_sent_at, :datetime
97
+ add_column :users, :invitation_accepted_at, :datetime
98
+ add_column :users, :invitation_limit, :integer
99
+ add_column :users, :invited_by_id, :integer
100
+ add_column :users, :invited_by_type, :string
101
+ add_index :users, :invitation_token, unique: true
102
+ end
103
+ ```
104
+
105
+ If you previously used devise_invitable with a `:limit` on
106
+ `:invitation_token`, remove it:
107
+
108
+ ```ruby
109
+ def up
110
+ change_column :users, :invitation_token, :string, limit: nil
111
+ end
112
+
113
+ def down
114
+ change_column :users, :invitation_token, :string, limit: 60
115
+ end
116
+ ```
117
+
118
+ ## Mongoid Field Definitions
119
+ If you are using Mongoid, define the following fields and indexes within your
120
+ invitable model:
121
+
122
+ ```ruby
123
+ field :invitation_token, type: String
124
+ field :invitation_created_at, type: Time
125
+ field :invitation_sent_at, type: Time
126
+ field :invitation_accepted_at, type: Time
127
+ field :invitation_limit, type: Integer
128
+
129
+ index( { invitation_token: 1 }, { background: true} )
130
+ index( { invitation_by_id: 1 }, { background: true} )
131
+ ```
132
+
133
+ You do not need to define a `belongs_to` relationship, as DeviseInvitable does
134
+ this on your behalf:
135
+ ```ruby
136
+ belongs_to :invited_by, polymorphic: true
137
+ ```
138
+
139
+ Remember to create indexes within the MongoDB database after deploying your
140
+ changes.
141
+ ```shell
142
+ rake db:mongoid:create_indexes
143
+ ```
144
+
145
+ ## Model configuration
146
+
147
+ DeviseInvitable adds some new configuration options:
148
+
149
+ * `invite_for`: The period the generated invitation token is valid. After
150
+ this period, the invited resource won't be able to accept the invitation.
151
+ When `invite_for` is `0` (the default), the invitation won't expire.
152
+
153
+
154
+ You can set this configuration option in the Devise initializer as follow:
155
+
156
+ ```ruby
157
+ # ==> Configuration for :invitable
158
+ # The period the generated invitation token is valid.
159
+ # After this period, the invited resource won't be able to accept the invitation.
160
+ # When invite_for is 0 (the default), the invitation won't expire.
161
+ # config.invite_for = 2.weeks
162
+ ```
163
+
164
+ or directly as parameters to the `devise` method:
165
+
166
+ ```ruby
167
+ devise :database_authenticatable, :confirmable, :invitable, invite_for: 2.weeks
168
+ ```
169
+
170
+ * `invitation_limit`: The number of invitations users can send. The default
171
+ value of `nil` means users can send as many invites as they want, there is
172
+ no limit for any user, `invitation_limit` column is not used. A setting
173
+ of `0` means they can't send invitations. A setting `n > 0` means they can
174
+ send `n` invitations. You can change `invitation_limit` column for some
175
+ users so they can send more or less invitations, even with global
176
+ `invitation_limit = 0`.
177
+
178
+ * `invite_key`: The key to be used to check existing users when sending an
179
+ invitation. You can use multiple keys. This value must be a hash with the
180
+ invite key as hash keys, and values that respond to the `===` operator
181
+ (including procs and regexes). The default value is looking for users by
182
+ email and validating with `Devise.email_regexp`.
183
+
184
+ * `validate_on_invite`: force a record to be valid before being actually
185
+ invited.
186
+
187
+ * `resend_invitation`: resend invitation if user with invited status is
188
+ invited again. Enabled by default.
189
+
190
+ * `invited_by_class_name`: the class name of the inviting model. If this is
191
+ `nil`, polymorphic association is used.
192
+
193
+ * `invited_by_foreign_key`: the foreign key to the inviting model (only used
194
+ if `invited_by_class_name` is set, otherwise `:invited_by_id`)
195
+
196
+ * `invited_by_counter_cache`: the column name used for counter_cache column.
197
+ If this is `nil` (default value), the `invited_by` association is declared
198
+ without `counter_cache`.
199
+
200
+ * `allow_insecure_sign_in_after_accept`: automatically sign in the user
201
+ after they set a password. Enabled by default.
202
+
203
+ * `require_password_on_accepting`: require password when user accepts the
204
+ invitation. Enabled by default. Disable if you don't want to ask or
205
+ enforce to set password while accepting, because is set when user is
206
+ invited or it will be set later.
207
+
208
+
209
+ For more details, see `config/initializers/devise.rb` (after you invoked the
210
+ `devise_invitable:install` generator described above).
211
+
212
+ ## Configuring views
213
+
214
+ All the views are packaged inside the gem. If you'd like to customize the
215
+ views, invoke the following generator and it will copy all the views to your
216
+ application:
217
+
218
+ ```shell
219
+ rails generate devise_invitable:views
220
+ ```
221
+
222
+ You can also use the generator to generate scoped views:
223
+
224
+ ```shell
225
+ rails generate devise_invitable:views users
226
+ ```
227
+
228
+ Then turn scoped views on in `config/initializers/devise.rb`:
229
+
230
+ ```ruby
231
+ config.scoped_views = true
232
+ ```
233
+
234
+ Please refer to [Devise's README](https://github.com/plataformatec/devise) for
235
+ more information about views.
236
+
237
+ ## Configuring controllers
238
+
239
+ To change the controller's behavior, create a controller that inherits from
240
+ `Devise::InvitationsController`. The available methods are: `new`, `create`,
241
+ `edit`, and `update`. Refer to the [original controllers source](https://github.com/scambra/devise_invitable/blob/master/app/controllers/devise/invitations_controller.rb)
242
+ before editing any of these actions. Your
243
+ controller might now look something like this:
244
+
245
+ ```ruby
246
+ class Users::InvitationsController < Devise::InvitationsController
247
+ def update
248
+ if some_condition
249
+ redirect_to root_path
250
+ else
251
+ super
252
+ end
253
+ end
254
+ end
255
+ ```
256
+
257
+ Now just tell Devise that you want to use your controller, the controller
258
+ above is `'users/invitations'`, so our routes.rb would have this line:
259
+
260
+ ```ruby
261
+ devise_for :users, controllers: { invitations: 'users/invitations' }
262
+ ```
263
+
264
+ be sure that you generate the views and put them into the controller that you
265
+ generated, so for this example it would be:
266
+
267
+ ```shell
268
+ rails generate devise_invitable:views users
269
+ ```
270
+
271
+ To change behaviour of inviting or accepting users, you can simply override
272
+ two methods:
273
+
274
+ ```ruby
275
+ class Users::InvitationsController < Devise::InvitationsController
276
+ private
277
+
278
+ # This is called when creating invitation.
279
+ # It should return an instance of resource class.
280
+ def invite_resource
281
+ # skip sending emails on invite
282
+ super { |user| user.skip_invitation = true }
283
+ end
284
+
285
+ # This is called when accepting invitation.
286
+ # It should return an instance of resource class.
287
+ def accept_resource
288
+ resource = resource_class.accept_invitation!(update_resource_params)
289
+ # Report accepting invitation to analytics
290
+ Analytics.report('invite.accept', resource.id)
291
+ resource
292
+ end
293
+ end
294
+ ```
295
+
296
+ ## Strong Parameters
297
+
298
+ When you customize your own views, you may end up adding new attributes to
299
+ forms. Rails 4 moved the parameter sanitization from the model to the
300
+ controller, causing DeviseInvitable to handle this concern at the controller
301
+ as well. Read about it in [Devise
302
+ README](https://github.com/plataformatec/devise#strong-parameters)
303
+
304
+ There are just two actions in DeviseInvitable that allows any set of
305
+ parameters to be passed down to the model, therefore requiring sanitization.
306
+ Their names and the permited parameters by default are:
307
+
308
+ * `invite` (Devise::InvitationsController#create) - Permits only the
309
+ authentication keys (like `email`)
310
+ * `accept_invitation` (Devise::InvitationsController#update) - Permits
311
+ `invitation_token` plus `password` and `password_confirmation`.
312
+
313
+ Here is an example of the steps needed to add a first_name, last_name and role to invited Users.
314
+
315
+ 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.
316
+
317
+ ### Configuring your application controller to accept :first_name, :last_name, and :role for a User
318
+
319
+ Note: These modifications can be applied directly in the InvitationsController if not needed for other Devise actions.
320
+
321
+ ```ruby
322
+ before_action :configure_permitted_parameters, if: :devise_controller?
323
+
324
+ protected
325
+
326
+ # Permit the new params here.
327
+ def configure_permitted_parameters
328
+ devise_parameter_sanitizer.permit(:invite, keys: [:first_name, :last_name, :role])
329
+ end
330
+ ```
331
+
332
+ ### Define your roles in the User model
333
+
334
+ ```ruby
335
+ class User < ApplicationRecord
336
+ has_many :models
337
+
338
+ enum role: {Role 1 Name: 0, Role 2 Name: 1, Role 3 Name: 2, etc...}
339
+ end
340
+ ```
341
+
342
+ ### In the Invitation view
343
+
344
+ ```ruby
345
+ <h2><%= t "devise.invitations.new.header" %></h2>
346
+
347
+ <%= form_for(resource, as: resource_name, url: invitation_path(resource_name), html: { method: :post }) do |f| %>
348
+ <%= render "devise/shared/error_messages", resource: resource %>
349
+ <% resource.class.invite_key_fields.each do |field| -%>
350
+ <div class="field">
351
+ <%= f.label field %><br />
352
+ <%= f.text_field field %>
353
+ </div>
354
+ <% end %>
355
+
356
+ <div class="field">
357
+ <%= f.label :first_name %>
358
+ <%= f.text_field :first_name %>
359
+ </div>
360
+
361
+ <div class="field">
362
+ <%= f.label :last_name %>
363
+ <%= f.text_field :last_name %>
364
+ </div>
365
+
366
+ <div class="field">
367
+ <%= f.label :role %>
368
+ <%= f.select :role, options_for_select(User.roles.map { |key, value| [key.humanize, key] }), {prompt: "Select Role"} %>
369
+ </div>
370
+
371
+ <div class="actions">
372
+ <%= f.submit t("devise.invitations.new.submit_button") %>
373
+ </div>
374
+ <% end %>
375
+ ```
376
+
377
+ ## Usage
378
+
379
+ ### Send an invitation
380
+
381
+ To send an invitation to a user, use the `invite!` class method. **Note: This
382
+ will create a user, and send an email for the invite.** `:email` must be
383
+ present in the parameters hash. You can also include other attributes in the
384
+ hash. The record will not be validated.
385
+
386
+ ```ruby
387
+ User.invite!(email: 'new_user@example.com', name: 'John Doe')
388
+ # => an invitation email will be sent to new_user@example.com
389
+ ```
390
+
391
+ If you want to create the invitation but not send it, you can set
392
+ `skip_invitation` to `true`.
393
+
394
+ ```ruby
395
+ user = User.invite!(email: 'new_user@example.com', name: 'John Doe') do |u|
396
+ u.skip_invitation = true
397
+ end
398
+ # => the record will be created, but the invitation email will not be sent
399
+ ```
400
+
401
+ When generating the `accept_user_invitation_url` yourself, you must use the
402
+ `raw_invitation_token`. This value is temporarily available when you invite a
403
+ user and will be decrypted when received.
404
+
405
+ ```ruby
406
+ accept_user_invitation_url(invitation_token: user.raw_invitation_token)
407
+ ```
408
+
409
+ When `skip_invitation` is used, you must also then set the
410
+ `invitation_sent_at` field when the user is sent their token. Failure to do so
411
+ will yield "Invalid invitation token" error when the user attempts to accept
412
+ the invite. You can set the column, or call `deliver_invitation` to send the
413
+ invitation and set the column:
414
+
415
+ ```ruby
416
+ user.deliver_invitation
417
+ ```
418
+
419
+ You can add `:skip_invitation` to attributes hash if `skip_invitation` is
420
+ added to `attr_accessible`.
421
+
422
+ ```ruby
423
+ User.invite!(email: 'new_user@example.com', name: 'John Doe', skip_invitation: true)
424
+ # => the record will be created, but the invitation email will not be sent
425
+ ```
426
+
427
+ `skip_invitation` skips sending the email, but sets `invitation_token`, so
428
+ `invited_to_sign_up?` on the resulting user returns `true`.
429
+
430
+ To check if a particular user is created by invitation, irrespective to state
431
+ of invitation one can use `created_by_invite?`
432
+
433
+ **Warning**
434
+
435
+ When using `skip_invitation` you must send the email with the user object
436
+ instance that generated the tokens, as `user.raw_invitation_token` is
437
+ available only to the instance and is not persisted in the database.
438
+
439
+ You can also set `invited_by` when using the `invite!` class method:
440
+
441
+ ```ruby
442
+ User.invite!({ email: 'new_user@example.com' }, current_user) # current_user will be set as invited_by
443
+ ```
444
+
445
+ ### Sending an invitation after user creation
446
+
447
+ You can send an invitation to an existing user if your workflow creates them
448
+ separately:
449
+
450
+ ```ruby
451
+ user = User.find(42)
452
+ user.invite!(current_user) # current user is optional to set the invited_by attribute
453
+ ```
454
+
455
+ ### Find by invitation token
456
+
457
+ To find by invitation token use the `find_by_invitation_token` class method.
458
+
459
+ ```ruby
460
+ user = User.find_by_invitation_token(params[:invitation_token], true)
461
+ ```
462
+
463
+ ### Accept an invitation
464
+
465
+ To accept an invitation with a token use the `accept_invitation!` class
466
+ method. `:invitation_token` must be present in the parameters hash. You can
467
+ also include other attributes in the hash.
468
+
469
+ ```ruby
470
+ User.accept_invitation!(invitation_token: params[:invitation_token], password: 'ad97nwj3o2', name: 'John Doe')
471
+ ```
472
+
473
+ ### Callbacks
474
+
475
+ A callback event is fired before and after an invitation is created
476
+ (User#invite!) or accepted (User#accept_invitation!). For example, in your
477
+ resource model you can add:
478
+
479
+ ```ruby
480
+ # Note: callbacks should be placed after devise: :invitable is specified.
481
+ before_invitation_created :email_admins
482
+ after_invitation_accepted :email_invited_by
483
+
484
+ def email_admins
485
+ # ...
486
+ end
487
+
488
+ def email_invited_by
489
+ # ...
490
+ end
491
+ ```
492
+
493
+ The callbacks support all options and arguments available to the standard
494
+ callbacks provided by ActiveRecord.
495
+
496
+ ### Scopes
497
+
498
+ A pair of scopes to find those users that have accepted, and those that have
499
+ not accepted, invitations are defined:
500
+
501
+ ```ruby
502
+ User.invitation_accepted # => returns all Users for whom the invitation_accepted_at attribute is not nil
503
+ User.invitation_not_accepted # => returns all Users for whom the invitation_accepted_at attribute is nil
504
+ User.created_by_invite # => returns all Users who are created by invitations, irrespective to invitation status
505
+ ```
506
+
507
+ ## Integration in a Rails application
508
+
509
+ Since the invitations controller takes care of all the creation/acceptation of
510
+ an invitation, in most cases you wouldn't call the `invite!` and
511
+ `accept_invitation!` methods directly. Instead, in your views, put a link to
512
+ `new_user_invitation_path` or `new_invitation_path(:user)` or even
513
+ `/users/invitation/new` to prepare and send an invitation (to a user in this
514
+ example).
515
+
516
+ After an invitation is created and sent, the inviter will be redirected to
517
+ `after_invite_path_for(inviter, invitee)`, which is the same path as
518
+ `signed_in_root_path` by default.
519
+
520
+ After an invitation is accepted, the invitee will be redirected to
521
+ `after_accept_path_for(resource)`, which is the same path as
522
+ `signed_in_root_path` by default. If you want to override the path, override
523
+ invitations controller and define `after_accept_path_for` method. This is
524
+ useful in the common case that a user is invited to a specific location in
525
+ your application. More on [Devise's
526
+ README](https://github.com/plataformatec/devise), "Controller filters and
527
+ helpers" section.
528
+
529
+ The invitation email includes a link to accept the invitation that looks like
530
+ this: `/users/invitation/accept?invitation_token=abcd123`. When clicked, the
531
+ invited must set a password in order to accept its invitation. Note that if
532
+ the `invitation_token` is not present or not valid, the invited is redirected
533
+ to `invalid_token_path_for(resource_name)`, which by default is
534
+ `after_sign_out_path_for(resource_name)`.
535
+
536
+ The controller sets the `invited_by_id` attribute for the new user to the
537
+ current user. This will let you easily keep track of who invited whom.
538
+
539
+ ## Controller filter
540
+
541
+ InvitationsController uses `authenticate_inviter!` filter to restrict who can
542
+ send invitations. You can override this method in your
543
+ `ApplicationController`.
544
+
545
+ Default behavior requires authentication of the same resource as the invited
546
+ one. For example, if your model `User` is invitable, it will allow all
547
+ authenticated users to send invitations to other users.
548
+
549
+ You would have a `User` model which is configured as invitable and an `Admin`
550
+ model which is not. If you want to allow only admins to send invitations,
551
+ simply overwrite the `authenticate_inviter!` method as follow:
552
+
553
+ ```ruby
554
+ class ApplicationController < ActionController::Base
555
+ protected
556
+
557
+ def authenticate_inviter!
558
+ authenticate_admin!(force: true)
559
+ end
560
+ end
561
+ ```
562
+
563
+ And include `DeviseInvitable::Inviter` module into `Admin` model:
564
+
565
+ ```ruby
566
+ class Admin < ActiveRecord::Base
567
+ devise :database_authenticatable, :validatable
568
+ include DeviseInvitable::Inviter
569
+ end
570
+ ```
571
+
572
+ ## Has many invitations
573
+
574
+ If you want to get all records invited by a resource, you should define
575
+ `has_many` association in the model allowed to send invitations.
576
+
577
+ For the default behavior, define it like this:
578
+
579
+ ```ruby
580
+ has_many :invitations, class_name: self.to_s, as: :invited_by
581
+ ```
582
+
583
+ For the previous example, where admins send invitations to users, define it
584
+ like this:
585
+
586
+ ```ruby
587
+ has_many :invitations, class_name: 'User', as: :invited_by
588
+ ```
589
+
590
+ ## I18n
591
+
592
+ DeviseInvitable uses flash messages with I18n with the flash keys
593
+ `:send_instructions`, `:invitation_token_invalid` and `:updated`. To customize
594
+ your app, you can modify the generated locale file:
595
+
596
+ ```yaml
597
+ en:
598
+ devise:
599
+ invitations:
600
+ send_instructions: 'An invitation email has been sent to %{email}.'
601
+ invitation_token_invalid: 'The invitation token provided is not valid!'
602
+ updated: 'Your password was set successfully. You are now signed in.'
603
+ updated_not_active: 'Your password was set successfully.'
604
+ ```
605
+
606
+ You can also create distinct messages based on the resource you've configured
607
+ using the singular name given in routes:
608
+
609
+ ```yaml
610
+ en:
611
+ devise:
612
+ invitations:
613
+ user:
614
+ send_instructions: 'A new user invitation has been sent to %{email}.'
615
+ invitation_token_invalid: 'Your invitation token is not valid!'
616
+ updated: 'Welcome on board! You are now signed in.'
617
+ updated_not_active: 'Welcome on board! Sign in to continue.'
618
+ ```
619
+
620
+ The DeviseInvitable mailer uses the same pattern as Devise to create mail
621
+ subject messages:
622
+
623
+ ```yaml
624
+ en:
625
+ devise:
626
+ mailer:
627
+ invitation_instructions:
628
+ subject: 'You got an invitation!'
629
+ user_subject: 'You got a user invitation!'
630
+ ```
631
+
632
+ Take a look at the [generated locale file](https://github.com/scambra/devise_invitable/blob/master/config/locales/en.yml) to check all available messages.
633
+
634
+ Check out [wiki](https://github.com/scambra/devise_invitable/wiki/I18n) for
635
+ translations.
636
+
637
+ ### Use with sub schema
638
+ If you are using sub schema in you application, you need to make sure that you
639
+ are prioritizing your sub schema scheme over Warden in Rack. For instance, if
640
+ you are using the Apartment gem go inside your `config/application.rb` file,
641
+ add the following lines:
642
+
643
+ ```ruby
644
+ module YourSite
645
+ class Application < Rails::Application
646
+ ...
647
+ Rails.application.config.middleware.insert_before Warden::Manager, Apartment::Elevators::Subdomain
648
+ end
649
+ end
650
+ ```
651
+
652
+
653
+ ## Other ORMs
654
+
655
+ DeviseInvitable supports ActiveRecord and Mongoid, like Devise.
656
+
657
+ ## Wiki
658
+
659
+ It's possible to find additional information about DeviseInvitable on the
660
+ Wiki:
661
+
662
+ https://github.com/scambra/devise_invitable/wiki
663
+
664
+ ## Testing
665
+
666
+ To run tests:
667
+
668
+ ```shell
669
+ bundle install
670
+ bundle exec rake test
671
+ ```
672
+
673
+ ## Contributors
674
+
675
+ Check them all at:
676
+
677
+ https://github.com/scambra/devise_invitable/contributors
678
+
679
+ Special thanks to [rymai](https://github.com/rymai) for the Rails 3 support,
680
+ his fork was a great help.
681
+
682
+ ## Note on Patches/Pull Requests
683
+
684
+ * Fork the project.
685
+ * Make your feature addition or bug fix.
686
+ * Add tests for it. This is important so I don't break it in a future
687
+ version unintentionally.
688
+ * Commit, do not mess with rakefile, version, or history. (if you want to
689
+ have your own version, that is fine but bump version in a commit by itself
690
+ I can ignore when I pull)
691
+ * Send me a pull request. Bonus points for topic branches.
692
+
693
+
694
+ ## Copyright
695
+
696
+ Copyright (c) 2019 Sergio Cambra. See LICENSE for details.