devise_invitable 2.0.5 → 2.0.7
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.
Potentially problematic release.
This version of devise_invitable might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +10 -0
- data/README.rdoc +61 -4
- data/app/controllers/devise/invitations_controller.rb +3 -3
- data/config/locales/ca.yml +32 -0
- data/config/locales/de.yml +31 -31
- data/config/locales/es.yml +1 -1
- data/lib/devise_invitable/controllers/helpers.rb +4 -0
- data/lib/devise_invitable/mapping.rb +4 -2
- data/lib/devise_invitable/models.rb +3 -2
- data/lib/devise_invitable/version.rb +1 -1
- data/lib/generators/devise_invitable/devise_invitable_generator.rb +1 -1
- data/test/functional/controller_helpers_test.rb +10 -0
- data/test/mailers/invitation_mail_test.rb +1 -1
- data/test/model_tests_helper.rb +1 -1
- data/test/models/invitable_test.rb +2 -2
- data/test/orm/active_record.rb +6 -1
- data/test/test_helper.rb +1 -1
- metadata +4 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f2a7d1c4ae3cc61e2992fa9920ddd35e6626745dd32333a88e8231fb267e2cb0
|
4
|
+
data.tar.gz: ee68fbb505a629c391934bee8c644c0ade499333d5c7065745426fd6e419642a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: fd3ead62e8c2246f9246fbac3a2138ea6ff4f1abcf3c577faad920b339f1c1795b54497d03b34f4bc685be6131f62692d2497fbc5d1081e740e0a85d7e1a25c2
|
7
|
+
data.tar.gz: 0453554d47731a99e931c81dbd44e77eca935ff6ca453172f40f394da84bd1d5a92507aafa881ab491202cee5fa534aef4ba9b2a4ac1fa37327a664c7ceb8e61
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,13 @@
|
|
1
|
+
- Allow customizing invalid_token_path_for, the path to redirect users who try to accept with invalid token
|
2
|
+
- Don't override registrations controller in routes if module option is used
|
3
|
+
- Fix typo in spanish translation, add Catalan translation ([#857](https://github.com/scambra/devise_invitable/pull/857))
|
4
|
+
- Fix for ruby 3.2.0
|
5
|
+
|
6
|
+
## 2.0.6
|
7
|
+
- Fix submit form failure with turbolinks, fixes ([#865](https://github.com/scambra/devise_invitable/issues/865))
|
8
|
+
- Fix obsolete symbols in German translation ([#864](https://github.com/scambra/devise_invitable/pull/864))
|
9
|
+
- Allow to provide validate option to the instance method "invite!", default to follow the setting validate_on_invite
|
10
|
+
|
1
11
|
## 2.0.5
|
2
12
|
- Fix NoMethodError in random_password when validatable is not used ([#850](https://github.com/scambra/devise_invitable/pull/850))
|
3
13
|
|
data/README.rdoc
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
= DeviseInvitable
|
2
|
-
{<img src="https://badge.fury.io/rb/devise_invitable.svg"/>}[http://badge.fury.io/rb/devise_invitable]
|
2
|
+
{<img src="https://badge.fury.io/rb/devise_invitable.svg"/>}[http://badge.fury.io/rb/devise_invitable]
|
3
|
+
{<img src="https://github.com/scambra/devise_invitable/actions/workflows/ci.yml/badge.svg"/>}[https://github.com/scambra/devise_invitable/actions/workflows/ci.yml]
|
4
|
+
{<img src="https://codeclimate.com/github/scambra/devise_invitable/badges/gpa.svg"/>}[https://codeclimate.com/github/scambra/devise_invitable]
|
3
5
|
|
4
6
|
It adds support to Devise[https://github.com/plataformatec/devise] for sending invitations by email (it requires to be authenticated) and accept the invitation setting the password.
|
5
7
|
|
@@ -35,14 +37,14 @@ Replace MODEL by the class name you want to add DeviseInvitable, like <tt>User</
|
|
35
37
|
|
36
38
|
Follow the walkthrough for Devise and after it's done, follow this walkthrough.
|
37
39
|
|
38
|
-
|
40
|
+
==== Devise Configuration
|
39
41
|
Add <tt>:invitable</tt> to the <tt>devise</tt> call in your model (we’re assuming here you already have a User model with some Devise modules):
|
40
42
|
|
41
43
|
class User < ActiveRecord::Base
|
42
44
|
devise :database_authenticatable, :confirmable, :invitable
|
43
45
|
end
|
44
46
|
|
45
|
-
|
47
|
+
==== ActiveRecord Migration
|
46
48
|
Add <tt>t.invitable</tt> to your Devise model migration:
|
47
49
|
|
48
50
|
create_table :users do
|
@@ -217,6 +219,61 @@ Here is an example of what your application controller might need to include in
|
|
217
219
|
devise_parameter_sanitizer.permit(:accept_invitation, keys: [:first_name, :last_name, :phone])
|
218
220
|
end
|
219
221
|
|
222
|
+
Here is an example setting a User's first name, last name, and role for a custom invitation:
|
223
|
+
|
224
|
+
#Configuring the InvitationsController to accept :first_name, :last_name, and :role
|
225
|
+
|
226
|
+
class Users::InvitationsController < Devise::InvitationsController
|
227
|
+
before_action :configure_permitted_parameters
|
228
|
+
|
229
|
+
protected
|
230
|
+
|
231
|
+
# Permit the new params here.
|
232
|
+
def configure_permitted_parameters
|
233
|
+
devise_parameter_sanitizer.permit(:invite, keys: [:first_name, :last_name, :role])
|
234
|
+
end
|
235
|
+
end
|
236
|
+
|
237
|
+
#Define your roles in the User model
|
238
|
+
|
239
|
+
class User < ApplicationRecord
|
240
|
+
has_many :models
|
241
|
+
|
242
|
+
enum role: {Role 1 Name: 0, Role 2 Name: 1, Role 3 Name: 2, etc...}
|
243
|
+
end
|
244
|
+
|
245
|
+
#In the Invitation view
|
246
|
+
|
247
|
+
<h2><%= t "devise.invitations.new.header" %></h2>
|
248
|
+
|
249
|
+
<%= form_for(resource, as: resource_name, url: invitation_path(resource_name), html: { method: :post }) do |f| %>
|
250
|
+
<%= render "devise/shared/error_messages", resource: resource %>
|
251
|
+
<% resource.class.invite_key_fields.each do |field| -%>
|
252
|
+
<div class="field">
|
253
|
+
<%= f.label field %><br />
|
254
|
+
<%= f.text_field field %>
|
255
|
+
</div>
|
256
|
+
<% end %>
|
257
|
+
|
258
|
+
<div class="field">
|
259
|
+
<%= f.label :first_name %>
|
260
|
+
<%= f.text_field :first_name %>
|
261
|
+
</div>
|
262
|
+
|
263
|
+
<div class="field">
|
264
|
+
<%= f.label :last_name %>
|
265
|
+
<%= f.text_field :last_name %>
|
266
|
+
</div>
|
267
|
+
|
268
|
+
<div class="field">
|
269
|
+
<%= f.label :role %>
|
270
|
+
<%= f.select :role, options_for_select(User.roles.map { |key, value| [key.humanize, key] }), {prompt: "Select Role"} %>
|
271
|
+
</div>
|
272
|
+
|
273
|
+
<div class="actions">
|
274
|
+
<%= f.submit t("devise.invitations.new.submit_button") %>
|
275
|
+
</div>
|
276
|
+
<% end %>
|
220
277
|
|
221
278
|
== Usage
|
222
279
|
|
@@ -315,7 +372,7 @@ After an invitation is created and sent, the inviter will be redirected to <tt>a
|
|
315
372
|
|
316
373
|
After an invitation is accepted, the invitee will be redirected to <tt>after_accept_path_for(resource)</tt>, which is the same path as <tt>signed_in_root_path</tt> by default. If you want to override the path, override invitations controller and define <tt>after_accept_path_for</tt> 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}[https://github.com/plataformatec/devise], "Controller filters and helpers" section.
|
317
374
|
|
318
|
-
The invitation email includes a link to accept the invitation that looks like this: <tt>/users/invitation/accept?invitation_token=abcd123</tt>. When clicked, the invited must set a password in order to accept its invitation. Note that if the <tt>invitation_token</tt> is not present or not valid, the invited is redirected to <tt>after_sign_out_path_for(resource_name)</tt>.
|
375
|
+
The invitation email includes a link to accept the invitation that looks like this: <tt>/users/invitation/accept?invitation_token=abcd123</tt>. When clicked, the invited must set a password in order to accept its invitation. Note that if the <tt>invitation_token</tt> is not present or not valid, the invited is redirected to <tt>invalid_token_path_for(resource_name)</tt>, which by default is <tt>after_sign_out_path_for(resource_name)</tt>.
|
319
376
|
|
320
377
|
The controller sets the <tt>invited_by_id</tt> attribute for the new user to the current user. This will let you easily keep track of who invited whom.
|
321
378
|
|
@@ -31,7 +31,7 @@ class Devise::InvitationsController < DeviseController
|
|
31
31
|
respond_with resource, location: after_invite_path_for(current_inviter, resource)
|
32
32
|
end
|
33
33
|
else
|
34
|
-
respond_with_navigational(resource) { render :new }
|
34
|
+
respond_with_navigational(resource) { render :new, status: :unprocessable_entity }
|
35
35
|
end
|
36
36
|
end
|
37
37
|
|
@@ -63,7 +63,7 @@ class Devise::InvitationsController < DeviseController
|
|
63
63
|
end
|
64
64
|
else
|
65
65
|
resource.invitation_token = raw_invitation_token
|
66
|
-
respond_with_navigational(resource) { render :edit }
|
66
|
+
respond_with_navigational(resource) { render :edit, status: :unprocessable_entity }
|
67
67
|
end
|
68
68
|
end
|
69
69
|
|
@@ -99,7 +99,7 @@ class Devise::InvitationsController < DeviseController
|
|
99
99
|
def resource_from_invitation_token
|
100
100
|
unless params[:invitation_token] && self.resource = resource_class.find_by_invitation_token(params[:invitation_token], true)
|
101
101
|
set_flash_message(:alert, :invitation_token_invalid) if is_flashing_format?
|
102
|
-
redirect_to
|
102
|
+
redirect_to invalid_token_path_for(resource_name)
|
103
103
|
end
|
104
104
|
end
|
105
105
|
|
@@ -0,0 +1,32 @@
|
|
1
|
+
|
2
|
+
ca:
|
3
|
+
devise:
|
4
|
+
failure:
|
5
|
+
invited: "Tens una invitació pendent, accepta-la per acabar de crear el teu compte."
|
6
|
+
invitations:
|
7
|
+
send_instructions: "S'ha enviat una invitació a %{email}."
|
8
|
+
invitation_token_invalid: "La invitació no es vàlida!"
|
9
|
+
updated: "S'ha configurat la seva contrasenya i s'ha ingressat al sistema"
|
10
|
+
updated_not_active: "La seva contrasenya s'ha configurat correctament."
|
11
|
+
no_invitations_remaining: "No queden invitacions"
|
12
|
+
invitation_removed: "S'ha retirat la seva invitació"
|
13
|
+
new:
|
14
|
+
header: "Enviar Invitació"
|
15
|
+
submit_button: "Envia una invitació"
|
16
|
+
edit:
|
17
|
+
header: "Establir contrasenya"
|
18
|
+
submit_button: "Guardar la meva contrasenya"
|
19
|
+
mailer:
|
20
|
+
invitation_instructions:
|
21
|
+
subject: "Instruccions de la invitació"
|
22
|
+
hello: "Hola %{email}"
|
23
|
+
someone_invited_you: "Has estat invitat a %{url}, pots acceptar-ho seguint el següent enllaç"
|
24
|
+
accept: "Aceptar la invitació"
|
25
|
+
accept_until: "Aquesta invitació expirarà en %{due_date}."
|
26
|
+
ignore: "Si no li interessa aquesta invitació, simplement ignori aquest correu. No es crearà el teu compte fins que accedeixis a l'anterior enllaç i creïs una contrasenya"
|
27
|
+
time:
|
28
|
+
formats:
|
29
|
+
devise:
|
30
|
+
mailer:
|
31
|
+
invitation_instructions:
|
32
|
+
accept_until_format: "%d de %B de %Y, %H:%M"
|
data/config/locales/de.yml
CHANGED
@@ -1,31 +1,31 @@
|
|
1
|
-
de:
|
2
|
-
devise:
|
3
|
-
failure:
|
4
|
-
invited: "Du hast bereits eine Einladung erhalten. Nimm die Einladung an um dein Nutzerkonto zu erstellen."
|
5
|
-
invitations:
|
6
|
-
send_instructions: "Eine Einladung wurde an %{email} verschickt."
|
7
|
-
invitation_token_invalid: "Der Einladungs-Code ist ungültig!"
|
8
|
-
updated: "Dein Passwort wurde gesetzt. Du bist nun angemeldet."
|
9
|
-
updated_not_active: "Dein Passwort wurde gesetzt."
|
10
|
-
no_invitations_remaining: "Es gibt keine weiteren Einladungen"
|
11
|
-
invitation_removed: "Deine Einladung wurde gelöscht."
|
12
|
-
new:
|
13
|
-
header: "Einladung schicken"
|
14
|
-
submit_button: "Einladung schicken"
|
15
|
-
edit:
|
16
|
-
header: "Setze ein Passwort"
|
17
|
-
submit_button: "Passwort setzen"
|
18
|
-
mailer:
|
19
|
-
invitation_instructions:
|
20
|
-
subject: "Einladung"
|
21
|
-
hello: "Hallo %{email}"
|
22
|
-
someone_invited_you: "Jemand hat dich zu %{url} eingeladen. Du kannst die Einladung mit dem Link unten annehmen."
|
23
|
-
accept: "Einladung annehmen"
|
24
|
-
accept_until: "Diese Einladung ist gültig bis zum %{due_date}."
|
25
|
-
ignore: "Wenn du die Einladung nicht annehmen willst, ignoriere diese E-Mail einfach
|
26
|
-
time:
|
27
|
-
formats:
|
28
|
-
devise:
|
29
|
-
mailer:
|
30
|
-
invitation_instructions:
|
31
|
-
accept_until_format: "%d. %B %Y %H:%M"
|
1
|
+
de:
|
2
|
+
devise:
|
3
|
+
failure:
|
4
|
+
invited: "Du hast bereits eine Einladung erhalten. Nimm die Einladung an um dein Nutzerkonto zu erstellen."
|
5
|
+
invitations:
|
6
|
+
send_instructions: "Eine Einladung wurde an %{email} verschickt."
|
7
|
+
invitation_token_invalid: "Der Einladungs-Code ist ungültig!"
|
8
|
+
updated: "Dein Passwort wurde gesetzt. Du bist nun angemeldet."
|
9
|
+
updated_not_active: "Dein Passwort wurde gesetzt."
|
10
|
+
no_invitations_remaining: "Es gibt keine weiteren Einladungen"
|
11
|
+
invitation_removed: "Deine Einladung wurde gelöscht."
|
12
|
+
new:
|
13
|
+
header: "Einladung schicken"
|
14
|
+
submit_button: "Einladung schicken"
|
15
|
+
edit:
|
16
|
+
header: "Setze ein Passwort"
|
17
|
+
submit_button: "Passwort setzen"
|
18
|
+
mailer:
|
19
|
+
invitation_instructions:
|
20
|
+
subject: "Einladung"
|
21
|
+
hello: "Hallo %{email}"
|
22
|
+
someone_invited_you: "Jemand hat dich zu %{url} eingeladen. Du kannst die Einladung mit dem Link unten annehmen."
|
23
|
+
accept: "Einladung annehmen"
|
24
|
+
accept_until: "Diese Einladung ist gültig bis zum %{due_date}."
|
25
|
+
ignore: "Wenn du die Einladung nicht annehmen willst, ignoriere diese E-Mail einfach. Es wird kein Benutzerkonto erstellt solange du nicht die Einladung mittels des Links oben annimmst."
|
26
|
+
time:
|
27
|
+
formats:
|
28
|
+
devise:
|
29
|
+
mailer:
|
30
|
+
invitation_instructions:
|
31
|
+
accept_until_format: "%d. %B %Y %H:%M"
|
data/config/locales/es.yml
CHANGED
@@ -17,7 +17,7 @@ es:
|
|
17
17
|
submit_button: "Guardar mi contraseña"
|
18
18
|
mailer:
|
19
19
|
invitation_instructions:
|
20
|
-
subject: "
|
20
|
+
subject: "Instrucciones de la invitación"
|
21
21
|
hello: "Hola %{email}"
|
22
22
|
someone_invited_you: "Has sido invitado a %{url}, puedes aceptarlo siguiendo el siguiente enlace"
|
23
23
|
accept: "Aceptar la invitación"
|
@@ -3,8 +3,10 @@ module DeviseInvitable
|
|
3
3
|
private
|
4
4
|
|
5
5
|
def default_controllers(options)
|
6
|
-
options[:
|
7
|
-
|
6
|
+
unless options[:module]
|
7
|
+
options[:controllers] ||= {}
|
8
|
+
options[:controllers][:registrations] ||= 'devise_invitable/registrations'
|
9
|
+
end
|
8
10
|
super
|
9
11
|
end
|
10
12
|
end
|
@@ -158,7 +158,8 @@ module Devise
|
|
158
158
|
self.downcase_keys if new_record_and_responds_to?(:downcase_keys)
|
159
159
|
self.strip_whitespace if new_record_and_responds_to?(:strip_whitespace)
|
160
160
|
|
161
|
-
|
161
|
+
validate = options.key?(:validate) ? options[:validate] : self.class.validate_on_invite
|
162
|
+
if save(validate: validate)
|
162
163
|
self.invited_by.decrement_invitation_limit! if !was_invited and self.invited_by.present?
|
163
164
|
deliver_invitation(options) unless skip_invitation
|
164
165
|
end
|
@@ -324,7 +325,7 @@ module Devise
|
|
324
325
|
end
|
325
326
|
|
326
327
|
yield invitable if block_given?
|
327
|
-
mail = invitable.invite!(nil, options) if invitable.errors.empty?
|
328
|
+
mail = invitable.invite!(nil, options.merge(validate: false)) if invitable.errors.empty?
|
328
329
|
[invitable, mail]
|
329
330
|
end
|
330
331
|
|
@@ -7,7 +7,7 @@ module DeviseInvitable
|
|
7
7
|
|
8
8
|
def inject_devise_invitable_content
|
9
9
|
path = File.join('app', 'models', "#{file_path}.rb")
|
10
|
-
inject_into_file(path, 'invitable, :', after: 'devise :') if File.
|
10
|
+
inject_into_file(path, 'invitable, :', after: 'devise :') if File.exist?(path)
|
11
11
|
end
|
12
12
|
|
13
13
|
hook_for :orm
|
@@ -41,4 +41,14 @@ class ControllerHelpersTest < ActionController::TestCase
|
|
41
41
|
assert Devise::InvitationsController.method_defined? :after_accept_path_for
|
42
42
|
assert !Devise::InvitationsController.instance_methods(false).include?(:after_accept_path_for)
|
43
43
|
end
|
44
|
+
|
45
|
+
test 'invalid token path defaults to after sign out path' do
|
46
|
+
assert_equal @controller.send(:after_sign_out_path_for, :user), @controller.invalid_token_path_for(:user)
|
47
|
+
end
|
48
|
+
|
49
|
+
test 'invalid token path is customizable from application controller' do
|
50
|
+
custom_path = 'customized/invalid/token/path'
|
51
|
+
@controller.instance_eval "def invalid_token_path_for(resource_name) '#{custom_path}' end"
|
52
|
+
assert_equal @controller.invalid_token_path_for(:user), custom_path
|
53
|
+
end
|
44
54
|
end
|
@@ -102,7 +102,7 @@ class InvitationMailTest < ActionMailer::TestCase
|
|
102
102
|
def initialize(*args); end
|
103
103
|
def deliver; end
|
104
104
|
end
|
105
|
-
Devise.mailer = CustomMailer
|
105
|
+
Devise.mailer = 'InvitationMailTest::CustomMailer'
|
106
106
|
|
107
107
|
User.invite!({ email: 'valid@email.com' }, nil, { invited_at: Time.now })
|
108
108
|
end
|
data/test/model_tests_helper.rb
CHANGED
@@ -89,12 +89,12 @@ class InvitableTest < ActiveSupport::TestCase
|
|
89
89
|
user.invite!
|
90
90
|
old_invitation_created_at = 3.days.ago
|
91
91
|
old_invitation_sent_at = 3.days.ago
|
92
|
-
user.
|
92
|
+
user.update(invitation_sent_at: old_invitation_sent_at, invitation_created_at: old_invitation_created_at)
|
93
93
|
3.times do
|
94
94
|
user.invite!
|
95
95
|
refute_equal old_invitation_sent_at, user.invitation_sent_at
|
96
96
|
refute_equal old_invitation_created_at, user.invitation_created_at
|
97
|
-
user.
|
97
|
+
user.update(invitation_sent_at: old_invitation_sent_at, invitation_created_at: old_invitation_created_at)
|
98
98
|
end
|
99
99
|
end
|
100
100
|
|
data/test/orm/active_record.rb
CHANGED
@@ -1,7 +1,12 @@
|
|
1
1
|
ActiveRecord::Migration.verbose = false
|
2
2
|
ActiveRecord::Base.logger = Logger.new(nil)
|
3
3
|
|
4
|
-
if
|
4
|
+
if ActiveRecord::VERSION::MAJOR >= 6
|
5
|
+
ActiveRecord::MigrationContext.new(
|
6
|
+
File.expand_path('../../rails_app/db/migrate/', __FILE__),
|
7
|
+
ActiveRecord::Base.connection.schema_migration
|
8
|
+
).migrate
|
9
|
+
elsif defined? ActiveRecord::MigrationContext # rails >= 5.2
|
5
10
|
ActiveRecord::MigrationContext.new(File.expand_path('../../rails_app/db/migrate/', __FILE__)).migrate
|
6
11
|
else
|
7
12
|
ActiveRecord::Migrator.migrate(File.expand_path('../../rails_app/db/migrate/', __FILE__))
|
data/test/test_helper.rb
CHANGED
@@ -7,7 +7,7 @@ require "rails_app/config/environment"
|
|
7
7
|
require 'rails/test_help'
|
8
8
|
require "orm/#{DEVISE_ORM}"
|
9
9
|
require 'capybara/rails'
|
10
|
-
require 'mocha/
|
10
|
+
require 'mocha/minitest'
|
11
11
|
|
12
12
|
ActionMailer::Base.delivery_method = :test
|
13
13
|
ActionMailer::Base.perform_deliveries = true
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: devise_invitable
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.0.
|
4
|
+
version: 2.0.7
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sergio Cambra
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2023-01-09 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: actionmailer
|
@@ -70,6 +70,7 @@ files:
|
|
70
70
|
- app/views/devise/mailer/invitation_instructions.html.erb
|
71
71
|
- app/views/devise/mailer/invitation_instructions.text.erb
|
72
72
|
- config/locales/ar.yml
|
73
|
+
- config/locales/ca.yml
|
73
74
|
- config/locales/da.yml
|
74
75
|
- config/locales/de.yml
|
75
76
|
- config/locales/en.yml
|
@@ -186,7 +187,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
186
187
|
- !ruby/object:Gem::Version
|
187
188
|
version: '0'
|
188
189
|
requirements: []
|
189
|
-
rubygems_version: 3.
|
190
|
+
rubygems_version: 3.3.7
|
190
191
|
signing_key:
|
191
192
|
specification_version: 4
|
192
193
|
summary: An invitation strategy for Devise
|