Twitter認証機能の追加
半日以上かかってしまったので、エラー部分について自分用に反省メモφ(・・
127.0.0.1:3000
に飛びたいのに何故か/login
に遷移する
Twitterログインボタンを設置しているTOPページに遷移するためのstatic_pages_controller.rb
でskip_before_action :require_login
してなかった…
CircleCIでエラー
DBをセットアップできていない・・・
rake aborted! NoMethodError: undefined method `[]' for nil:NilClass /home/circleci/repo/config/initializers/sorcery.rb:88:in `block in <main>'
該当箇所をみると、これ
config.twitter.key = Rails.application.credentials.twitter[:key]
CircleCI
側にマスターキーを登録したらOKだった
Rails 6よりサポートされたMulti Environment Credentialsをプロジェクトに導入する
今後の課題
TwitterからEmail取得できない問題
permissionがrejectされる!
とりあえず、email取得は諦めて、usersテーブルのemailカラムにはtwitter_idを詰めてごまかしているので今後対応する
CircleCIの導入
CircleCI
githubにpushすると同時にCircleCI
が起動し、RSpec
テストやrubocop
のLintチェックを自動で走らせてくれます。
私はズボラでpush前にrubocopやRSpecを実行するのを忘れがちなので、正しいコードをmergeできるようにCircleCI
を導入しました。
詰まりに詰まり、1日かかってしまいました。。とりあえず動いてくれてますが、細かい部分は合っているか謎。
公式のサンプル集からコピーして、Qiita等を参考に切り貼りして、ローカルで実行→エラーを潰していくという流れで進めてしまいました。
環境
config.yml
version: 2.1 orbs: ruby: circleci/ruby@0.1.2 jobs: build: docker: - image: circleci/ruby:2.7.2-node-browsers-legacy #rubyのversionに合ったコンテナ environment: - BUNDLER_VERSION: 2.1.4 # これがないとbundle installできない - RAILS_ENV: 'test' - DB_HOST: 127.0.0.1 - image: circleci/mysql:5.7 environment: - MYSQL_ALLOW_EMPTY_PASSWORD: 'true' - MYSQL_USER: root - MYSQL_DB: ci_test # testのDB名指定 working_directory: ~/repo steps: # CI環境上の working_directory の値の場所にGitリポジトリをコピーする。 - checkout # dockerコンテナの立ち上げを待つ(これ不要かも…???) - run: name: wait for database command: dockerize -wait tcp://127.0.0.1:3306 -timeout 5m # キャッシュがあれば、リストアする。テスト時間の短縮につながる。keysでリストアするキャッシュを複数指定 - restore_cache: keys: - v1-dependencies-{{ checksum "Gemfile.lock" }} - v1-dependencies- # Bundle install dependencies - run: name: Install dependencies command: | gem install bundler -v 2.1.4 bundle install --path=vendor/bundle --jobs 4 --retry 3 # キャッシュする - save_cache: key: v1-dependencies-{{ checksum "Gemfile.lock" }} paths: - vendor/bundle # DBのセットアップ - run: name: Database Setup command: | bundle exec rake db:create bundle exec rake db:schema:load # rubocopを実行 - run: name: Rubocop command: bundle exec rubocop # RSpecを実行 - run: name: Run rspec command: | bundle exec rspec --profile 10 \ --format RspecJunitFormatter \ #gem 'rspec-junit-fomatter'が必要 --out test_results/rspec.xml \ --format progress \ $(circleci tests glob "spec/**/*_spec.rb" | circleci tests split --split-by=timings) # Save artifacts - store_test_results: path: /tmp/test-results
default: &default adapter: mysql2 encoding: utf8mb4 pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %> username: root password: <%= ENV['DATABASE_DEV_PASSWORD'] %> host: localhost collation: utf8mb4_bin # 略 test: <<: *default database: ci_test # 名前変更(config.ymlに合わせる) host: <%=ENV['DB_HOST'] || '127.0.0.1' %> # 追加
CircleCIをローカルで実行する
私は最初の数回、ローカルで実行できるのを知らず、pushして動作確認していました…
ジョブを実行して、エラーを1つづつ潰していけばOK
store_cache
, save_cache
は実行されずスキップします。
# CircleCIのインストール ❯ brew install circleci # CircleCIの設定ファイルconfig.ymlの文法チェック ❯ circleci config validate .circleci/config.yml # 文法間違いがあるときの結果 Error: Unable to parse YAML mapping values are not allowed here in 'string', line 12, column 30: - image: circleci/mysql: 5.7 # OKなとき ❯ circleci config validate .circleci/config.yml Config file at .circleci/config.yml is valid. #ジョブの実行 ❯ circleci local execute --job build
遭遇したエラー①
Step failed ====>> Uploading test results Error: Unable to save test results from /tmp/test-results Error path is not valid /tmp/test-results: error accessing path: /tmp/test-results: lstat /tmp/test-results: no such file or directory
テストの結果を入れるファイルを用意していなかった。/tmp/test-results
を作成。
遭遇したエラー②
# --- Caused by: --- # Mysql2::Error: # Unknown database 'ci_test' # ./spec/rails_helper.rb:28:in `<top (required)>'
db名を変えたのに、db:create
していなかった。
❯ rails db:create Created database 'ci_test'
これでOK
参考にしたもの
CircleCI のローカル CLI の使用 - CircleCI
ローカルで実行
公式サンプルRuby用
公式サンプルRails&Mysql用
bundler設定を参考
.circleci/config.yml内の用語参考
save_cacheとstore_cacheの説明
エラー参考
【環境構築】rails new ~ MySQLの初期設定
rails new
そもそも、rails
コマンドを使ったら、command not found
のエラーが出たので、gem install rails install
実行してインストール。
rails new オプションいろいろ
rails new
コマンドを実行するにあたり、オプションを指定しておきます。
~/workspace/カレントディレクトリ *ブランチ名 ❯ rails _6.0.3.4_ new . -B -d mysql --skip-test
- アプリケーションに先行してREADMEを作っていたため、カレントディレクトリにアプリケーションを作成したいです。
.
でカレントディレクトリに雛形ファイルを作成できます。 -B
オプションで、bundle installをスキップしました。-d
オプションで、使用するデータベースをmysqlに指定しています。--skip-test
オプションで、テストの生成をパスしています。
railsコマンド(rails) | Railsドキュメント
必要なgem
を追記して、bundle install
します。
MySQLの設定
こっちが詰まりに詰まり、苦しかったです。一日苦しみました。
MySQLをアンインストール
私はもともとMySQLをインストールしていたようですが、パスワード等をなくしてしまったので一度アンインストールしました。
関連ファイルまで全て削除しないとアンインストールできませんでした。
macOSにHomebrewでインストールしたMySQL5.7, MySQL8.0をアンインストールする方法 | プログラミング入門ナビ
再インストール
ローカルの環境にインストールしていきます。
基本的に、環境構築はプロゲートがわかりやすいです。
MySQLの開発環境を用意しよう(macOS) | プログラミングの入門なら基礎から学べるProgate[プロゲート]
Rails側の設定
ローカルでMySQLのログインまで終わったら、Rails側の設定をします。
config/detabase.yml
でDBの設定をします。
rails new
するときにMySQLを指定していたので、自動でファイルが出来上がっています。
passwordは入力する必要があるのですが、Githubにpushしたくないので、環境変数を設定し、そこからパスワードを読み込む設定にします。
環境変数設定
gem 'dotenv'
を導入しました。
GitHub - bkeepers/dotenv: A Ruby gem to load environment variables from `.env`.
【Ruby on Rails】GitHubに公開したくない変数や値を隠してpushする方法 - Qiita
DATABASE_DEV_PASSWORD = '設定したパスワード'
default: &default adapter: mysql2 encoding: utf8mb4 pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %> username: root password: <%= ENV['DATABASE_DEV_PASSWORD'] %> # 追加 host: localhost 略
Githubにpushしないように、gitignore
に追加します。
/.env
DB生成エラー
MySQLの初期設定が終わったので、DBを生成していきます。
エラー発生…
❯ bundle exec rails db:create rails aborted! LoadError: dlopen(/Users/ユーザー名/workspace/アプリ名/vendor/bundle/ruby/2.7.0/gems/mysql2-0.5.3/lib/mysql2/mysql2.bundle, 9): Library not loaded: /usr/local/opt/mysql/lib/libmysqlclient.21.dylib Referenced from: /Users/ユーザー名/workspace/アプリ名/vendor/bundle/ruby/2.7.0/gems/mysql2-0.5.3/lib/mysql2/mysql2.bundle Reason: image not found - /Users/ユーザー名/workspace/アプリ名/vendor/bundle/ruby/2.7.0/gems/mysql2-0.5.3/lib/mysql2/mysql2.bundle
LoadError
読み込めてない…?
もしかしたら、gem 'mysql2
がインストール失敗している…?
❯ bundle doctor The following gems are missing OS dependencies: * mysql2: /usr/local/opt/mysql-client/lib/libcrypto.1.1.dylib * mysql2: /usr/local/opt/mysql-client/lib/libssl.1.1.dylib * mysql2: /usr/local/opt/mysql/lib/libmysqlclient.21.dylib
対処
# アンインストールしてから ❯ bundle exec gem uninstall mysql2 # 再インストール ❯ bundle install
そしたら今度はインストール中にエラー…
open-sslライブラリのパスを通す必要があるよう。
❯ export LIBRARY_PATH=$LIBRARY_PATH:/usr/local/opt/openssl/lib/
このコマンドを実行後、bundle install
したらうまくいきました。
その後、rails db:create
rails db:migrate
rails server
も成功。
エラー対処で参考にしたもの
【MySQL, Rails】「Gem::Ext::BuildError: ERROR: Failed to build gem native extension.」の対処 - Qiita
Cannot install mysql2 gem for Rails project - Stack Overflow
【環境構築】rbenv globalが効かないとき
Rubyのversion指定で詰まったのでメモ
rbenv
はインストール済みです。
Rubyインストール
❯ rbenv install 2.7.2
Rubyバージョンを指定
システム全体で使用するRubyのバージョンを指定するために、rbenv global
コマンドを実行。(そもそも、globalは強引でよくないかも)
これがうまくいかなかった
❯ rbenv global 2.7.2
rubyのバージョンを確認すると、指定したバージョンに変わっていない…
❯ ruby -v ruby 2.6.6
インストール自体はできている
❯ rbenv versions system 2.6.5 *2.6.6 (set by /Users/user_name/.rbenv/version) 2.7.2
以前はまった、Rubyの参照先も合っている。
❯ which ruby /Users/user_name/.rbenv/shims/ruby
/usr/bin/ruby
ではなく、rbenvでインストールした/.rbenv/shims/ruby
を正しく参照している。
study-diary.hatenadiary.jp
結論
rbenv local
はrbenv global
に優先する。
おそらく、以前にrbenv local 2.6.6
を実行しており、その設定が優先されたと思われる。
❯ rbenv local 2.7.2
❯ ruby -v ruby 2.7.2p137 (2020-10-01 revision 5445e04352) [x86_64-darwin19]
できた!
ポートフォリオ作成
設計の段階で何を使っていいか戸惑うことがあったのでメモφ(・・ 使ったツールなど、適宜更新していく。
画面遷移図
adobeXDを使用。
画面遷移の順番を指定できる。
リンクも作成できるので、READMEに貼り付けられる。
画面遷移の順番がうまく指定できず悩んだ。
プロトタイプで移動先を指定していても、配置している高さ順が優先されるのを知らなかった。。
www.adobe.com
グラフとかデザインはcanvaが使いやすくてかわいい。 こっちで作ってから、XDへ画像として貼り付けした。 www.canva.com
ER図
ER図はこれで。VScodeでも使えるらしい。 線があらぬ方向に曲がったり慣れるまで時間がかかる。
線がアクティブ状態のときに線のスタイルを選択できる
カラムの追加は
⌘+D
app.diagrams.net
そもそもDB設計について無知だったので、『楽々ERDレッスン』『スッキリわかるSQL入門』を流し読み。
【API】【Rails】エラーメモ
エラーを出しまくったので、繰り返さないようにメモ。
wrong number of arguments
Postmanを使って、articleの更新と削除を試していたのに、できない。
新規作成のPOSTと一覧取得のGETは問題なし。
コードは基礎的なものだしパッと見間違っていなそう…
{ "message": "Internal Server Error", "errors": [ "wrong number of arguments (given 1, expected 0)" ] }
wrong number of arguments
引数の数が間違っている・・・?
他のアクションはできているので、create
とdestroy
アクションに関わる箇所が間違ってそう。
ということでよくよく見直してみると、
module Api module V1 class User::ArticlesController < BaseController before_action :set_article, only: %i[update destroy] # 略 def update if @article.update(article_params) json_string = ArticleSerializer.new(@article).serialized_json render json: json_string else render_400(nil, @article.errors.full_messages) end end # 略 private # 略 def set_article @article = current_user.articles.find(params(:id)) # ここ!! end end end end
params[:id]
だった。。。タイポで数時間悩んだ。
namespaceの重複
ユーザー登録用のコントローラーで、createアクションをPostmanで試してみるも、ユーザー登録できない。
module Api module V1 class RegistrationsController < BaseController def create @user = User.new(user_params) … # 略
ディレクトリ階層はこんな感じ。
undefined method 'new' for Api::V1::User::Module
エラー文をみると、Api::V1::User::Moduleでnewメソッドが定義されていない…?
これは自力で解決できずにギブアップしてしまいました。
結論は、「namespaceの重複を防ぐために、::User
とし、絶対参照にする。 」
ただ、理由が分かってなくて、User
という定数を探すためにrailsが自動で上から順番に探索してくるけど、見つからなかったからエラーになった??
以下のリンクを読んでぼんやりとしかまだ分かってないので今度まとめられたら…
def create @user = ::User.new(user_params)
できた。
Rubyにおけるクラス/モジュール定義関連の仕組みと、Ruby on Railsにおけるautoloadの仕組み - Qiita
ネームスペースが重複する場合はその定数の参照はコンテキストに依存しない絶対的な参照に変更したほうがいい。::User、Admin::Userのように
定数の自動読み込みと再読み込み (Classic) - Railsガイド
Rubyでクラス名のはじめに::(コロンを2つ)をつけるとそのクラスの絶対的な位置表現をすることができる - コード日進月歩
【Rails】【API】雑多なメモ
response.headers
HTTPheader
のAccessToken
にtokenをセットしたいとき
Provides access to the request's HTTP headers, for example:
response.headers['AccessToken'] = token
Action Controller の概要 - Railsガイド
class Net::HTTPResponse (Ruby 2.7.0 リファレンスマニュアル)
POSTMANで確認すると、ちゃんとheadersにtokenが格納されています。
HTTPのトークン認証
authenticate_or_request_with_http_token
を使う
include ActionController::HttpAuthentication::Token::ControllerMethods
モジュールをincludeするのを忘れないこと。
module Api module V1 class BaseController < ApplicationController include ActionController::HttpAuthentication::Token::ControllerMethods before_action :authenticate # サブクラスで使うのでprotected protected # ApiKey.activeで有効期限内に限定している(activeというスコープを別で定義している) # &.userで、レシーバがnilではない場合にApikeyの情報から関連するuserを特定して返す。 def authenticate authenticate_or_request_with_http_token do |token, _options| @_current_user ||= ApiKey.active.find_by(access_token: token)&.user end end # @_というのは、インスタンス変数を、ローカルキャッシュとして扱う場合、_をプレフィックスとして付ける慣習がある # current_userメソッドを使ってほしいので、直接@current_userを使わないように明示している。 def current_user @_current_user end private def form_authenticity_token; end end end end
Rails による API 専用アプリケーション - Railsガイド
ActionController::HttpAuthentication::Token
Rails-APIでsorceryを使ったらundefined local variable or method `form_authenticity_token'と怒られた - Qiita