DeviseInvitable - thuy-econsys/rails_app GitHub Wiki
Install devise_invitable
gem and run bundle install
.
Run rails generate devise_invitable:install
to insert DeviseInvitable configurations into the Devise configuration file as well as create a yaml internationalization file for DeviseInvitable.
Run rails generate devise_invitable User
to auto-generate a DeviseInvitable User model and migration file to add DeviseInvitable to User model.
Or, manually spin up your own migration and add the :invitable
flag to your User model devise modules because that's what the generator basically does.
rails g migration AddColumnsToUsers invitation_token:string:uniq invitation_created_at:datetime invitation_sent_at:datetime invitation_accepted_at:datetime invitation_limit:integer invited_by_id:integer invited_by_type:string
...should give you a migration file to run rails db:migrate
and update your schema:
class AddColumnsToUsers < ActiveRecord::Migration[5.2]
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
end
Here are the routes created for DeviseInvitable:
Prefix Verb URI Pattern Controller#Action
cancel_user_registration GET /users/cancel(.:format) devise_invitable/registrations#cancel
new_user_registration GET /users/sign_up(.:format) devise_invitable/registrations#new
edit_user_registration GET /users/edit(.:format) devise_invitable/registrations#edit
user_registration PATCH /users(.:format) devise_invitable/registrations#update
PUT /users(.:format) devise_invitable/registrations#update
DELETE /users(.:format) devise_invitable/registrations#destroy
POST /users(.:format) devise_invitable/registrations#create
accept_user_invitation GET /users/invitation/accept(.:format) devise/invitations#edit
remove_user_invitation GET /users/invitation/remove(.:format) devise/invitations#destroy
new_user_invitation GET /users/invitation/new(.:format) devise/invitations#new
user_invitation PATCH /users/invitation(.:format) devise/invitations#update
PUT /users/invitation(.:format) devise/invitations#update
POST /users/invitation(.:format) devise/invitations#create
Inside the rails console, run User.invite!(:email => "[email protected]")
to test out DeviseInvitable
This will generate a simulation of the Devise::Mailer#invitation_instructions process. Inside the email body, there will be a link, http://localhost:3000/users/invitation/accept?invitation_token=<random_token_here>
which will take you to a page for setting a password for the user.
In the rails server, you can follow along the routes that the process takes:
HTTP Controller#action Rendered View paths
GET "/users/sign_in" Devise::SessionsController#new devise/shared/_links.html.erb
devise/sessions/new.html.erb within layouts/application
GET "/users/invitation/accept?invitation_token=<token> Devise::InvitationsController#edit devise/invitations/edit.html.erb
Parameters: {"invitation_token"=>"<token>"}
PUT "/users/invitation" Devise::InvitationsController#update devise/invitations/edit.html.erb
Redirected to http://localhost:3000/
Parameters: {"utf8"=>"✓", "authenticity_token"=>"<auth_token>", "user"=>{"invitation_token"=>"<token>", "password"=>"[FILTERED]", "password_confirmation"=>"[FILTERED]"}, "commit"=>"Set my password"}
Note that for the HTTP PUT action, there are 2 updates:
User Update (0.6ms) UPDATE "users" SET "invitation_token" = $1, "encrypted_password" = $2, "invitation_accepted_at" = $3, "updated_at" = $4 WHERE "users"."id" = $5
[["invitation_token", nil], ["encrypted_password", "<hash>"], ["invitation_accepted_at", "2020-10-05 22:26:26.373091"], ["updated_at", "2020-10-05 22:26:26.374717"], ["id", 74]]
User Update (0.6ms) UPDATE "users" SET "sign_in_count" = $1, "current_sign_in_at" = $2, "last_sign_in_at" = $3, "current_sign_in_ip" = $4, "last_sign_in_ip" = $5, "updated_at" = $6 WHERE "users"."id" = $7
[["sign_in_count", 1], ["current_sign_in_at", "2020-10-05 22:26:26.380368"], ["last_sign_in_at", "2020-10-05 22:26:26.380368"], ["current_sign_in_ip", "::1/128"], ["last_sign_in_ip", "::1/128"], ["updated_at", "2020-10-05 22:26:26.381536"], ["id", 74]]
Those are attributes that you can access in the rails console, if you're interested:
2.5.1 :033 > User.last.last_sign_in_ip
User Load (0.6ms) SELECT "users".* FROM "users" ORDER BY "users"."id" DESC LIMIT $1 [["LIMIT", 1]]
=> #<IPAddr: IPv6:0000:0000:0000:0000:0000:0000:0000:0001/ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff>
seed some data but skip the invitation process, u.skip_invitation = true
:
def adduser(email, password)
@user = User.invite!(:email => email) do |u|
u.skip_invitation = true
end
token = Devise::VERSION >= "3.1.0" ? @user.instance_variable_get(:@raw_invitation_token) : @user.invitation_token
User.accept_invitation!(:invitation_token => token, :password => password, :password_confirmation => password)
puts "Created User #{email} with password #{password}"
@user
end