devise_invitable 1.1.6 → 1.1.7
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of devise_invitable might be problematic. Click here for more details.
- data/README.rdoc +24 -0
- data/app/controllers/devise/invitations_controller.rb +18 -7
- data/app/controllers/devise_invitable/registrations_controller.rb +1 -1
- data/config/locales/en.yml +1 -0
- data/lib/devise_invitable/model.rb +18 -5
- data/lib/devise_invitable/routes.rb +1 -0
- data/lib/devise_invitable/version.rb +1 -1
- data/lib/generators/active_record/templates/migration.rb +1 -1
- metadata +5 -4
data/README.rdoc
CHANGED
@@ -32,12 +32,14 @@ Replace MODEL by the class name you want to add DeviseInvitable, like User, Admi
|
|
32
32
|
|
33
33
|
Follow the walkthrough for Devise and after it's done, follow this walkthrough.
|
34
34
|
|
35
|
+
== Devise Configuration
|
35
36
|
Add :invitable to the <tt>devise</tt> call in your model (we’re assuming here you already have a User model with some Devise modules):
|
36
37
|
|
37
38
|
class User < ActiveRecord::Base
|
38
39
|
devise :database_authenticatable, :confirmable, :invitable
|
39
40
|
end
|
40
41
|
|
42
|
+
== ActiveRecord Migration
|
41
43
|
Add t.invitable to your Devise model migration:
|
42
44
|
|
43
45
|
create_table :users do
|
@@ -67,6 +69,25 @@ or for a model that already exists, define a migration to add DeviseInvitable to
|
|
67
69
|
|
68
70
|
# Allow null encrypted_password
|
69
71
|
change_column :users, :encrypted_password, :string, :null => true
|
72
|
+
# Allow null password_salt (add it if you are using Devise's encryptable module)
|
73
|
+
change_column :users, :password_salt, :string, :null => true
|
74
|
+
|
75
|
+
== Mongoid Field Definitions
|
76
|
+
If you are using Mongoid, define the following fields and indexes within your invitable model:
|
77
|
+
|
78
|
+
field :invitation_token, type: String
|
79
|
+
field :invitation_sent_at, type: Time
|
80
|
+
field :invitation_accepted_at, type: Time
|
81
|
+
field :invitation_limit, type: Integer
|
82
|
+
|
83
|
+
index( {invitation_token: 1}, {:background => true} )
|
84
|
+
index( {invitation_by_id: 1}, {:background => true} )
|
85
|
+
|
86
|
+
You do not need to define a belongs_to relationship, as DeviseInvitable does this on your behalf:
|
87
|
+
belongs_to :invited_by, :polymorphic => true
|
88
|
+
|
89
|
+
Remember to create indexes within the MongoDB database after deploying your changes.
|
90
|
+
rake db:mongoid:create_indexes
|
70
91
|
|
71
92
|
== Model configuration
|
72
93
|
|
@@ -153,6 +174,9 @@ You can add :skip_invitation to attributes hash if skip_invitation is added to a
|
|
153
174
|
User.invite!(:email => "new_user@example.com", :name => "John Doe", :skip_invitation => true)
|
154
175
|
# => the record will be created, but the invitation email will not be sent
|
155
176
|
|
177
|
+
Skip_invitation skips sending the email, but sets invitation_token, so invited_to_sign_up? on the
|
178
|
+
resulting user returns true.
|
179
|
+
|
156
180
|
You can send an invitation to an existing user if your workflow creates them separately:
|
157
181
|
|
158
182
|
user = User.find(42)
|
@@ -2,7 +2,8 @@ class Devise::InvitationsController < DeviseController
|
|
2
2
|
|
3
3
|
before_filter :authenticate_inviter!, :only => [:new, :create]
|
4
4
|
before_filter :has_invitations_left?, :only => [:create]
|
5
|
-
before_filter :require_no_authentication, :only => [:edit, :update]
|
5
|
+
before_filter :require_no_authentication, :only => [:edit, :update, :destroy]
|
6
|
+
before_filter :resource_from_invitation_token, :only => [:edit, :destroy]
|
6
7
|
helper_method :after_sign_in_path_for
|
7
8
|
|
8
9
|
# GET /resource/invitation/new
|
@@ -25,12 +26,7 @@ class Devise::InvitationsController < DeviseController
|
|
25
26
|
|
26
27
|
# GET /resource/invitation/accept?invitation_token=abcdef
|
27
28
|
def edit
|
28
|
-
|
29
|
-
render :edit
|
30
|
-
else
|
31
|
-
set_flash_message(:alert, :invitation_token_invalid)
|
32
|
-
redirect_to after_sign_out_path_for(resource_name)
|
33
|
-
end
|
29
|
+
render :edit
|
34
30
|
end
|
35
31
|
|
36
32
|
# PUT /resource/invitation
|
@@ -46,6 +42,13 @@ class Devise::InvitationsController < DeviseController
|
|
46
42
|
respond_with_navigational(resource){ render :edit }
|
47
43
|
end
|
48
44
|
end
|
45
|
+
|
46
|
+
# GET /resource/invitation/remove?invitation_token=abcdef
|
47
|
+
def destroy
|
48
|
+
resource.destroy
|
49
|
+
set_flash_message :notice, :invitation_removed
|
50
|
+
redirect_to after_sign_out_path_for(resource_name)
|
51
|
+
end
|
49
52
|
|
50
53
|
protected
|
51
54
|
def current_inviter
|
@@ -59,5 +62,13 @@ class Devise::InvitationsController < DeviseController
|
|
59
62
|
respond_with_navigational(resource) { render :new }
|
60
63
|
end
|
61
64
|
end
|
65
|
+
|
66
|
+
def resource_from_invitation_token
|
67
|
+
unless params[:invitation_token] && self.resource = resource_class.to_adapter.find_first(params.slice(:invitation_token))
|
68
|
+
set_flash_message(:alert, :invitation_token_invalid)
|
69
|
+
redirect_to after_sign_out_path_for(resource_name)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
62
73
|
end
|
63
74
|
|
@@ -7,7 +7,7 @@ class DeviseInvitable::RegistrationsController < Devise::RegistrationsController
|
|
7
7
|
self.resource = resource_class.where(:email => hash[:email], :encrypted_password => '').first
|
8
8
|
if self.resource
|
9
9
|
self.resource.attributes = hash
|
10
|
-
self.resource.accept_invitation
|
10
|
+
self.resource.accept_invitation
|
11
11
|
end
|
12
12
|
end
|
13
13
|
self.resource ||= super
|
data/config/locales/en.yml
CHANGED
@@ -5,6 +5,7 @@ en:
|
|
5
5
|
invitation_token_invalid: 'The invitation token provided is not valid!'
|
6
6
|
updated: 'Your password was set successfully. You are now signed in.'
|
7
7
|
no_invitations_remaining: "No invitations remaining"
|
8
|
+
invitation_removed: 'Your invitation was removed.'
|
8
9
|
new:
|
9
10
|
header: "Send invitation"
|
10
11
|
submit_button: "Send an invitation"
|
@@ -36,13 +36,17 @@ module Devise
|
|
36
36
|
|
37
37
|
include ActiveSupport::Callbacks
|
38
38
|
define_callbacks :invitation_accepted
|
39
|
+
before_update :generate_confirmation_token, :if => :confirmation_required_for_invited?
|
40
|
+
after_update :send_on_create_confirmation_instructions, :if => :confirmation_required_for_invited?
|
39
41
|
|
40
42
|
attr_writer :skip_password
|
41
43
|
|
42
|
-
scope :
|
44
|
+
scope :active, lambda { where(:confirmation_token => nil) }
|
43
45
|
if defined?(Mongoid) && self < Mongoid::Document
|
46
|
+
scope :invitation_not_accepted, lambda { where(:invitation_accepted_at => nil, :confirmation_token.ne => nil) }
|
44
47
|
scope :invitation_accepted, lambda { where(:invitation_accepted_at.ne => nil) }
|
45
48
|
else
|
49
|
+
scope :invitation_not_accepted, lambda { where(arel_table[:confirmation_token].not_eq(nil)).where(:invitation_accepted_at => nil) }
|
46
50
|
scope :invitation_accepted, lambda { where(arel_table[:invitation_accepted_at].not_eq(nil)) }
|
47
51
|
|
48
52
|
[:before_invitation_accepted, :after_invitation_accepted].each do |callback_method|
|
@@ -71,12 +75,17 @@ module Devise
|
|
71
75
|
end
|
72
76
|
|
73
77
|
# Accept an invitation by clearing invitation token and and setting invitation_accepted_at
|
74
|
-
|
78
|
+
def accept_invitation
|
79
|
+
self.invitation_accepted_at = Time.now.utc
|
80
|
+
self.invitation_token = nil
|
81
|
+
end
|
82
|
+
|
83
|
+
# Accept an invitation by clearing invitation token and and setting invitation_accepted_at
|
84
|
+
# Saves the model and confirms it if model is confirmable, running invitation_accepted callbacks
|
75
85
|
def accept_invitation!
|
76
86
|
if self.invited_to_sign_up? && self.valid?
|
77
|
-
self.invitation_accepted_at = Time.now.utc
|
78
87
|
run_callbacks :invitation_accepted do
|
79
|
-
self.
|
88
|
+
self.accept_invitation
|
80
89
|
self.confirmed_at = self.invitation_accepted_at if self.respond_to?(:confirmed_at)
|
81
90
|
self.save(:validate => false)
|
82
91
|
end
|
@@ -120,7 +129,7 @@ module Devise
|
|
120
129
|
end
|
121
130
|
|
122
131
|
generate_invitation_token if self.invitation_token.nil?
|
123
|
-
self.invitation_sent_at = Time.now.utc
|
132
|
+
self.invitation_sent_at = Time.now.utc unless @skip_invitation
|
124
133
|
self.invited_by = invited_by if invited_by
|
125
134
|
|
126
135
|
# Call these before_validate methods since we aren't validating on save
|
@@ -163,6 +172,10 @@ module Devise
|
|
163
172
|
!@skip_password && super
|
164
173
|
end
|
165
174
|
|
175
|
+
def confirmation_required_for_invited?
|
176
|
+
respond_to?(:confirmation_required?) && confirmation_required? && invitation_accepted?
|
177
|
+
end
|
178
|
+
|
166
179
|
# Deliver the invitation email
|
167
180
|
def deliver_invitation
|
168
181
|
send_devise_notification(:invitation_instructions)
|
@@ -6,6 +6,7 @@ module ActionDispatch::Routing
|
|
6
6
|
resource :invitation, :only => [:new, :create, :update],
|
7
7
|
:path => mapping.path_names[:invitation], :controller => controllers[:invitations] do
|
8
8
|
get :edit, :path => mapping.path_names[:accept], :as => :accept
|
9
|
+
get :destroy, :path => mapping.path_names[:remove], :as => :remove
|
9
10
|
end
|
10
11
|
end
|
11
12
|
|
@@ -6,7 +6,7 @@ class DeviseInvitableAddTo<%= table_name.camelize %> < ActiveRecord::Migration
|
|
6
6
|
t.datetime :invitation_accepted_at
|
7
7
|
t.integer :invitation_limit
|
8
8
|
t.references :invited_by, :polymorphic => true
|
9
|
-
t.index :invitation_token # for invitable
|
9
|
+
t.index :invitation_token, :unique => true # for invitable
|
10
10
|
t.index :invited_by_id
|
11
11
|
end
|
12
12
|
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: devise_invitable
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 29
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 1
|
8
8
|
- 1
|
9
|
-
-
|
10
|
-
version: 1.1.
|
9
|
+
- 7
|
10
|
+
version: 1.1.7
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Sergio Cambra
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2013-
|
18
|
+
date: 2013-04-01 00:00:00 Z
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
21
21
|
name: bundler
|
@@ -162,3 +162,4 @@ specification_version: 3
|
|
162
162
|
summary: An invitation strategy for Devise
|
163
163
|
test_files: []
|
164
164
|
|
165
|
+
has_rdoc:
|