EC2インスタンスにログインできる新ユーザー作成及びローカルで鍵を作成しSSH通信によるインスタンスへのログイン

どうもどハマりエンジニアです。

 

<対象>

・すでにEC2インスタンスを作成

・Elstatic IP アドレスの関連付けができている。

 

<さっそくやってみよう!!!>

 インスタンス作成時にEC2にログインするために必要となるキーペアをダウンロードしたと思います。作成した公開鍵をsshフォルダに移動させます(移動はさせなくても出来る) 。 読み書きができる権限を付与し、公開鍵を利用し、すでにAWSでデフォルトであるユーザー(ec2-user)を使いログインします。

 $: mv Downloads/myserverkey.pem/
(#作成した公開鍵をsshフォルダに移動)
 $: cd .ssh/
(#ディレクトリをsshに移動)
 $: chmod 600 myserverkey.pem
(#公開鍵に600番で定義されたアクセス権を付与する)
 $: ssh -i myserverkey.pem ec2-user@18.222.239.124
(#公開鍵を利用してec2-userとしてログイン)

ここまできたら新たなユーザーを作成し、作成したユーザーにマスター権限を与えていきます。

[ec2-user|~]$ sudo adduser yoshihiro
(#新規ユーザー名の登録)
[ec2-user|~]$ sudo passwd yoshihiro
(#新規ユーザー名のパスワード登録)
[ec2-user|~]$ sudo visudo
(#vimを使いrootに関する権限追記をする)

vimで編集モードになったら下記のように追記していきます。

i で編集モード

esc でInputモードを終了

Shift + zzで保存&編集完了

1.rootに関する権限の記述箇所
root    ALL=(ALL)       ALL  を探す。
2.その下に、作成したユーザーに権限を追加する記述
yoshihiro   ALL=(ALL)       ALL  を追加する

編集が完了したら下記のコマンドでユーザーの切り替えを行います。

[ec2-user|~]$ sudo su - yoshihiro

ec2-userのところが作成したユーザー名に変わっていればユーザーの作成は完了です。

ローカルで鍵を生成し、SSH通信によるインスタンスへのログイン

ローカルのターミナル

$ cd .ssh
[.ssh]$ ssh-keygen -t rsa
(#公開鍵を作成)
-----------------------------
Enter file in which to save the key (): app_key_rsa 
(#ここでファイルの名前(なんでもいい)を記述して、エンター)
Enter passphrase (empty for no passphrase): 
(#何もせずそのままエンター)
Enter same passphrase again: 
(#何もせずそのままエンター)
-----------------------------

上記のコマンドより公開鍵(app_key_rsaとapp_key_rsa.pub)を作成することができたので、vimで.sshファイルに設定ファイル(config)を編集していきます。

[.ssh]$ ls
#「app_key_rsa」と「app_key_rsa.pub」が生成されたことを確認
[.ssh]$ vim config
(#Vimを起動し、設定ファイルを編集する)
-----------------------------
# 以下を追記
Host app_key_rsa
  Hostname  18.222.239.124(Elastic IP)
  Port 22
  User yoshihiro (先ほどのユーザー名)
  IdentityFile ~/.ssh/app_key_rsa (#秘密鍵の設定)
-----------------------------
[.ssh]$ cat app_key_rsa.pub
(鍵の中身をターミナル上に出力→後で使うのでコピーしておく)

上記により、

1.ローカルで鍵の生成

2.その鍵をどの通信の認証時に使用するか等を設定

ここまでが完了しました。

続いてはインスタンス側の設定をしていきます

[yoshihiro|~]$ mkdir .ssh
[yoshihiro|~]$ chmod 700 .ssh
[yoshihiro|~]$ cd .ssh
[yoshihiro|.ssh]$ vim authorized_keys
(#vimが開く)
-----------------------------
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDKIYAGCKxDvEf0SNLxHU/iXmAAX8Sm+AqsqUj+7KIxf60KoJWDpvxEhVC7mVG/81rA9qn3vTnm++6g7LfJhxru3SN5jp9RJS6cvHqYP55VpEmEV2baSpHjTsQK4KD/vbSh2+/f+FkL5+XXNTPdX6q/DOV1Jic8uOrKsYQZHd0rGQ4v/ktCRNzjeW+1hG929bjCQrivwH+Q5s9zvGmnLJyMP9TMGD1Q3CqYoDPVhWsbw/hbXUIxgvtUKwZ7WzOCDivtZLutV0omaffc6RBURmmIGh3L7R373yo7QG52gHlIE/hG8+IQW89m5IU2syLifs1QGXV/zFiiHCzpVhbyjnifMa6kw2DZl7z3LH9+qIVU1nUcsjI5NI0zap6sZvSoNYHdubvw0fdg1n2aEgqh+nc8bOAdfUwMgxZPPa40FysmAcN05+dzQ7dUuwli312ohfkmT4qlLC3dh8+QuRUB8zqxrpoImS7VH0l94kJtEKVA8jqglKE= yoshihironoMacBook-Air.local
(#先ほどコピーした鍵の中身を貼り付け)
-----------------------------
[yoshihiro|.ssh]$ chmod 600 authorized_keys
[yoshihiro|.ssh]$ exit
[ec2-user|~]$ exit

以上より新ユーザーに権限が付与されました。 ローカルで下記コマンドを入力し、実際にログインしてみてください

$ ssh app_key_rsa

swiperの使い方にについて

どうもどハマりエンジニアです。

 

本日はswiperを導入し、トップページに一定間隔で複数の画像の切替を行っていきたいと思います。

 

 Swiper.jsとは何?

 Swiper.jsとはスライダーが作れるJavaScriptのライブラリです。

CSSとJSを適用することで、画像などをスライドできる機能を実装するものです。

PCでもスマホでも使えて、レスポンシブ対応していることや、jQueryに依存しません。

 

Swiperを使うための準備

CSS及びJSの適用方法には3種類あります。

  • CDNクラウド上に公開されているCSSとJSを適用させる)
  • ファイルをダウンロードして、愚直にCSSとJSを適用させる
  • NPMというJSのパッケージマネージャ(RubyでいうところのGemを管理するBundlerのようなもの)
    • Yarnという類似のパッケージマネージャーを使うことも可能です

今回はCDNを使いクラウド上に公開されているCSSとJSを使い実装をしていきたいと思います。(一番楽に実装できるとのこと)

 

HTMLのheadタグにcss、bodyタグにjsを以下のコードを貼り付けるだけです。(最バージョンが更新されていれば、最新のバージョンのコードにする必要がある)

 

application.html.slim

head
5.4.5/css/swiper.css'
 
body
Swiper/5.4.5/js/swiper.min.js'
 

 

最新のswiperのバージョンは下記のサイトを参照してください!

cdnjs.com

 

viewsの実装

スライドを実装したいhtmlにswiperでもともとあるクラスを書いていく。

すでにswiper-containerなどのクラスは準備されているので、同じように書いていけばいいです。

app/views/layouts/_header.html.slim

header.swiper-container
  .swiper-wrapper
    - if current_site.main_images.present?
    - current_site.main_images.each do |main_image|
     = image_tag main_image, class: 'swiper-slide'
   - else
     = image_tag '/images/cover.jpg', class: 'swiper-slide'
   .swiper-pagination
   .swiper-button-prev
  .swiper-button-next
  .swiper-scrollbar

 

 

JSの実装

Qiitaなどをみていると、var mySwiper = new Swiper('.swiper-container', {

のように実装しているものが多かったが、下記のようにかかないとjsが反映されないので注意が必要である。

 

app/assets/javascripts/application.js

$(function() {
  new Swiper('.swiper-container', {
    autoplay: {
      delay: 3000,
      stopOnLastSlide: false,
      disableOnInteraction: false,
      reverseDirection: false
  },
    navigation: {
      nextEl: '.swiper-button-next',
      prevEl: '.swiper-button-prev'
    },
    pagination: {
      el: '.swiper-pagination',
      type: 'bullets',
      clickable: true  
    }
  })
});

 

上記の実装だと、ページが3秒の一定間隔で切り替わるようになります。

その他にもページネーションなどの実装を行っています。

 

以上で簡単にスライドを実装することができます!

 

 

検索機能の追加

どうもどハマりエンジニアです。

本日はActiceModelでDBに依存しないモデルを作り、検索機能の実装を行っていきます。

 

今回の勉強内容

・form object

・Active Model

・scope

 

 

form objectとは?

form_withのmodelオプション*1にActive Record以外のオブジェクトを渡すデザインパターンです。form_withのmodelオプションに渡すオブジェクト自体もform objectと呼びます。

利点は大きく次の2点です。

  • DBを使わないフォームでも、Active Recordを利用した場合と同じお作法を利用できるので可読性が増す
  • 他の箇所に分散されがちなロジックをform object内に集めることができ、凝集度を高められる

 

Active Modelとは?

Active RecordからDBに依存する部分を除いた振る舞いを提供しているライブラリです。これを利用することにより、DBを利用しないフォームでもActive Recordを利用したときと同じような記述をすることができます。

 

 

モデルの作成

scopeを使い複数のクエリをまとめたメソッドを作成していきます。

また他テーブルとの結合させるためにjoinsを使用。

 

models/article.rb

belongs_to :category
belongs_to :author
has_many :article_tags
has_many :tags, through: :article_tags
has_many :sentences, through: :article_blocks, source: :blockable, source_type: 'Sentence'
 ・
 ・
 ・
scope :by_category, ->(category_id) { where(category_id: category_id) }
scope :by_state, ->(state) { where(state: state) }
scope :by_tag, ->(tag_id) { joins(:tags).where(article_tags: { tag_id: tag_id }) }
scope :by_author, ->(author_id) { where(author_id: author_id) }
scope :title_contain, ->(word) { where('title LIKE ?', "%#{word}%") }
scope :body_contain, ->(word) { joins(:sentences).merge(where('sentences.body LIKE ?', "%#{word}%")) }

scopeの上から4つ目まではセレクトで選択できるように作成します。下記二つのscopeは文字列から検索出来るように作成します。

上から3つ目のscopeはfoinsを使いtagsテーブルと結合させています。Active Recordでは、joinsメソッドを使用して関連付けでJOIN句を指定する際に、モデルで定義された関連付けの名前をショートカットとして使用できます。なので今回はアソシエーションを組んだtagsを使用します。今回は中間テーブルが存在しますので、article_tagsテーブルのtag_idでクエリを発行させることで条件の合うデータを取得できます。

同じく最後のscopeでもjoinsを使いsentencesテーブルを結合させます。mergeメソッドは直前に行った条件に対して、さらに絞り込みを行いたい時に使います。(今回はなくても機能します)

 

 

ActiveModelを使いDBに依存しないモデルの作成

app/forms/serch_form_atricles.rb

class SearchArticlesForm
  # ActiveModelはモデルではないがまるでモデルかのように扱うことが出来る優れものである。
  include ActiveModel::Model
  include ActiveModel::Attributes

  # ActiveModel::Attributes で属性を定義する
  attribute :category_id, :integer
  attribute :title, :string  
  attribute :author_id, :integer
  attribute :body, :string
  attribute :state, :integer
  attribute :tag_id, :integer

  def search
    # distinctメソッドは重複レコードを1つにまとめるためのメソッド
    relation = Article.distinct
 
    # by_〇〇はモデルのscopeで定義
    relation = relation.by_category(category_id) if category_id.present?
    relation = relation.by_author(author_id) if author_id.present?
    relation = relation.by_state(state) if state.present?
    relation = relation.by_tag(tag_id) if tag_id.present?

    title_words.each do |word|
      relation = relation.title_contain(word)
    end
    body_words.each do |word|
      relation = relation.body_contain(word)
    end
    relation
  end

  private

  def title_words
    title.present? ? title.split(nil) :
  end

  def body_words
    body.present? ? body.split(' ') :
  end
end

 

 

コントローラーの作成

 

app/controllers/admin/articles_controleller.rb

def index
  authorize(Article)

  @search_articles_form = SearchArticlesForm.new(search_params)
  @articles = @search_articles_form.search.order(id: :desc).page(params[:page]).per(25)
end
 ・
 ・
 ・
def search_params
  params[:q]&.permit(:title, :body, :category_id, :author_id, :state, :tag_id)
end

 

 

テンプレートの作成

articles/index.html.slim

= form_with model: @search_articles_form, scope: :q, url: admin_articles_path,
             method: :get, html: { class: 'form-inline' } do |f|
   => f.select :category_id, Category.pluck(:name, :id) ,
                { include_blank: true }, class: 'form-control'
  => f.select :author_id, Author.pluck(:name, :id) ,
                { include_blank: true }, class: 'form-control'
  => f.select :tag_id, Tag.pluck(:name, :id) , { include_blank: true },
                class: 'form-control'
  => f.select :state, Article.states.map{ |k, v| [t("enums.article.
     state.#{k}"), v] }, { include_blank: true }, class: 'form-control'
  .input-group
    = f.search_field :title, class: 'form-control', placeholder: 'タイトル'
  .input-group
    = f.search_field :body, class: 'form-control', placeholder: '本文'
   span.input-group-btn
   = f.submit '検索', class: %w[btn btn-default btn-flat]

pluckは、1つのモデルで使用されているテーブルからカラム (1つでも複数でも可) を取得するクエリを送信するのに使用できます。引数としてカラム名のリストを与えると、指定したカラムの値の配列を、対応するデータ型で返します。今回はnameとidカラム を取得してきて、表示されるのは第一引数、第二引数はパラメーターとして渡されます。

 

 

 

 

Rakeタスクを作り

どうもどハマりエンジニアです。

本日は簡単にRakeタスク について実装したので、まとめていきます。

 

 

記事ステータスの追加

 

まずenumのメソッドが使えるように定義していきます。

i18nの設定

state:
  draft: '下書き'
  published: '公開'
  publish_wait: '公開待ち'

 

モデルの状況 article.rb

enum state: { draft: 0, published: 1, publish_wait: 2 }

 

 

 

Rakeとは

そもそもRakeですが、Rubyで書かれたコードをタスクとして作成しておき必要に応じて呼び出し実行する事が出来る機能です。

rakeタスクを利用する場面としては、こんなのが有ります。

  • 何かしらのデータの連携
  • データベースのバックアップ
  • 定期的にデータを更新、削除する ←今回はこれ

 

Rakeタスクの処理を記述するファイルを作成します。

$ rails g task article_status

するとlib/tasks/article_status.rakeが生成されるのでこのファイルに書いていきます!

 

lib/tasks/article_status.rake

namespace :article_state do
  desc '公開待ちの中で、公開日時が過去になっているものがあれば、ステータスを「公開」に変更されるようにする。'
  task state_change: :environment do
    Article.publish_wait.past_published.each{ |x| x.published! }
  end
end

 

作ったrakeファイルを確認

$ rake -vT

 

実行する

$ rake task_sample:sample

 

DBに接続する場合

namespace :task_sample do
  desc "task_sample_use_model"
  task :task_model => :environment do
    puts User.first().to_yaml  #Userモデルを参照する!
  end
end

上記を実行する
$rake task sample:task model


wheneverを使いcronを管理


Gemfile
gem 'whenever', require: false


下記を実行し、config/schedule.rbファイルを作成する。
$ bundle exec wheneverize .


wheneverでは次の4つをスケジューリングできます。
  • command: bashコマンド実行
  • rake: rakeタスク実行
  • runner: Rails内のメソッドを実行
  • script: scriptの実行

 

下記コマンドでインストールされているcronジョブを一覧表示

crontab -l .

 


config/schedule.rb

# Rails.rootを使用するために必要
require File.expand_path(File.dirname(__FILE__) + "/environment")
# cronを実行する環境変数
rails_env = ENV['RAILS_ENV'] || :development
# cronを実行する環境変数をセット
set :environment, rails_env
# cronのログの吐き出し場所
set :output, "#{Rails.root}/log/cron.log"

every :houre do
  rake 'article_status:update_article_state'
end

今回は1時間ごとに実行させたいので、上記のように設定。

 

 

以上でRakeタスクについての説明でした。



 

 

 

 

 

 

 

パンクズの設定について

どうもどハマりエンジニアです。

 

パンくずとは、パンくずリストを省略した表現で、ユーザーが今WEBサイト内のどの位置にいるのかを視覚的に分かりやすくするため、上位の階層となるWEBページを階層順にリストアップしてリンクを設置したリストのことを指しています。

 

このパンくずをサイトに設置してあげることで、

  • ユーザーがどのページをよんでいるのか瞬時にわかるようにする
  • クローラー巡回を手助けする
  • 内部 SEOに有効

などのメリットがあります。

Gemfile

gem 'gretel'

 

 $bundle install 

$rails generate gretel:install

config配下にbreadcrumb.rbというファイルが生成されるので、そこにパンくずの定義を一元化してまとめた後、viewファイルから呼び出します。

 

config/breadcrumbs.rb

crumb :admin_dashboard do
  link 'Home', admin_dashboard_path
end

crumb :edit_admin_site do
  link '設定', edit_admin_site_path
  parent :admin_dashboard
end

crumb :admin_users do
  link 'ユーザー', admin_users_path
  parent :admin_dashboard
end

crumb :admin_user do |user|
  link 'プロフィール', admin_user_path(user)
  parent :admin_users
end

parentで親を指定してあげることで、前の情報を引き継ぐことができます。

 

users/show.html.slim

- breadcrumb :admin_user, @user

 このように記載してあげるだけで、いい感じに表示してくれるようになります。

 

Rspecの環境構築から必須のgemの解説と

 

 

どうもどハマりエンジニアです。

ここ最近は仕事等が忙しく更新出来ませんでしたが、仕事も落ち着いてきたので本日からまたしっかりと更新できるように頑張りたいと思います。

 

       目次
  • Rspecの環境構築
  • gem(factory_bot_rails や capybara)
  • モデルスペック
  • システムスペック

 

 

環境構築

gemの追加(capybaraやwebdriverなど必要なgemも追加しておく) 

 

Gemfile

group :development, :test do
  gem 'rspec-rails', '~> 3.8'
  gem 'byebug', platforms: [:mri, :mingw, :x64_mingw]
  gem 'factory_bot_rails'
end

 

group :test do
  gem 'capybara'
  gem 'webdriver'
end

 

 

 スペックディレクトリ等を作成

$ bundle exec rails g rspec:install

create .rspec

create spec
create spec/spec_helper.rb

create spec/rails_helper.rb 

 

 

RSpec の出力をデフォルトの形式から読みやすいドキュメント形式へ

.rspec

--require spec_helper

--format documentation

これによってテストスイートの実行中にどのスペックがパスし、どのスペ ックが失敗したのかがわかりやすくなります。それだけでなく、スペックのアウトラインが美しく出力されます。

 

 

generateコマンドで一緒にスペックファイルも作成

 rails generate コマンドを使ってアプリケーションにコードを追加 する際に、RSpec 用のスペックファイルも一緒に作ってもらうよう Rails を設定しましょう。

 

config/application.rb

config.generators do |g|
 
g.test_framework :rspec,
           view_specs: false,
           helper_specs: false,
           routing_specs: false,
           controller_specs: false,
           model_specs: true,
           request_specs: false,
           fixtures: true
g.fixture_replacement :factory_bot, dir: 'spec/factories'

 

view_specs: false はビュースペックを作成しないことを指定します。代わりに システムスペック で UI をテストします。

helper_specs: false はヘルパーファイル用のスペックを作成しないことを指定します。ヘルパー ファイルは Rails がコントローラごとに作成するファイルです。RSpec を自在に操れるようになって きたら、このオプションを true にしてヘルパーファイルをテストするようにしても良いでしょう。

routing_specs: false config/routes.rb 用のスペックファイルの作成を省略します。シンプルなら、このスペックを作らなくても 問題ないと思います。しかし、アプリケーションが大きくなってルーティングが複雑になってきた ら、ルーティングスペックを導入するのは良い考えです。

モデルスペックとコントローラスペックの定型コードはデフォルトで自動的に作成されます。

 

 

spec/support配下のファイルを読み込む

 

rails_helper.rb 

Dir[Rails.root.join('spec', 'support', '**', '*.rb')].each { |f| require f }

 

上記の一文がコメントアウトされているので、コメントアウトを外してください。これでspec/support/配下のファイルを読み込むことができます。 

 

 

capybaraの設定

ブラウザの操作をシミュレートするために Capybara を使います。Capybara を 使うとリンクをクリックしたり、Web フォームを入力したり、画面の表示を検証したりすることができます。

Capybara は大変便利なRuby ライブラリで、フィーチャスペックのステップを定義したり、アプリケーションの実際の使われ方をシミュレートしたりするのに役立ちます。

これまでに見てきた gem とは異なり、Capybara には Rails の開発環境で実行可能なジェネレータ は用意されていません。Capybara をテスト環境に だけ 追加することにより、開発環境のメモリ消費を 少し軽くすることができます。次に、テストスイートに対して Capybara を読み込むように伝えなければ行けません。rails_helper を開き、Capybara のライブラリを 追加してください(訳注: 最後の行に require 'capybara/rspec' を追加しています)。

 

 

FactoryBotの設定について

 

rails_helper.rb

RSpec.configure do |config|
  config.include FactoryBot::Syntax::Methods


FactoryBotメソッドを使用する際に短縮して書くことができます。

 # 通常FactoryBotをつけないと、メソッドを呼べない
 user = FactoryBot.create(:user)
 # 上の設定を追加することで、FactoryBotの記述が省略できる。
 user = create(:user)

 

 

 連番を持ったデータを生成する(sequence)

sequence(:email) { |n| "tester#{n}@example.com" }

 

 

モデルスペック

 $ rails g rspec:model task (設定していない場合)

spec/models/task_spec.rbが作成されます

 

マッチャmatcher)は「期待値と実際の値を比較して、一致した(もしくは一致しなかった)という結果を返すオブジェクト」のことです。

 

specモデルの書き方
spec/models/task_spec.rb

it 'is invalid without title' do
  task = build(:task, title: '')
  expect(task).to be_invalid
  expect(task.errors.messages[:title]).to include("can't be blank")
end
本来ならエラーメッセージを出す時には、task.valid? といったようなコードを書く必要がありますが、今回はexpect(task).to be_invalid といったように記載しているので、今回は書く必要がありません。
 

 

 

 システムスペックの設定
 
 
System Specを配置するspec/systemディレクトリを作ります。
$ rails generate rspec:system task 
 
spec/support/driver_setting.rb
RSpec.configure do |config|
  config.before(:each, type: :system) do
 # driven_by(:rack_test) 
  # driven_by(:selenium_chrome)
  driven_by(:selenium_chrome_headless)
  end
end
 

 

 

mudule macrosを使ってログインとログアウトを実行するマクロを使えるようにします。 

module LoginMacros
  def login(user)
    visit login_path
    fill_in 'Email', with: 'user.email'
    fill_in 'Password', with: 'password'
    click_button 'Login'
    expect(page).to have_content 'Login successful'
  end

  def logout
    click_link 'Logout'
    expect(page).to have_content 'Logged out'
  end
end

rails_helper.rb

config.include LoginMacros

 spec/system/user_spec.rb

before { login(user) }

 

 

以上がRspecを使う上で必要となる設定についてです。

SNS(Facebook)ログイン機能の追加

どうもどハマりエンジニアです。

 

Facebook認証によるユーザー登録・ログイン機能を追加していきます。

 

authenticationsテーブルを作成

$ rails g sorcery:install external --only-submodules

 

migrate/2020020311301_sorcery_external.rb

class SorceryExternal < ActiveRecord::Migration[5.2]
 def change
  create_table :authentications do |t|
  t.integer :user_id, null: false
  t.string :provider, :uid, null: false

  t.timestamps null: false
 end

  add_index :authentications, [:provider, :uid]
  add_index :authentications, :user_id ←user_idにindexを貼る場合は追加
 end
end

ここでは外部認証に必要なautenticationsテーブルを作成するためのマイグレーションが作成されます。

$bundle exec rails db:migrate

 

Authenticationモデルの設定

$ rails g model Authentication --migration=false

先ほどマイグレーションファイルを作成したので、--migration=false オプションをつけます。

 

models/authentication.rb

belongs_to :user

 

models/user.rb

has_many :authentications, dependent: :destroy
accepts_nested_attributes_for :authentications

 

ここまではfacebook認証に限らず、外部認証共通の処理になります。

 

 

sorcery.rbの設定

Rails.application.config.sorcery.submodules = %i[reset_password external]

Rails.application.config.sorcery.configure do |config|
 config.external_providers = %i[twitter facebook]

 ①config.facebook.key = Rails.application.credentials.dig(:sorcery, :facebook, :key) # 1.で解説
 ①config.facebook.secret = Rails.application.credentials.dig(:sorcery, :facebook, :secret) # 1.で解説
 ②config.facebook.callback_url = 'https://localhost:3001/oauth/callback?provider=facebook' # 2.で解説
 config.facebook.user_info_path = 'me?fields=email, first_name, last_name' # 3.で解説
 config.facebook.user_info_mapping = { email: 'email', first_name: 'first_name', last_name: 'last_name' } # 3.で解説
 config.facebook.display = 'page'
 ④config.facebook.api_version = 'v8.0' # 4.で解説 
 config.facebook.parse = :json

 config.user_config do |user|
  user.reset_password_mailer = UserMailer
  user.authentications_class = Authentication
 end

 config.user_class = 'User'
end

 

①.facebook.keyとsecret

facebook.keyとsecretについてはfacebookの設定→ベーシックより参照できます。fecebook for deveropperでアカウントをまず作成し、アプリ登録をしておく必要があります。

簡単に流れを説明します。

①アカウントを作成する

②アプリ作成をする

③アプリの基本情報を入力していく。

④有効なOAuthリダイレクトURIを設定(後から説明)

 

ベーシックで確認したfacebook.keyとsecretを記載していくのですが、これは外部には漏らしたくないため、credentialsで管理します。

Rails5.2のcredential管理の方法のざっくりとした説明

config/credentials.yml.encファイルが追加され、productionアプリの秘密情報(secret)をここに保存できるようになりました。これによって、外部サービスのあらゆる認証credentialを、config/master.keyファイルまたはRAILS_MASTER_KEY環境変数にあるキーで暗号化した形で直接リポジトリに保存できます。Rails.application.secretsやRails 5.1で導入された暗号化済み秘密情報は、最終的にこれによって置き換えられます。 さらに、Rails 5.2ではcredentialを支えるAPIが用意され、その他の暗号化済み設定/キー/ファイルも簡単に扱えます。 詳しくは、Rails セキュリティガイドを参照してください。

  • config/master.keyに記述したキー情報でcredential情報を暗号化
  • 暗号化した情報はconfig/credentials.yml.encに書き込む
  • credential情報は普通に人間が読める感じで書ける
  • RailsアプリはRails.application.credentials.dig(:aws, :access_key_id)って感じで簡単に呼べる

って感じです!

<下記サイトより>

https://blog.naoshihoshi.com/entry/2018/06/18/153000

 

 

$  EDITOR="vi" bin/rails credentials:edit    

 

credentials.yml

sorcery:
  key: 'アプリIDの値'
  secret: 'app secretの値'
 

facebook for developersからマイアプリにアクセスし、「ダッシュボード」下の「設定」→「ベーシック」の画面から「アプリID」と「app secret」を確認し、記述してください。

 

②.callback_url

上記の実装を行う前に、今回はHTTPS通信を行いたいので、mkcertツールを使い、railsの開発環境でHTTPSを有効にします。

実装は簡単です。

$ brew install mkcert

$ mkcert -install

$ mkcert localhost

"/Users/ユーザーの名前/library/Application Support/mkcert"にあるローカル認証局を使っています。"localhost"という名前で新しい証明書を作成し、証明書は".localhost.pem"に、鍵は".localhost-key.pem"にあります。

 

puma.rb

if Rails.env.development?
ssl_bind '0.0.0.0', '3001', { cert: './localhost.pem', key: './localhost-key.pem' }
end

 

以上でHTTPS接続の設定は完了です。

https://localhost:3001/にアクセスして、接続が可能か確認します。注意すべきことは今回は3001で設定をしたので、facebookの有効なOAuthリダイレクトURIを設定とsorcery.rbのとこでも3001で設定をする必要があります。

 

有効なOAuth リダイレクトURI

https://localhost:3001/oauth/callback?provider=facebook

 

 

③.facebookから取得するデータ

デフォルトでfacebookから取得できるデータは以下のとおりになります。

  • id
  • first_name(名)
  • last_name(姓)
  • middle_name(ミドルネーム)
  • name(フルネーム)
  • name_format(デフォルトは{last}{first}
  • picture(プロフィール画像
  • short_name(設定されていない場合はフルネーム)

それ以外のデータを取得したい場合は、config.facebook.access_permissionsに記述します。
emailを取得するためにはfacebook側の手続きは要りませんが、それ以外にはアプリレビューが必要です。

 

今回はfirst_name、last_name、emailの3つになりますので、下記のようになります。

config.facebook.user_info_path = 'me?fields=email, first_name, last_name' # 3.で解説
config.facebook.user_info_mapping = { email: 'email', first_name: 'first_name', last_name: 'last_name' } # 3.で解説

プロフィール画像の取得方法は他と少し違うので注意が必要です。

 

 

4.APIのバージョン

facebookAPIは「Facebookログイン」の「クイックスタート」から「ウェブ」「2. JavaScriptFacebook SDKを設定する」で確認できます。

 

 

Oauth処理を行うコントローラを作成

$ rails g controller Oauths oauth callback

 

oauths_controller

class OauthsController < ApplicationController
skip_before_action :require_login

 def oauth
  login_at(auth_params[:provider])
 end

 def callback
  provider = auth_params[:provider]
  if (@user = login_from(provider))
   redirect_to root_path, notice: "#{provider.titleize}でログインしました"
  else
   begin
    @user = create_from(provider)
    reset_session
    auto_login(@user)
    redirect_to root_path, notice: "#{provider.titleize}でログインしました"
   rescue StandardError
    redirect_to root_path, alert: "#{provider.titleize}でのログインに失敗しました"
   end
  end
 end

 private

 def auth_params
  params.permit(:code, :provider)
 end
end

 

 

ログインボタンを追加

<%= link_to auth_at_provider_path(provider: :facebook), class: 'facebook-button' do %>
<%= icon 'fab', 'facebook-f' %>
<%= 'Facebookログイン' %>

 

 

ルーティングの追加

post 'oauth/callback', to: 'oauths#callback'
get 'oauth/callback', to: 'oauths#callback'
get 'oauth/:provider', to: 'oauths#oauth', as: :auth_at_provider

 

以上でfacebookによるログイン機能の実装は完了です。