Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

「発展編 omniauth を使って GitHub 認証を実装する」の差分 #9

Open
wants to merge 19 commits into
base: 21-github_login
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
GITHUB_ID=(your id)
GITHUB_SECRET=(your secret)
4 changes: 4 additions & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ gem 'image_processing', '~> 1.2'
group :development, :test do
# See https://guides.rubyonrails.org/debugging_rails_applications.html#debugging-with-the-debug-gem
gem 'debug', platforms: %i[mri mingw x64_mingw]
gem 'dotenv-rails'
end

group :development do
Expand Down Expand Up @@ -86,4 +87,7 @@ gem 'carrierwave'
gem 'devise'
gem 'devise-i18n'
gem 'kaminari'
gem 'omniauth'
gem 'omniauth-github'
gem 'omniauth-rails_csrf_protection'
gem 'rails_autolink'
42 changes: 42 additions & 0 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,10 @@ GEM
warden (~> 1.2.3)
devise-i18n (1.11.0)
devise (>= 4.9.0)
dotenv (2.8.1)
dotenv-rails (2.8.1)
dotenv (= 2.8.1)
railties (>= 3.2)
erb_lint (0.4.0)
activesupport
better_html (>= 2.0.1)
Expand All @@ -121,9 +125,14 @@ GEM
erubi (1.12.0)
faker (3.2.0)
i18n (>= 1.8.11, < 2)
faraday (2.7.10)
faraday-net_http (>= 2.0, < 3.1)
ruby2_keywords (>= 0.0.4)
faraday-net_http (3.0.2)
ffi (1.15.5)
globalid (1.1.0)
activesupport (>= 5.0)
hashie (5.0.0)
i18n (1.14.1)
concurrent-ruby (~> 1.0)
i18n_generators (2.2.2)
Expand All @@ -142,6 +151,7 @@ GEM
actionview (>= 5.0.0)
activesupport (>= 5.0.0)
json (2.6.3)
jwt (2.7.1)
kaminari (1.2.2)
activesupport (>= 4.1.0)
kaminari-actionview (= 1.2.2)
Expand Down Expand Up @@ -179,6 +189,7 @@ GEM
mini_portile2 (2.8.4)
minitest (5.19.0)
msgpack (1.7.2)
multi_xml (0.6.0)
net-imap (0.3.7)
date
net-protocol
Expand All @@ -192,6 +203,26 @@ GEM
nokogiri (1.15.3)
mini_portile2 (~> 2.8.2)
racc (~> 1.4)
oauth2 (2.0.9)
faraday (>= 0.17.3, < 3.0)
jwt (>= 1.0, < 3.0)
multi_xml (~> 0.5)
rack (>= 1.2, < 4)
snaky_hash (~> 2.0)
version_gem (~> 1.1)
omniauth (2.1.1)
hashie (>= 3.4.6)
rack (>= 2.2.3)
rack-protection
omniauth-github (2.0.1)
omniauth (~> 2.0)
omniauth-oauth2 (~> 1.8)
omniauth-oauth2 (1.8.0)
oauth2 (>= 1.4, < 3)
omniauth (~> 2.0)
omniauth-rails_csrf_protection (1.0.1)
actionpack (>= 4.2)
omniauth (~> 2.0)
orm_adapter (0.5.0)
parallel (1.23.0)
parser (3.2.2.3)
Expand All @@ -202,6 +233,8 @@ GEM
nio4r (~> 2.0)
racc (1.7.1)
rack (2.2.8)
rack-protection (3.0.6)
rack
rack-test (2.1.0)
rack (>= 1.3)
rails (7.0.6)
Expand Down Expand Up @@ -270,12 +303,16 @@ GEM
ruby-progressbar (1.13.0)
ruby-vips (2.1.4)
ffi (~> 1.12)
ruby2_keywords (0.0.5)
rubyzip (2.3.2)
selenium-webdriver (4.11.0)
rexml (~> 3.2, >= 3.2.5)
rubyzip (>= 1.2.2, < 3.0)
websocket (~> 1.0)
smart_properties (1.17.0)
snaky_hash (2.0.1)
hashie
version_gem (~> 1.1, >= 1.1.1)
sprockets (4.2.0)
concurrent-ruby (~> 1.0)
rack (>= 2.2.4, < 4)
Expand All @@ -297,6 +334,7 @@ GEM
tzinfo (2.0.6)
concurrent-ruby (~> 1.0)
unicode-display_width (2.4.2)
version_gem (1.1.3)
warden (1.2.9)
rack (>= 2.0.9)
web-console (4.2.0)
Expand All @@ -322,6 +360,7 @@ DEPENDENCIES
debug
devise
devise-i18n
dotenv-rails
erb_lint
faker
i18n_generators
Expand All @@ -330,6 +369,9 @@ DEPENDENCIES
jbuilder
kaminari
letter_opener_web
omniauth
omniauth-github
omniauth-rails_csrf_protection
puma
rails (~> 7.0.6)
rails_autolink
Expand Down
19 changes: 19 additions & 0 deletions app/controllers/users/omniauth_callbacks_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# frozen_string_literal: true

class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController
def github
@user = User.from_omniauth(request.env['omniauth.auth'])

if @user.persisted?
sign_in_and_redirect @user, event: :authentication
set_flash_message(:notice, :success, kind: 'GitHub') if is_navigational_format?
else
alert = t('devise.omniauth_callbacks.failure', kind: 'GitHub', reason: @user.errors.full_messages.join(', '))
redirect_to new_user_session_url, alert:
end
end

def failure
redirect_to new_user_session_url
end
end
18 changes: 18 additions & 0 deletions app/controllers/users/registrations_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# frozen_string_literal: true

class Users::RegistrationsController < Devise::RegistrationsController
protected

# Override
def update_resource(resource, params)
if params[:password].blank?
# パスワード変更を伴わない場合はオーバーライドする
# current_passwordが残っていると、これを更新しようとしてエラーになるのでparamsから削除
params.delete(:current_password)
resource.update_without_password(params)
else
# パスワード変更を伴う場合はデフォルトの実装を使う
super
end
end
end
13 changes: 12 additions & 1 deletion app/models/user.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@

class User < ApplicationRecord
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :validatable
:recoverable, :rememberable, :validatable,
:omniauthable, omniauth_providers: %i[github]

has_many :reports, dependent: :destroy
has_many :comments, dependent: :destroy
Expand All @@ -11,6 +12,16 @@ class User < ApplicationRecord
attachable.variant :thumb, resize_to_limit: [150, 150]
end

validates :uid, uniqueness: { scope: :provider }, if: -> { uid.present? }

def self.from_omniauth(auth)
find_or_create_by(provider: auth.provider, uid: auth.uid) do |user|
user.name = auth.info.name
user.email = auth.info.email
user.password = Devise.friendly_token[0, 20]
end
end

def name_or_email
name.presence || email
end
Expand Down
2 changes: 1 addition & 1 deletion app/views/devise/shared/_links.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@

<%- if devise_mapping.omniauthable? %>
<%- resource_class.omniauth_providers.each do |provider| %>
<%= link_to t('.sign_in_with_provider', provider: OmniAuth::Utils.camelize(provider)), omniauth_authorize_path(resource_name, provider), method: :post %><br />
<%= button_to t('.sign_in_with_provider', provider: OmniAuth::Utils.camelize(provider)), omniauth_authorize_path(resource_name, provider), data: { turbo: false } %><br />
<% end %>
<% end %>
</nav>
5 changes: 4 additions & 1 deletion config/initializers/devise.rb
Original file line number Diff line number Diff line change
Expand Up @@ -271,7 +271,10 @@
# ==> OmniAuth
# Add a new OmniAuth provider. Check the wiki for more information on setting
# up on your models and hooks.
# config.omniauth :github, 'APP_ID', 'APP_SECRET', scope: 'user,public_repo'
if ENV["GITHUB_ID"].blank? || ENV["GITHUB_SECRET"].blank?
raise "環境変数 GITHUB_ID と GITHUB_SECRET を設定してください。(開発環境ではdotenv-railsを利用してください)"
end
config.omniauth :github, ENV["GITHUB_ID"], ENV["GITHUB_SECRET"], scope: "user"

# ==> Warden configuration
# If you want to use other strategies, that are not supported by Devise, or
Expand Down
2 changes: 1 addition & 1 deletion config/routes.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Rails.application.routes.draw do
mount LetterOpenerWeb::Engine, at: "/letter_opener" if Rails.env.development?
devise_for :users
devise_for :users, controllers: { omniauth_callbacks: 'users/omniauth_callbacks', registrations: "users/registrations" }
root to: 'books#index'
resources :books do
scope module: :books do
Expand Down
7 changes: 7 additions & 0 deletions db/migrate/20230103055415_add_omniauth_to_users.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
class AddOmniauthToUsers < ActiveRecord::Migration[7.0]
def change
add_column :users, :provider, :string
add_column :users, :uid, :string
add_index :users, %i[provider uid], unique: true
end
end
3 changes: 3 additions & 0 deletions db/schema.rb

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

18 changes: 17 additions & 1 deletion test/system/devise_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ class DeviseTest < ApplicationSystemTestCase
# バリデーションエラーを発生させる
fill_in 'Eメール', with: ''
click_button '更新'
assert_text '2 件のエラーが発生したため ユーザ は保存されませんでした。'
assert_text 'エラーが発生したため ユーザ は保存されませんでした。'

fill_in 'Eメール', with: '[email protected]'
fill_in '氏名', with: 'ありす'
Expand Down Expand Up @@ -134,4 +134,20 @@ class DeviseTest < ApplicationSystemTestCase
click_button 'パスワードを変更する'
assert_text 'パスワードが正しく変更されました。'
end

test 'delete account' do
visit root_path

fill_in 'Eメール', with: '[email protected]'
fill_in 'パスワード', with: 'password'
click_button 'ログイン'
assert_text 'ログインしました。'

click_link 'アカウント編集'
accept_alert do
click_button 'アカウント削除'
end
assert_text 'アカウントを削除しました。またのご利用をお待ちしております。'
assert_current_path new_user_session_path
end
end
24 changes: 24 additions & 0 deletions test/system/oauth_test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# frozen_string_literal: true

require 'application_system_test_case'

class OAuthTest < ApplicationSystemTestCase
setup do
OmniAuth.config.test_mode = true
OmniAuth.config.add_mock(:github, { uid: '12345', info: { name: 'Alice', email: '[email protected]' } })
end

test 'GitHub sign up' do
visit root_path
assert_css 'h2', text: 'ログイン'
click_button 'GitHubでログイン'
assert_text 'GitHub アカウントによる認証に成功しました。'
assert_text 'Alice としてログイン中'
click_link 'ユーザ'
assert_css 'h1', text: 'ユーザの一覧'
within '#users' do
assert_text '[email protected]'
assert_text 'Alice'
end
end
end