Deviseなしで、Twitterログインを実装する(OAuth認証)
現在作成しているアプリケーションにdeviseなしでtwitteログインを実装したので、アウトプットします。
OAuth認証という認証により、twitter,facebook等のユーザー情報でログインできるよにしま。
OAuth認証については以下の記事が分かりやすかったので、一度読んでみてください。
https://qiita.com/TakahikoKawasaki/items/e37caf50776e00e733be
ruby 2.5.7
rails 5.2.3
やること
・twitterAPIを取得する。
・gemのインストール
・ルーティングの設定、APIキーの設定、OAuth認証の設定
・twitterログインを実装
●twitterAPIを取得する。
twitterAPIの取得は以下の記事を参考させて頂き取得できました。
https://digitalnavi.net/internet/3072/
●gemのインストール
Gemfile
#twitter認証の為のgem
gem 'omniauth' gem 'omniauth-twitter'
#APIキーをGitHubに上げな為に環境変数に入れます。このgemは.envファイルから環境変数をロードする為のgemです。 gem 'dotenv-rails'
※APIキーをGitHub上に上げない方法は以前ブログに書いたので参考にしてみてください。
https://golikyua.hatenablog.com/entry/2019/12/02/135230
$bundle install
ルーティングの設定
routes.rb
Rails.application.routes.draw do ・・・ get 'auth/:provider/callback', to: 'sessions#create' ・・・ end
今回はログイン機能をsessionsコントローラーのcreateアクションで実装したので、上のようにルーティングを設定しました。
環境変数の設定
.env
TWITTER_KEY="取得したAPI key" TWITTER_SECRET="取得したAPI secret key"
これでローカル環境で、APIキーを使用することができますが、本番環境ではまだ使用できません。
自分の場合、アプリケーションをherokuにデプロイしていたので、heroku側でも環境変数を設定します。
コンソールで以下の設定を行います。
$ heroku config:set TWITTER_SECRET="取得したAPI key" $ heroku config:set TWITTER_SECRET="取得したAPI secret key"
以下のコマンドで設定されている環境変数一覧が確認できるので、設定されているか確認してみましょう。
$ heroku config
OAuth認証の設定
config/initializers/omniauth.rbを作成し、以下を記入する。
Rails.application.config.middleware.use OmniAuth::Builder do provider :twitter, ENV['TWITTER_KEY'], ENV['TWITTER_SECRET'] end
●twitterログインを実装
userモデルに以下のカラムを追加します。
class AddColumnsToUsers < ActiveRecord::Migration[5.0] def change add_column :users, :uid, :string add_column :users, :provider, :string add_column :users, :image_url, :string end end
$ rails db:migrate
user.rb内に以下のメソッドを追加します。
class User < ApplicationRecord ・・・ def self.find_or_create_form_auth(auth) provider = auth[:provider] uid = auth[:uid] name = auth[:info][:name] image = auth[:info][:image] self.find_or_create_by(provider: provider, uid: uid) do |user| user.name = name user.image_url = image end end end
自分の場合これだけでログインしようとしたら、バリデーションに引っかかってログイン出来なかったので、バリデーションを変更します。
class User < ApplicationRecord validates :name, presence: true, unless: :uid?, length: { maximum: 30 } validates :email, presence: true, unless: :uid?, uniqueness: true, length: { maximum:255 }, format: { with: /\A[\w+\-.]+@[a-z\d\-.]+\.[a-z]+\z/i.freeze } validates :password, format: { with: /\A(?=.*?[a-z])(?=.*?\d)[a-z\d]{8,30}+\z/i }, length: { in: 8..30 }, unless: :uid? has_secure_password validations: false has_one_attached :image, dependent: :destroy has_many :posts, dependent: :destroy has_many :favorites, dependent: :destroy has_many :favorite_posts, through: :favorites, source: 'post' has_many :reviews, dependent: :destroy ・・・ end
自分の場合nameカラム、emailカラム、passwordカラムにunless: :uid?を追加したら、バリデーションに引っかからなくなりました。
もしバリデーションに引っかかってログイン出来ない状態だったら、コメントアウトを使ってどこで引っかかっているか確認してみるといいと思います。
続いてsessionsコントローラーの設定を行います。
app/contorllers/sessions_controller.rb
class SessionsController < ApplicationController ・・・ def create auth = request.env['omniauth.auth'] if auth.present? user = User.find_or_create_form_auth(request.env['omniauth.auth']) session[:user_id] = user.id flash[:success] = "ユーザー認証が完了しました。" redirect_to user else @user = User.find_by(email: params[:session][:email]) if @user && @user.authenticate(params[:session][:password]) log_in @user flash[:success] = "ログインしました" redirect_to @user else flash.now[:danger] = "ログインに失敗しました" render 'new' end end end ・・・ end
ポイントは if文で、twitterログインと通常のログインを分けることです。これをやらないとエラーが発生します。(だいぶ苦労しました。)
最後に、ログインする為のビューを設定します。
app/views/sessions/new.html.erb
<%= link_to "Twitterアカウントでログイン", "/auth/twitter" %>
これで上手く行くと思います。
githubにpushする際に環境変数を使ってAPI_KEYを隠す方法
作成中のアプリでGoogle mapを使用指定と思いGoogle Cloud PlatformでAPI_KEYを取得しました。
githubにpushする際に、API_KEYを隠さずにそのままpushしたら、Google Cloud
Platformからメールで怒られたので、API_KEYを隠してpushする方法を学んだので合うプットします。
やること
・gem 'dotenv-rails' をインストール
・API_KEYをそのまま書いている部分を環境変数に変更する。
・.gitignoreファイルに.envを追加して、git管理下から外す。
gem 'dotenv-rails' をインストール
gemfileにgem 'dotenv-rails'を記入して、bundle install
Gemfile
... ... gem 'dotenv-rails'
ルートディレクトリ直下に.envを作成する。
.env
GOOGLE_API_KEY = "<自分のAPI_KEY>"
以下のようにコンソールで確認すると代入したAPI_KEYの値が出力されます。
[1] pry(main)> puts ENV["GOOGLE_API_KEY"] <自分のAPI_KEY> => nil
API_KEYをそのまま書いている部分を環境変数に変更する。
自分の場合application.html.erbにそのままのAPI_KEYを書いていたので以下のように変更
<html> <head> ... ... <script src="//maps.google.com/maps/api/js?v=3.23&key=<%= E NV["GOOGLE_API_KEY"] %>"></script>
CarrierWaveを使用した画像をアップロードする方法
CarrierWaveを使用して画像投稿機能を実装したのでアウトプットします。
前提
ruby 2.6.3
Rails 5.0.7.2
開発環境 AWS cloud9
やること
・データベースに画像保存用のカラムを作成
・gem 'carrierwave'のインストール
・画像をアップロードするためのコードを作成
・config/application.rbで設定変更
・モデルに関連付ける
・データベースに画像保存用のカラムを作成
$ rails g model Topic user_id:integer description:string image:string
モデルを作成してimageカラムに「画像がどこにあるか」という情報を持たせる。
$ rails db:migrate
maigrationファイルをデータベースに反映させる
・gem 'carrierwave'のインストール
Gemfile
gem 'carrierwave'
Gemfileに上のgemを書いてbundle install
・画像をアップロードするためのコードを作成
コンソールで以下のコマンドを入力
$ rails g uploader image
このコマンドで app/uploaders/image_uploader.rb が作成される。
・config/application.rbで設定変更
class Application < Rails::Application config.autoload_paths += Dir[Rails.root.join('app', 'uploaders')] end
・モデルに関連付ける
app/models/topics.rb
class Topic < ApplicationRecord mount_uploader :image, ImageUploader end
これでcarrierwaveの設定は完了。
☆画像タイプの制限と画像サイズの制限についても学んだので書いておく
画像タイプの制限、画像サイズの制限共に以下のコマンドで作成された app/uploaders/imageuploader.rbのコードを変更する
$ rails g uploader image
・画像タイプの制限
ファイル内のコードでコメントアウトされている以下の文のコメントアウトを解除する。
app/uploaders/imageuploader
def extension_whitelist %w(jpg jpeg gif png) end
・画像サイズの制限
今回は10MB以下の画像のみ使えるようにする。
これもファイル内に以下のメソッドを足すだけ
app/uploaders/imageuploader
def size_range 1..10.megabytes end
Githubへのpushの流れ
githubへpushを勉強したのでアウトプットします。
前提
開発環境 AWScloud9
やること
- githubにアカウント登録(飛ばす)
- リモートリポジトリを作成(ここも飛ばす)
- ssh公開鍵を登録
- pushしたいディレクトリをgit管理下に置く
- pushするディレクトリをcommitする
- リモートリポジトリの登録
- githubへpushする
sh公開鍵の登録
作成した公開鍵の内容を表示し、コピペしてgithubに登録。
pushしたいディレクトリをgit管理下に置く
githubにpushしたいディレクトリに移動して下のコマンドを実行するとディレクトリをgit管理下に置くことができる。
$git init
pushするディレクトリをcommitする
リモートリポジトリを登録する
※間違ったリモートリポジトリを登録してしまった場合
githubにpushする
#以下のコマンドでpushできる
$git push -u origin master
参考
http://tetsuyai.hatenablog.com/entry/20110912/1315798082
ペジネーション
ペジネーションについて勉強したのでアウトプットします!
目標
「タスク一覧の表示数を制限して、複数のページに分割して表示する」
やること
・kanimariのインストール
・ページ番号に対応した範囲の内容を表示する
・ビューにペジネーションのための情報を表示する
本題
・kaminariのインストール
Gemfileに「gem 'kaminari'」を記入して、「bundle」を実行。
・ページ番号に対応した範囲の内容を表示する。
ページ番号に対応するデータの範囲を検索の部分はkaminariが提供するpageというスコープを使うこと簡単にできる!
これを用いてindexアクションを編集
app/controller/tasks_controller.rb
def index @q = current_user.tasks.ransack(params[:q]) @tasks = @q.result(distinct: true).page(params[:page]) ... end
ちなみにデフォルトで、1ページあたりに表示できる件数は25件になっている。
・ビューにペジネーションのための情報を表示する
ペジネーションを行う際に必要な情報は以下の3つ
1.現在どのページを表示しているかの情報
2.他のページに移動するためのリンク
3.全データ何件なのかという情報
kaminariはこれらを表示するためのヘルパーメソッドが用意されている
1.2の目的の為にpaginateと3の目的の為にpage_entries_info
app/views/tasks/index.html.slim
... .mb-3 = paginate @tasks = page_entries_info @tasks ...
これで、一覧ページが複数に分割されてが表示される!
タスク一覧画面に検索機能を実装する(ransack)
検索機能の実装について勉強したので、アウトプットしたいと思います!
目標
「タスク一覧画面に検索機能を追加」
やること
・Ransackのインストール
・名称による検索機能の実装
・登録日時による検索機能の実装
・検索条件を絞る
本題
・Ransackのインストール
Gemfileに「gem 'ransack'」を入力し、bundlerで「bundle」を実行。
・名称による検索機能の実装
ransackをインストールするとransackメソッドがモデルに追加される。
ransackメソッドを使用して、コントローラを修正する。
def index
@q = current_user.tasks.ransack(params[:q]) @tasks = @q.result(distinct: true).recent ... end
タスク一覧画面に検索フォームを作成する。
ranscakによりsarch_form_forという検索フォームを作成されるヘルパーが提供される!
h1 タスク一覧 = search_form_for @q, class: 'mb-5' do |f| .form-group.row = f.label :name_cont, '名称', class: 'col-sm-2 col-form-label' .col-sm-10 = f.search_field :name_cont, class: 'form-control'
.form-group
= f.submit class: 'btn btn-outline-primary' = link_to '新規登録', new_task_path, class: 'btn btn-primaty mb-3'
※ranscakを利用する際は、検索フィールドの名前を一定のルールに従ってつける。
今回は名称に「検索フォームで入力した文字が含まれている」という検索を実現したいので「name_cont」という名前をつける。
検索時のSQLを調べると、PostgreSQLのILIKE(大文字と小文字の区別をしない)が使われていた。これは検索フィールドの名前を「name」にした結果である。
また「_cont」は、検索文字列を含むものを検索するransackが用意したマッチャー。
よって「name_cont」を検索フォームの名前にすることで、入力した文字列を含むタスクを検索できるようになる。
・登録日時による検索
タスク一覧の検索フォームに登録日時のフィールドを追加する。
h1 タスク一覧
= search_form_for @q, class: 'mb-5' do |f|
.form-group.row
= f.label :name_cont, '名称', class: 'col-sm-2 col-form-label'
.col-sm-10
= f.search_field :name_cont, class: 'form-control'
.form-group.row
= f.label :created_at_gteq, '登録日時', class: 'col-sm-2 col-form-label'
.col-sm-10
= f.search_field :created_at_gteq, class: 'form-control'
.form-group
= f.submit class: 'btn btn-outline-primary'
= link_to '新規登録', new_task_path, class: 'btn btn-primary mb-3'
登録日時検索フィールドで使用した_gteqは、greater than or equalの略で、「入力した値より大きいか同じ」なものを検索する。
日時の場合は、「同じ日にちかそれより未来の日にち」を検索する。
登録日時の検索後のSQLでは、比較演算子の「>=」が使われている!
・検索条件を絞る
どうやらユーザーが意図的にパラメータを加工すると、他のカラムを使った検索ができてしまうらしい。
それを防ぐために、検索結果に制限をかける。
app/models/task.rb
class Task < ApplicationRecord def self.ransackable_attributes(auth_object = nil) %w[name created_at] end def self.ransackable_associations(auth_object = nil) [] end ... end
ransackable_attributesで、検索対象にすることを許可するカラムを指定する。
nameとcreate_atを指定することで、他のデータを検索フォームに入力しても無視される。
ransackable_associationsは、検索条件に含める関連を指定できる。
このメソッドを空の配列を返すようにオーバーライドすることで、検索条件に意図しない関連を含めないようにすることができる。
まとめ
・ransackをインストール
・ransackメソッドを使って、コンソールの編r集
・search_form_foを使い、ビューに検索フォームを作成する。
・rasackable_attributes, ransackable_associationsメソッドで検索条件をつける。
ransackめちゃめちゃ便利!!
Active Storageを使用したタスク管理アプリへの画像添付(development環境)
画像ファイル添付について勉強したのでアウトプットする!
目標
「タスク管理アプリのタスク詳細画面に画像を表示する」
やること
・Active Storageをタスク管理アプリで使うための準備。(Rails5.2以降はgemのインストールはされている)
・タスクモデルに画像を添付できるようにする。
大まかにはこんな感じ!
本題
・Active Storageをタスク管理アプリで使うための準備。
・マイグレーションファイルの出力。
$bin/rails active_storage:install
db/migrate/xxxxxxxxxxxxxx_create_active_storage_tables.active_storage
# This migration comes from active_storage (originally 20170806125915) class CreateActiveStorageTables < ActiveRecord::Migration[5.2] def change create_table :active_storage_blobs do |t| t.string :key, null: false t.string :filename, null: false t.string :content_type t.text :metadata t.bigint :byte_size, null: false t.string :checksum, null: false t.datetime :created_at, null: false t.index [ :key ], unique: true end create_table :active_storage_attachments do |t| t.string :name, null: false t.references :record, null: false, polymorphic: true, index: false t.references :blob, null: false t.datetime :created_at, null: false t.index [ :record_type, :record_id, :name, :blob_id ], name: "index_active_storage_attachments_uniqueness", unique: true t.foreign_key :active_storage_blobs, column: :blob_id end end end
このマイグレーションファイルはActive Storageが利用する二つのテーブル、active_storage_blobs と active_storage_attachment を作成する。
二つのテーブルは、ActiveStorage::Bolb と ActiveStorege::Attachmentというモデルに紐ずいている。
ActiveStorage::Bolbは添付されたファイルに対応するモデルで、ファイルの実態をデータベース外で管理する!
ActiveStorege::AttachmenはActiveStorage::Bolbとアプリ内の様々なモデルを関連づける中間テーブル!
今回はTaskとActiveStorege::boldを紐づけます。
紐づけのイメージは以下の感じ!(※この画像はuserモデルとの紐づけだが、今回はTaskモデルとの紐づけ)
・マイグレーションファイルをDBに反映させる
$bin/rails db:migrate
・添付したファイルの実体を管理する場所について設定を行う。
Rails.application.config.active_storage.serviceにファイルを管理する場所の名前を与え、その名前に対応する設定を、config/storage.ymlに定義する。
(デフォルトでは、development環境のファイル管理場所はlocalとなっている)
config/environments/development.rb
# Store uploaded files on the local file system (see config/storage.yml for options) config.active_storage.service = :local
local設定がされているconfig/storage.yml
test: service: Disk root: <%= Rails.root.join("tmp/storage") %> local: service: Disk root: <%= Rails.root.join("storage") %> # Use rails credentials:edit to set the AWS secrets (as aws:access_key_id|secret_access_key) # amazon: ...
・タスクモデルに画像を添付できるようにする。
・1つのタスクに1つの画像を紐づける。
class Task < ApplicationRecord has_one_attached :image ... end
app/views/tasks/show.html.slimに以下を追加
...
tr th= Task.human_attribute_name(:image) td= image_tag @task.image if @task.image.attached?
...
image_tagを使う場合は、実際に画像が添付されていないと、エラーが発生してしまうため、@task.image.attached?をいう判定メソッドを使用して、「画像が添付されている場合のみ、画像を表示する」というようにします!
まとめ
マイグレーションファイルを取得する
マイグレーションファイルの反映
一つのモデルに一つの画像を紐づける
新規登録、更新画面のビュー編集
imageラベルが日本語になるようにja.ymlファイルを編集
task_paremsを変更し、:imageを許可するパラメーターに追加
詳細画面のビュー変更 image_tagは画像がないとエラーになるため @task.image.attashed?で判定
参考文献
「現場で使える Ruby on Rails 5 速習実践ガイド 」