- 投稿日:2019-08-19T23:43:36+09:00
Railsチュートリアル(第9章)
はじめに
Railsチュートリアルの第9章が終わりました。
ポイントだけメモしておきます。トークンの考え方
永続的なログインを実装するために、cookieというものに値を保持します。
しかし、そのままログイン情報を保持してしまうと、情報を盗み見られたりするとサイバー攻撃に繋がってしまうため、複雑にして保持する必要があります。
流れを簡単にまとめると以下のようなイメージです。・ログイン時、ユーザーIDを暗号化したものと、ランダムな文字列トークンをcookieに保持
・ランダムな文字列トークンをハッシュ化して、ユーザーテーブルに保持
・ログインチェック時、cookieからユーザーIDを取り出してテーブル検索
・取得したデータのトークンとcookieのトークンのハッシュ値を比較トークンの生成
以下の記述で、64種類の文字(A–Z、a–z、0–9、"-"、"_")からランダムに22文字生成してくれます。
SecureRandom.urlsafe_base64モデルの仮想の属性
モデルにトークンを保持する際、データベースに保存せずに値を取得したいです。
その際に、以下のようにattr_accessor
でゲッターとセッターを定義して仮想の属性を定義できます。
rememberメソッドの2行目は、トークンをハッシュ化してデータベースに保存しています。class User < ApplicationRecord attr_accessor :remember_token # ランダムなトークンを返す def User.new_token SecureRandom.urlsafe_base64 end # 永続セッションのためにユーザーをデータベースに記憶する def remember self.remember_token = User.new_token update_attribute(:remember_digest, User.digest(remember_token)) end endcookieの保持
実際にcookieに値を保持する際は、sessionと同じようにハッシュの形式で値を設定します。
以下のように、expires
によって有効期限を設定できます。cookies[:remember_token] = { value: remember_token, expires: 20.years.from_now.utc }また、以下のように
permanent
メソッドを使用することで、自動的に20年を設定してくれます。cookies.permanent[:remember_token] = remember_tokenユーザーIDを保持する際など、暗号化して格納する場合は、
signed
メソッドを使用します。cookies.signed[:user_id] = user.id2つを合わせて記述すると以下のようになります。
cookies.permanent.signed[:user_id] = user.id取り出す際は同じように
cookies.signed[:user_id]
で複合化して取得できます。cookieの削除
cookieを削除する際は、
delete
を使用します。cookies.delete(:user_id) cookies.delete(:remember_token)チェックボックス
form_for
の中にチェックボックスを記述する際は、f.check_box
で記述します。
以下のように、ラベルの内側に書くことで、チェックボックスと文字列をひとまとまりにしています。<%= form_for(:session, url: login_path) do |f| %> ... <%= f.label :remember_me, class: "checkbox inline" do %> <%= f.check_box :remember_me %> <span>Remember me on this computer</span> <% end %> ... <% end %>値を取得する際は、チェックボックスがオンの時
1
、オフの時0
になります。
- 投稿日:2019-08-19T22:10:56+09:00
初学者がRuby on Railsでポートフォリオを作成しました。
はじめに
今回の内容は就職活動中で作成しているポートフォリオの説明です。
アドバイスなどありましたらよろしくお願いいたします。開発環境
- Ruby 2.5.1
- Rails 5.2.3
- DB:Mysql5.6
- AWS/S3
- 少しだけVue.js
アプリ概要
・業者などに頼むほどではない作業や困りごとを得意な人に助けてもらう。
・使う機会がないスキルや自分の得意なことを活かして、困っている人を助ける。
そのような人と人が助け合うアプリがあればいいなという思いから作成しました。接続先情報
⚠️URLはデプロイなどで接続できないタイミングがございます。その際は少し時間をおいてから接続してください。
⚠︎簡単ログインでログインした方は終わる時にログアウトもお願いいたします。何ができるか?(機能)
Koto_Kotoは、以下のことができます。
・困りごと,スキルの作成/編集/削除
困りごとを作成したいときは、demandボタン、スキルを提案したいときはsupplyボタンから作成することができ、目的別に分けて投稿ができます。
編集や削除は下の画像の赤丸のところからできます。
・クレジット登録機能
クレジット登録機能
Test用としてこちらを入力して頂ければ使用できます。
- カード番号 4242424242424242
- 有効期限 12/22
- CVC番号 123
- 名前 適当に入力してください
カードの削除も可能です。
・スキル,困りごとの助け合い機能(購入機能)
カードを登録した場合のみ購入,助けることが可能です。(ポートフォリオなので、万が一購入しても、仮想的に作っているので、お支払いは発生しません。)
あと、助けるボタンを押した場合は、購入ではないので、クレジットからお支払いは発生しないような作りになっています。
・購入後のチャットのやりとり
スキル購入、困りごとへの助けるボタンを押したら、チャットルームが作成される仕様になっており、お互いでやりとりが可能です。
・契約完了後の評価
契約完了したら、スキル購入の場合は購入者,困りごと解決の場合は困りごと出品者がその契約内容に関して、評価する仕様になっています。その評価に応じて対象者の信頼スコア(各々が持っている評価指標。マイページの右側の円に囲まれたもの)が加算されます。信頼スコアが高ければ高いほど、その人の評価が高いことになります。⚠︎評価画面の見た目部分は後々、モーダルで作成したいため、いじっておりません。
・ポイント機能
評価されて信頼スコアが上がるだけだとモチベーションupには繋がらないと思ったので、ポイント機能を作成しました。
信頼スコアをあげればあげるほど、ポイント倍率が高くなって、ポイントをためやすくなる仕様にしています。
今後、このポイントを使用して、スキル購入の時に割引として使えるなどの機能を実装したいと考えています。・ユーザー登録/編集/退会機能
deviseは使用せずに作成しました。(Session&Cookieの概要を学ぶため)
ユーザー登録をすると、確認メールが届くようにしており、そのメールに書かれているリンクを押して初めて、ユーザーが登録される仕様になっています。・簡単ログイン機能
就活用に簡単ログイン機能を実装しました。
ボタン一つでログインできれば、就活の際に見てもらいやすくなるのではないかと考え実装に至りました。・スキルや困りごとのコメント機能
・レスポンシブ対応
スマートフォンが主流なので、そちらでも使いやすくするためにレスポンシブ対応にしました。
課題&追加したい機能
- vueでのモーダル実装(評価する部分)
- ランキング機能(頑張った人ほど目に止まる率が高くなる機能を作りたいため)
- ポイント機能の使用(スキル購入の時に割引として使えるなど)
- カテゴリー別一覧表示
- Rspecテスト
最後に
記事を読んでいただきありがとうございました。
また機能を追加次第、更新していきたいと思います。
- 投稿日:2019-08-19T21:48:36+09:00
大学2年生のオリジナルWebアプリケーション開発4日目
今日の流れ
- Yarnのアップデート
- 基本的なログイン機構の作成
今日は時間がなかったためあまり進められませんでした。
1. Yarnのアップデート
開発中にGitHubから次のような Security Alertsが来ました。
どうやら「Yarnのバージョンが古いからセキュリティー上危険な状態だぞ」ということらしいです。ということで、Yarnのアップデート方法について調べて、解決しました。具体的な方法が気になる方は、次の記事Cloud9上でのYarnのアップデート(Windows)をご覧ください。2. 基本的なログイン機構の作成
Railsチュートリアルの第8章にあたる部分です。個人的にRailsチュートリアルを勉強していた時に、一番頭が追い付かなかったのがこのログイン機構の作成です(特に第9章)。たださすがに3週目なのか第8章はすらすら理解できました。
ログイン機構とは別に、Bootstrapのドロップダウン機能について公式サイトやRailsチュートリアルで呼んでいると、JavaScriptの機能なのだと認識でき、Ruby、Railsしか勉強していない自分からすると、少しJavaScriptを使ったことに感動しました笑。まぁ、最終的にこのアプリケーションではどんどん使っていくつもりではありますが。終わりに
今日は復習メインとなってしまいましたが、Yarnなど初めてきくものもあり、まだまだ知らないことだらけだと実感しました。明日は発展的なログイン機構の作成ですので、気を引き締めていきたいです。
昨日のサマソニはすごかった。
- 投稿日:2019-08-19T21:46:28+09:00
Railsのvalidatesとは?
validatesとは?
フォームに値や文字を入力するときに、必須の項目ってありますよね。
こんな感じの。会員登録の時、「必ず入力してください」っていう項目、誰でも一度は目にしたことがあると思います。
このように入力欄に制限をかける機能のことをvalidatesといいます。
例:空欄を拒否するvalidation
では、実際にコードを記述してvalidationを設定します。
validationはmodelファイルで設定します。
product.rbclass Product < ApplicationRecord validates :name, presence: true end
validates カラム名, バリデーションの条件
の記述でバリデーションを設定しました。今回はproductモデルのnameカラムにpresence: trueというバリデーションをかけました。
presence: trueは
空ではない
という条件のバリデーションです。これによりnameカラムに何らかの文字列が入ってないといけない状態になりました。例:値を被らないようにするvalidation
次に同じ名前が被らないようnameカラムにバリデーションをかけます。
product.rbclass Product < ApplicationRecord validates :user_name, uniqueness: true enduniqueness: trueでnameカラムの値がかぶることを防ぐことができます。
様々なバリデーション
バリデーションにはたくさんの種類があるので、以下の記事を参考にしてみてください
- 投稿日:2019-08-19T21:25:44+09:00
Cloud9上でのYarnのアップデート(Windows)
はじめに
Railsでアプリケーション開発中にGitHubから次のような Security Alertsが来ました。
どうやら開発アプリケーションのherokuフォルダ内のyarn.lockというファイルに問題があるそうです。
Yarnのバージョンが古いらしくセキュリティー上に欠陥がありそうです。この問題を解決するためにYarnのバージョンアップデートの方法について調べ、まとめました。この記事では、Cloud9上でのYarnのアップデート(Windows)の方法をご紹介します。
環境
windows(64bit)
ruby 2.6.3p62
Rails 5.2.2
Cloud9上で開発Yarnとは
YarnとはFacebookなどによって開発された新しいJavaScriptパッケージマネージャーのことです。
アップデート方法
Yarnのアップデートを行うには、yarn.lockというファイルに変更を加えなければなりません。
yarn.lockとは、インストールされたYarnの各依存関係のバージョンを記録しておくファイルです。
ここで注意しなければならないことがあります。Yarnの公式サイトによるとyarn.lock ファイルは自動生成されるため、Yarn を使わずに手動で編集するべきではありません。 Yarn CLI を使用して依存パッケージの add/upgrade/remoe を実行すると、yarn.lockファイルも自動的に更新されます。 簡単に壊れてしまうため、このファイルを直接編集しないでください。
つまり、「yarn.lockに勝手に触れるな、yarnコマンドを使え」ということです。なのでそれに従ってアップデートを行おうと思います。
1. Node.jsのバージョンアップ
まず初めにNodeのstableなバージョンをインストールします。
$ nvm install stableちなみに僕のバージョンはv12.8.1でした。(2019年8月19日現在)
2. Yarnのインストール
次にYarnをインストールします。
$ npm install -g yarnちなみに僕のバージョンは1.17.3でした。(2019年8月19日現在)
3. Yarnのアップデート
実際に僕がアップデートした lodash.merge というYarnを例にとってみます。バージョンを4.6.2にするように求められたので、次のようにしてアップデートしました。
$ yarn upgrade lodash.merge@^4.6.2これでアップデート完了です!
残りのものも同様にアップデートしたところGitHubからの Security Alerts は来なくなりました。参考文献
(1) Yarn公式サイト. https://yarnpkg.com/ja/, (参照 2019-8-19)
(2) "cloud9でvue-cli 3 環境構築". Qiita. https://qiita.com/MssKnd/items/381483cad854b257586d, (参照 2019-8-19)
- 投稿日:2019-08-19T19:03:22+09:00
Railsのイベントで初心者ながらすごいなと思ったまとめ
先日Ruby/Railsのイベントに行ったので印象的だったことを簡単にはなりますがまとめました。
Railsは初めて触ったので認識が誤っている点があればご指摘ください...!scaffoldコマンド
MVCモデルに沿ったファイルの雛形を作ってくれる。
CRUD機能(Create, Read, Update, Delete)を簡単かつ一気に実装できるコマンド$ rails generate scaffold モデル名 カラム名:型一気にいろいろできるので処理が止まるまで少々待ちましょう。
基本的な機能は揃っていますがカスタマイズしたい場合などはscaffoldではなく、ひとつひとつ作るのがいいですとのことでした。
scaffoldを失敗してしまったと気づいたときはこちら
※scaffoldしたあとはマイグレーションファイルが作成されるので、テーブルを作成したことをDBに認識させるためにrails db:migrate
とサーバーを再起動しないとうまく読み込めなくなるので注意が必要
①scaffold
コマンドで設計図(migrationファイル)ができる
②rails db:migrate
で設計図(migrationファイル)の通りにDBが作成される、ということでした。
こちらを参考にさせていただきました。
※ @scivola さんにご指摘いただいたので確認しまして修正しました。ありがとうございました!現在定義されているルートの確認
①ターミナルに表示する方法
rails routes→laravelの
php artisan route:list
と似た感じで、ターミナルに表示されます②サーバーに表示する方法
localhost:3000/rails/info/routes→個人的にはこちらのほうが見やすかったです
gem
ライブラリやアプリケーションのパッケージで自分で実装すると時間がかかる機能も簡単にできるようになります。
ページネーション、画像を指定のサイズで作成など‥
gemの一種のBundlerをいれることで、Gemfileというファイルにパッケージ名、バージョンを記述してgem同士の互換性を保ちながらパッケージの種類やバージョンを管理してくれます。
Ruby gemsちょっとしたコードのテスト
直感的で使いやすく、ちょっとしたコードの確認ができます。見やすいし、初心者にはありがたい
TryRuby番外編:ターミナルからVScodeを起動する方法
1.
command
+shift
+p
2.shell
を入力
3.shell command:install 'code' command in PATH
を選択
4. ターミナルでcode .
参考にさせていただきました
macにもともとあるターミナルからVScodeが立ち上がるのですが、その発想なかったな〜と何度か試してしまいました。おもしろい!まとめ
laravelとルーティングの書き方が似ていたので想像しやすい部分もあったり、初めてでも便利なコマンドがたくさんあり面白かったです。
たくさんの地域コミュニティがあったり、なんとメンターさんが一人ひとりについてくれたり(!)、アットホームでわからないことを聞きやすい雰囲気が印象的で参加してよかったなぁと思いました。Rails Girls ガイド
初心者のひとは環境設定に躓くような気がしているのですが、全てわかりやすくのっているので簡単にできました
- 投稿日:2019-08-19T17:06:45+09:00
capybaraでファイルダウンロードをテストする
Capybaraでファイルをダウンロードするテストを書いたので備忘録
Capybaraでファイルをダウンロードすると、デフォルトのダウンロードディレクトリ(~/Downloads)にファイルがダウンロードされるため、テストがしづらい。
設定を追加して、システムテストを実行しやすくする。まずは、Capybaraで利用するWebDriverにダウンロードディレクトリを設定する
# spec/support/capybara.rb # frozen_string_literal: true require 'capybara/rspec' # 読みこんで、Capybara.current_driverの初期化を済ませる require 'action_dispatch/system_test_case' Capybara.register_driver(:pc_headless) do |app| options = Selenium::WebDriver::Chrome::Options.new options.headless! Capybara::Selenium::Driver.new(app, browser: :chrome, options: options) end RSpec.configure do |config| config.before(type: :system) do |example| driven_by(:pc_headless) # ここ。ダウンロード先を指定する page.driver.browser.download_path = CapybaraDownloadsHelper.path end end続いて、ダウンロードファイルをテストで利用するためのヘルパーを用意する
# spec/support/xxx_helper.rb # frozen_string_literal: true # Capybaraでダウンロードしたファイルを管理する module CapybaraDownloadsHelper PATH = Rails.root.join('tmp', 'data', 'downloads').to_s.freeze class << self # ダウンロード先のディレクトリ # # @return [String] def path File.join(PATH, Thread.current.object_id.to_s) end # ダウンロードしたファイル一覧を返す # # @return [Array<String>] def files Dir[File.join(path, '*')] end # ダウンロードが完了したか # # @return [boolean] ダウンロードが完了していればtrue def downloaded? files.grep(/\.crdownload$/).none? && files.any? end # ダウンロードしたファイルを削除する # # @return [void] def delete_all FileUtils.rm_f(files) end end end RSpec.configure do |config| config.before(:all) do FileUtils.mkdir_p(CapybaraDownloadsHelper.path) end config.after(:all) do FileUtils.rm_rf(CapybaraDownloadsHelper.path) end config.before do CapybaraDownloadsHelper.delete_all end endこれで、簡単にテストを行うことができるようになる。
RSpec.describe 'download', type: :system do it 'downloads file' do find('#download_link').click Timeout.timeout(10.second) do loop do break if CapybaraDownloadsHelper.downloaded? end end file = CapybaraDownloadsHelper.files[0] expect(file).to test_something end end
- 投稿日:2019-08-19T16:39:36+09:00
Ruby on Railsに触れてみる
はじめに
普段はPHP&JSで開発を行っているのですが、夏休みに入り時間的余裕ができたので、以前から気になっていたRuby on railsに触れたいと思います。
本記事ではUbuntu19.04上で開発環境を整えることをやっていきます。インストール
今回インストールするものは以下です!
- rbenv
- ruby-build
rbenv
Rubyのバージョン管理をしてくれるやつです。pythonで言うpyenvですね。
次のコマンドでインストールターミナル# apt install rbenv # rbenv -v ←入ったかどうかバージョンを見て確認!Ruby-build
rbenvのinstallコマンドを提供しているプラグインらしいです。
これが古いと新し目のバージョンがinstall listにないので気をつけてください。
さっきのコマンド実行時にインストールを一緒にしてくれているのですが、2.4.*のバージョンまでしかlistに出てこなかったので、以下のコマンドで新しくしてください。ターミナル# git clone https://github.com/rbenv/ruby-build.git ~/.rbenv/plugins/ruby-buil
早速Rubyをインストール
ターミナル# rbenv install -l ←インストールできるバージョンを表示 ----(略)---- 2.6.0-rc2 2.6.0 2.6.1 2.6.2 2.6.3 2.7.0-dev 2.7.0-preview1 ----(略)----- # rbenv install 2.6.0 ←2.6.0をインストール # rbenv versions ←インストールしたバージョンを確認 * system (set by /root/.rbenv/version) 2.6.0 # rbenv global 2.6.0 ←システムで使用するRubyを2.6.0に設定 # ruby -v ←バージョンの確認 ruby 2.5.5p157 (2019-03-15 revision 67260) [x86_64-linux-gnu]・・・変わってないだと!?
Rubyのバージョンがしっかり変わらない問題
調べたらPATHがしっかり通っていませんでした。
ubuntuなら以下のコマンドを実行してbash_profileを編集すれば直ります!ターミナル# vi ~/.bash_profile --以下のものを追記------ export PATH="~/.rbenv/shims:/usr/local/bin:$PATH" eval "$(rbenv init -)" ---------------------- # source ~/.bash_profile ←変更を適用 # rbenv global 2.6.0 # ruby -v ruby 2.6.0p0 (2018-12-25 revision 66547) [x86_64-linux]これで、しっかり変わりました!
railsをインストール
ターミナル# apt-get install build-essential liblzma-dev patch ruby-dev zlib1g-dev # gem install rails # rails --version Rails 5.2.2これでRailsのインストールが終了しました。
とりあえずプロジェクトを作成する
インストールできたので適当なサンプルプロジェクトを作ってみます。
とりあえずデスクトップに作っていきます。ターミナル# rails new foo # cd foo # rails s (略) ker/configuration.rb:91:in `rescue in load': Webpacker configuration file not found /home/hara/デスクトップ/foo/config/webpacker.yml. Please run rails webpacker:install Error: No such file or directory @ rb_sysopen - /home/hara/デスクトップ/foo/config/webpacker.yml (RuntimeError)なんかエラーコード吐かれた・・・
webpackerの設定が見つからないらしいので、そこらへんの情報を検索し以下のコードを実行したら直りました。
ターミナルyarnをインストール # curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | sudo apt-key add - # echo "deb https://dl.yarnpkg.com/debian/ stable main" | sudo tee /etc/apt/sources.list.d/yarn.list # sudo apt-get update && sudo apt-get install yarn 作ったプロジェクトフォルダー内で # rails webpacker:install 終わったあと # rails s => Booting Puma => Rails 6.0.0 application starting in development => Run 'rails server --help' for more startup options Puma starting in single mode... * Version 3.12.1 (ruby 2.6.0-p0), codename: Llamas in Pajamas * Min threads: 5, max threads: 5 * Environment: development * Listening on tcp://localhost:3000 Use Ctrl-C to stopこれでサーバが起動したのでlocalhost:3000 にアクセス
下のような画面が出れば無事Ruby on Railsを使う準備ができました。
とりあえずこれからなにかWebサービスを作ってみていろいろ試します〜〜
参考にさせていただいた記事・サイト
- 投稿日:2019-08-19T16:17:16+09:00
rails6アップデート時のrails app:update(devise)エラー,ActionDispatch::Routing::RouteSet:Class
rails6にあげるときこんなエラーが出た
> % rails app:update rails aborted! NoMethodError: undefined method `alias_method_chain' for ActionDispatch::Routing::RouteSet:Class Did you mean? alias_method /Users/jin/workspace/hoge/fuga/piyo/vendor/bundle/ruby/2.6.0/gems/devise-1.5.4/lib/devise/rails/routes.rb:14:in `<class:RouteSet>' /Users/jin/workspace/hoge/fuga/piyo/vendor/bundle/ruby/2.6.0/gems/devise-1.5.4/lib/devise/rails/routes.rb:2:in `<module:Routing>' /Users/jin/workspace/hoge/fuga/piyo/vendor/bundle/ruby/2.6.0/gems/devise-1.5.4/lib/devise/rails/routes.rb:1:in `<main>' /Users/jin/workspace/hoge/fuga/piyo/vendor/bundle/ruby/2.6.0/gems/bootsnap-1.4.4/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:22:in `require' /Users/jin/workspace/hoge/fuga/piyo/vendor/bundle/ruby/2.6.0/gems/bootsnap-1.4.4/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:22:in `block in require_with_bootsnap_lfi' /Users/jin/workspace/hoge/fuga/piyo/vendor/bundle/ruby/2.6.0/gems/bootsnap-1.4.4/lib/bootsnap/load_path_cache/loaded_features_index.rb:92:in `register' /Users/jin/workspace/hoge/fuga/piyo/vendor/bundle/ruby/2.6.0/gems/bootsnap-1.4.4/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:21:in `require_with_bootsnap_lfi' /Users/jin/workspace/hoge/fuga/piyo/vendor/bundle/ruby/2.6.0/gems/bootsnap-1.4.4/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:30:in `require' /Users/jin/workspace/hoge/fuga/piyo/vendor/bundle/ruby/2.6.0/gems/activesupport-6.0.0/lib/active_support/dependencies.rb:325:in `block in require' /Users/jin/workspace/hoge/fuga/piyo/vendor/bundle/ruby/2.6.0/gems/activesupport-6.0.0/lib/active_support/dependencies.rb:291:in `load_dependency' /Users/jin/workspace/hoge/fuga/piyo/vendor/bundle/ruby/2.6.0/gems/activesupport-6.0.0/lib/active_support/dependencies.rb:325:in `require' /Users/jin/workspace/hoge/fuga/piyo/vendor/bundle/ruby/2.6.0/gems/devise-1.5.4/lib/devise/rails.rb:1:in `<main>' /Users/jin/workspace/hoge/fuga/piyo/vendor/bundle/ruby/2.6.0/gems/bootsnap-1.4.4/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:22:in `require' /Users/jin/workspace/hoge/fuga/piyo/vendor/bundle/ruby/2.6.0/gems/bootsnap-1.4.4/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:22:in `block in require_with_bootsnap_lfi' /Users/jin/workspace/hoge/fuga/piyo/vendor/bundle/ruby/2.6.0/gems/bootsnap-1.4.4/lib/bootsnap/load_path_cache/loaded_features_index.rb:92:in `register' /Users/jin/workspace/hoge/fuga/piyo/vendor/bundle/ruby/2.6.0/gems/bootsnap-1.4.4/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:21:in `require_with_bootsnap_lfi' /Users/jin/workspace/hoge/fuga/piyo/vendor/bundle/ruby/2.6.0/gems/bootsnap-1.4.4/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:30:in `require' /Users/jin/workspace/hoge/fuga/piyo/vendor/bundle/ruby/2.6.0/gems/activesupport-6.0.0/lib/active_support/dependencies.rb:325:in `block in require' /Users/jin/workspace/hoge/fuga/piyo/vendor/bundle/ruby/2.6.0/gems/activesupport-6.0.0/lib/active_support/dependencies.rb:291:in `load_dependency' /Users/jin/workspace/hoge/fuga/piyo/vendor/bundle/ruby/2.6.0/gems/activesupport-6.0.0/lib/active_support/dependencies.rb:325:in `require' /Users/jin/workspace/hoge/fuga/piyo/vendor/bundle/ruby/2.6.0/gems/devise-1.5.4/lib/devise.rb:445:in `<main>' /Users/jin/workspace/hoge/fuga/piyo/vendor/bundle/ruby/2.6.0/gems/bootsnap-1.4.4/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:22:in `require' /Users/jin/workspace/hoge/fuga/piyo/vendor/bundle/ruby/2.6.0/gems/bootsnap-1.4.4/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:22:in `block in require_with_bootsnap_lfi' /Users/jin/workspace/hoge/fuga/piyo/vendor/bundle/ruby/2.6.0/gems/bootsnap-1.4.4/lib/bootsnap/load_path_cache/loaded_features_index.rb:92:in `register' /Users/jin/workspace/hoge/fuga/piyo/vendor/bundle/ruby/2.6.0/gems/bootsnap-1.4.4/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:21:in `require_with_bootsnap_lfi' /Users/jin/workspace/hoge/fuga/piyo/vendor/bundle/ruby/2.6.0/gems/bootsnap-1.4.4/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:30:in `require' /Users/jin/workspace/hoge/fuga/piyo/config/application.rb:20:in `<main>' /Users/jin/workspace/hoge/fuga/piyo/vendor/bundle/ruby/2.6.0/gems/bootsnap-1.4.4/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:22:in `require' /Users/jin/workspace/hoge/fuga/piyo/vendor/bundle/ruby/2.6.0/gems/bootsnap-1.4.4/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:22:in `block in require_with_bootsnap_lfi' /Users/jin/workspace/hoge/fuga/piyo/vendor/bundle/ruby/2.6.0/gems/bootsnap-1.4.4/lib/bootsnap/load_path_cache/loaded_features_index.rb:92:in `register' /Users/jin/workspace/hoge/fuga/piyo/vendor/bundle/ruby/2.6.0/gems/bootsnap-1.4.4/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:21:in `require_with_bootsnap_lfi' /Users/jin/workspace/hoge/fuga/piyo/vendor/bundle/ruby/2.6.0/gems/bootsnap-1.4.4/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:30:in `require' /Users/jin/workspace/hoge/fuga/piyo/vendor/bundle/ruby/2.6.0/gems/activesupport-6.0.0/lib/active_support/dependencies.rb:325:in `block in require' /Users/jin/workspace/hoge/fuga/piyo/vendor/bundle/ruby/2.6.0/gems/activesupport-6.0.0/lib/active_support/dependencies.rb:291:in `load_dependency' /Users/jin/workspace/hoge/fuga/piyo/vendor/bundle/ruby/2.6.0/gems/activesupport-6.0.0/lib/active_support/dependencies.rb:325:in `require' /Users/jin/workspace/hoge/fuga/piyo/vendor/bundle/ruby/2.6.0/gems/bootsnap-1.4.4/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:48:in `require_relative' /Users/jin/workspace/hoge/fuga/piyo/Rakefile:6:in `<main>' /Users/jin/workspace/hoge/fuga/piyo/vendor/bundle/ruby/2.6.0/gems/bootsnap-1.4.4/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:54:in `load' /Users/jin/workspace/hoge/fuga/piyo/vendor/bundle/ruby/2.6.0/gems/bootsnap-1.4.4/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:54:in `load' /Users/jin/workspace/hoge/fuga/piyo/vendor/bundle/ruby/2.6.0/gems/activesupport-6.0.0/lib/active_support/dependencies.rb:319:in `block in load' /Users/jin/workspace/hoge/fuga/piyo/vendor/bundle/ruby/2.6.0/gems/activesupport-6.0.0/lib/active_support/dependencies.rb:291:in `load_dependency' /Users/jin/workspace/hoge/fuga/piyo/vendor/bundle/ruby/2.6.0/gems/activesupport-6.0.0/lib/active_support/dependencies.rb:319:in `load' /Users/jin/workspace/hoge/fuga/piyo/vendor/bundle/ruby/2.6.0/gems/railties-6.0.0/lib/rails/commands/rake/rake_command.rb:22:in `block in perform' /Users/jin/workspace/hoge/fuga/piyo/vendor/bundle/ruby/2.6.0/gems/railties-6.0.0/lib/rails/commands/rake/rake_command.rb:20:in `perform' /Users/jin/workspace/hoge/fuga/piyo/vendor/bundle/ruby/2.6.0/gems/railties-6.0.0/lib/rails/command.rb:48:in `invoke' /Users/jin/workspace/hoge/fuga/piyo/vendor/bundle/ruby/2.6.0/gems/railties-6.0.0/lib/rails/commands.rb:18:in `<main>' /Users/jin/workspace/hoge/fuga/piyo/vendor/bundle/ruby/2.6.0/gems/bootsnap-1.4.4/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:22:in `require' /Users/jin/workspace/hoge/fuga/piyo/vendor/bundle/ruby/2.6.0/gems/bootsnap-1.4.4/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:22:in `block in require_with_bootsnap_lfi' /Users/jin/workspace/hoge/fuga/piyo/vendor/bundle/ruby/2.6.0/gems/bootsnap-1.4.4/lib/bootsnap/load_path_cache/loaded_features_index.rb:92:in `register' /Users/jin/workspace/hoge/fuga/piyo/vendor/bundle/ruby/2.6.0/gems/bootsnap-1.4.4/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:21:in `require_with_bootsnap_lfi' /Users/jin/workspace/hoge/fuga/piyo/vendor/bundle/ruby/2.6.0/gems/bootsnap-1.4.4/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:30:in `require' /Users/jin/workspace/hoge/fuga/piyo/vendor/bundle/ruby/2.6.0/gems/activesupport-6.0.0/lib/active_support/dependencies.rb:325:in `block in require' /Users/jin/workspace/hoge/fuga/piyo/vendor/bundle/ruby/2.6.0/gems/activesupport-6.0.0/lib/active_support/dependencies.rb:291:in `load_dependency' /Users/jin/workspace/hoge/fuga/piyo/vendor/bundle/ruby/2.6.0/gems/activesupport-6.0.0/lib/active_support/dependencies.rb:325:in `require' bin/rails:6:in `<main>' (See full trace by running task with --trace)Gemfileを以下に設定すると成功する
gem 'devise', git: 'https://github.com/plataformatec/devise'参考
- 投稿日:2019-08-19T12:37:55+09:00
Rails / Bootstrap 4
概要
Rails で Bootstrap 4 を利用するための初期設定
動作環境
- Rails 5.2.3
- ruby 2.5.5
表記の注意事項
「$」 記号は ターミナルにおける /bin/bash のコマンドプロンプトを表します 「+ 」 (プラスとスペース1字)は、ファイル編集において、追記した行を表します 「- 」 (マイナスとスペース1字)は、ファイル編集において、削除した行を表します導入手順
Gem
Gemfile+ gem 'bootstrap', '~> 4.3.1' + # Bootstrap JavaScript depends on jQuery. If you're using Rails 5.1+, add the jquery-rails gem to your Gemfile + gem 'jquery-rails'$ bundle installSCSSマニフェストファイル
CSSマニフェストファイルを SCSSマニフェストファイルに変更
$ git mv app/assets/stylesheets/application.css app/assets/stylesheets/application.scssSCSSマニフェストファイル設定
app/assets/stylesheets/application.scss- *= require_tree . - *= require_self */ + // Custom bootstrap variables must be set or imported *before* bootstrap. + @import "bootstrap";JSマニフェストファイル設定
app/assets/javascripts/application.js//= require turbolinks + //= require jquery3 + //= require popper + //= require bootstrap-sprockets //= require_tree .参考
- 投稿日:2019-08-19T12:34:31+09:00
Rails6 のちょい足しな新機能を試す66(query with large number編)
はじめに
Rails 6 に追加されそうな新機能を試す第66段。 今回は、
query with large number
編です。
Rails 6 では、 検索条件の値が Integer などの型の範囲外の値であっても検索できるようになりました。Ruby 2.6.3, Rails 6.0.0.rc1, Rails 5.2.3 で確認しました。Rails 6.0.0.rc1 は
gem install rails --prerelease
でインストールできます。(Rails 6.0.0 がリリースされましたが、確認当時は Rails 6.0.0.rc1 がリリースされた時でした。悪しからず。)
$ rails --version Rails 6.0.0.rc1今回は、 User モデルに
:bigint
を指定したage
を追加して、age
の範囲外の値を検索条件にして検索してみます。プロジェクトを作る
rails new rails6_0_0rc1 cd rails6_0_0rc1
model を作る
User モデルを作ります。
name
の他に:bigint
を指定したage
を追加します。bin/rails g model User name age:bigintseed データを作る
1件だけですが、 seed データを作成します。
db/seeds.rbUser.create(name: 'Taro', age: 1)User モデルを修正する
User モデルに scope を5つ作ります。
ここで条件に age の値の範囲に含まれない大きな値と小さな値を指定します。
app/models/user.rbclass User < ApplicationRecord LARGE = 9223372036854775808 SMALL = -9223372036854775809 scope :age_in_large, -> { where(age: [1..LARGE]) } scope :age_eq_large, -> { where(age: LARGE) } scope :age_not_eq_large, -> { where.not(age: LARGE) } scope :age_in_small, -> { where(age: [SMALL..1]) } scope :age_in_small_large, -> { where(age: [SMALL..LARGE]) } endseed データを登録します。
$ bin/rails db:create db:migrate db:seed
rails console で確認する
rails console
で確認してみます。irb(main):001:0> User.age_in_large User Load (0.4ms) SELECT "users".* FROM "users" WHERE "users"."age" >= $1 LIMIT $2 [["age", 1], ["LIMIT", 11]] => #<ActiveRecord::Relation [#<User id: 1, name: "Taro", age: 1, created_at: "2019-07-26 21:21:06", updated_at: "2019-07-26 21:21:06">]> irb(main):002:0> User.age_eq_large User Load (0.5ms) SELECT "users".* FROM "users" WHERE 1=0 LIMIT $1 [["LIMIT", 11]] => #<ActiveRecord::Relation []> irb(main):003:0> User.age_not_eq_large User Load (0.5ms) SELECT "users".* FROM "users" WHERE 1=1 LIMIT $1 [["LIMIT", 11]] => #<ActiveRecord::Relation [#<User id: 1, name: "Taro", age: 1, created_at: "2019-07-26 21:21:06", updated_at: "2019-07-26 21:21:06">]> irb(main):004:0> User.age_in_small User Load (0.3ms) SELECT "users".* FROM "users" WHERE "users"."age" <= $1 LIMIT $2 [["age", 1], ["LIMIT", 11]] => #<ActiveRecord::Relation [#<User id: 1, name: "Taro", age: 1, created_at: "2019-07-26 21:21:06", updated_at: "2019-07-26 21:21:06">]> irb(main):005:0> User.age_in_small_large User Load (0.8ms) SELECT "users".* FROM "users" WHERE 1=1 LIMIT $1 [["LIMIT", 11]] => #<ActiveRecord::Relation [#<User id: 1, name: "Taro", age: 1, created_at: "2019-07-26 21:21:06", updated_at: "2019-07-26 21:21:06">]>ここで、実際に発行されているSQLに注目してください。SQL自体には、 -9223372036854775809 や 9223372036854775808 は登場しません。
これは、 age の値として、 -9223372036854775809 や 9223372036854775808 は、あり得ない範囲外の値なので、検索条件に含まなくても良いためです。
工夫されてますね。User.age_not_eq_large
の条件のwhere 1=1
など、なるほどと思ってしまいます。Rails 5では
検索条件の値が、
age
の範囲に収まらないため、 RangeError になってしまいます。irb(main):001:0> User.age_eq_large Traceback (most recent call last): ActiveModel::RangeError (9223372036854775808 is out of range for ActiveModel::Type::Integer with limit 8 bytes) irb(main):002:0> User.age_not_eq_large Traceback (most recent call last): ActiveModel::RangeError (9223372036854775808 is out of range for ActiveModel::Type::Integer with limit 8 bytes) irb(main):003:0> User.age_in_large Traceback (most recent call last): ActiveModel::RangeError (9223372036854775808 is out of range for ActiveModel::Type::Integer with limit 8 bytes) irb(main):004:0> User.age_in_small Traceback (most recent call last): ActiveModel::RangeError (-9223372036854775809 is out of range for ActiveModel::Type::Integer with limit 8 bytes) irb(main):005:0> User.age_in_small_large Traceback (most recent call last): ActiveModel::RangeError (-9223372036854775809 is out of range for ActiveModel::Type::Integer with limit 8 bytes)試したソース
試したソースは以下にあります。
https://github.com/suketa/rails6_0_0rc1/tree/try066_query_with_large_number参考情報
- 投稿日:2019-08-19T09:54:46+09:00
#Rails - GrapeLogging でパスワードのパラメータをフィルタする設定例
Rails-Configuration example for filtering password parameters with GrapeLogging
logger.formatter = GrapeLogging::Formatters::Default.new use GrapeLogging::Middleware::RequestLogger, logger: logger, include: [ GrapeLogging::Loggers::FilterParameters.new ]# ログの例 (一部)
"password":"[FILTERED]","password_confirmation":"[FILTERED]"Original by Github issue
- 投稿日:2019-08-19T08:27:31+09:00
Rails deviseの画面をカスタマイズ
はじめに
deviseの準備はできましたが、カスタマイズもしてみたいと思いました。
今回はdeviseのログイン画面をそれっぽくカスタマイズします。ビューをカスタマイズする
ビューをカスタマイズするには
Rails deviseの準備でも記述したように、deviseのカスタマイズ用のビューを生成する必要があります。
今回はログイン画面をカスタマイズしますので、生成された「app/views/devise/sessions/new.html.erb」をカスタマイズします。
修正前の画面
修正前の画面は次のようになります。
deviseのデフォルトのログイン画面です。ブラウザはChromeとなります。
修正後のコード
「app/views/devise/sessions/new.html.erb」を次のように修正します。
app/views/devise/sessions/new.html.erb<div class="box"> <div class="box-inner"> <%= form_for(resource, as: resource_name, url: session_path(resource_name)) do |f| %> <h1>ログイン</h1> <div class="box-email"> <%= f.label :email, "Eメール" %><br /> <%= f.email_field :email, autofocus: true, autocomplete: "email" %> </div> <div class="box-password"> <div class="a-row"> <div class="column-left"> <%= f.label :password, "パスワード" %> </div> <div class="column-right"> <%= link_to "パスワードを忘れた場合", new_user_password_path %> </div> </div> <%= f.password_field :password, autocomplete: "current-password" %> </div> <div class="box-login"> <%= f.submit "ログイン" %> <div class="legal-text"> 続行することで、Hogezonの <%= link_to "利用規約", "#" %> および <%= link_to "プライバシー規約", "#" %> に同意するものとみなされます。 </div> <% if devise_mapping.rememberable? %> <div class="remember"> <%= f.check_box :remember_me %> <%= f.label :remember, "ログインしたままにする" %> </div> <% end %> </div> <% end %> <div class="box-newusr"> <p><span>------------</span> Hogezonの新しいお客様ですか? <span>------------</span></p> <%= link_to "Hogezonアカウントを作成", new_user_registration_path %> </div> </div> </div>利用規約とプライバシー規約は未実装です。
雰囲気だけ出してます。CSSファイルを追加します。
app/assets/stylesheets/signup.css* { margin: 0px; padding: 0px; text-decoration: none; } .box { width: 350px; height: 450px; margin: 60px auto 0; border-radius: 4px; border: 1px #ddd solid; } .box-inner { padding: 20px 26px; } h1 { font-weight: 400; font-size: 28px; line-height: 1.2; margin-bottom: 10px; padding-bottom: 4px; color: #111111; } .box-email { margin-bottom: 13px; } .box-password { margin-bottom: 22px; } .box-email label, .box-password label { font-weight: 700; font-size: 13px; padding-left: 2px; padding-bottom: 2px; } .box-email input[type="email"], .box-password input[type="password"] { border-style: none; box-sizing: border-box; width: 100%; height: 31px; border: 1px solid #a6a6a6; box-shadow: 0 1px 0 rgba(0,0,0,.07) inset; border-radius: 3px; padding: 0 7px; } .column-left { float: left; } .column-right { float: right; } .box-password a { font-size: 13px; } .box-login { margin-bottom: 26px; } .box-login input[type="submit"] { border-style: none; width: 100%; height: 31px; background: linear-gradient(to bottom,#f7dfa5,#f0c14b); border-radius: 3px; border: 1px #a88734 solid; } .box-login input[type="submit"]:hover { cursor: pointer; background: #f0c14b; } .legal-text { margin-top: 18px; font-size: 12px; } .remember { font-size: 13px; margin-top: 18px; padding-left: 3px; } .box-newusr p { text-align: center; font-size: 12px; color: #767676; margin-bottom: 14px; } .box-newusr p span { text-decoration: line-through; text-decoration-color: #e7e7e7; } .box-newusr a { display: block; width: 100%; height: 31px; font-size: 13px; color: #111; line-height: 31px; text-align: center; background: linear-gradient(to bottom,#f7f8fa,#e7e9ec); border-radius: 3px; border: 1px #a2a6ac solid; } .box-newusr a:hover { background: #e7e9ec; }修正後の画面
ログイン画面がカスタマイズされました。
おわりに
「Hogezonの新しいお客様ですか?」の部分の横線がうまく表現できず、手を抜いて実装してしまいました。
deviseのビューをカスタマイズできたということで、よしとします。間違っている箇所とかがありましたら、教えていただけると助かります。
- 投稿日:2019-08-19T07:17:30+09:00
永久保存版!?伊藤さん式・Railsアプリのアップグレード手順
はじめに
Railsアプリケーションを長く運用していると避けて通れないのがRailsのバージョンアップです。
古いバージョンのRailsは順次サポートの対象から外れていく(=不具合修正やセキュリティ対応がされなくなる)ため、バージョンアップをせずに運用するわけにはいきません。
そこでこの記事では僕・伊藤淳一がRailsアプリのバージョンをアップグレード(アップデート)する手順を紹介します。
この手順はこれまで何度もRailsアプリケーションをアップグレードしてきた僕の知見が詰まった、いわば「秘伝のタレ」的なアップグレード手順です。
想定するRailsアプリケーション
この記事で想定しているのは以下のようなRailsアプリケーションです。
- 開発者1人でもなんとか面倒が見れるレベルの規模(=アップグレードは1人で作業する想定)
- 趣味で作っているのではなく、外部のユーザーがいるRailsアプリ(=不具合が発生すると困る人が出てくるサービス)
また、この記事でいうアップグレードとは、マイナーアップグレード(例:5.1系から5.2系)とメジャーアップグレード(例:5.2系から6.0系)のことです。
手順の概要
この記事は長いので、先に手順の概要を示しておきます。
- Rails以外のgemを最新にする
- Rubyのバージョンを最新にする
- Railsをバージョンアップする
rails app:update
タスクを実行するrails c
やrails s
でRailsが正常に起動することを確認する- 自動テストと手動テストで動作確認する
- 問題が無さそうならサーバーにデプロイする
ざっくり言うとこんな感じになります。
それでは以下が本文です。1. 公式のアップグレードガイドに目を通す
Railsガイドにはアップグレードの方法を説明している項があります。
アップグレードする際の主な注意点もバージョンごとに載っているので、まずはこのページに目を通します。日本語訳が追いついていないケースもあるので、英語版にも目を通しておく方がよいでしょう。
Upgrading Ruby on Rails — Ruby on Rails Guides
2. テストが全部パスすることを確認する
実際のアップグレード作業を開始する前に、RSpecやMinitestで書いたテストコードを実行し、全部テストがパスすることを確認します。
bundle exec rspecカバレッジにも注目し、必要に応じてテストを書き足す
テストが全部パスしていても、カバレッジが低いとテスト不足のため、アップグレード版をリリースした後にシステムエラーが発生、ということが起きかねません。
Simplecovのようなgemを使って、どのファイルがどれくらいテストされているか確認しておきましょう。
そして、「このロジックをテストコードでテストしていないのは怖い」という箇所が見つかったら、アップグレードする前にテストを書いておきましょう。
テストコードを書くのは面倒かもしれませんが、このあとのステップで何度もテストを実行します。
急がば回れの精神でテストを書きましょう。
トータルで見ればその工数は必ずペイできるはずです。3. 開発用ブランチを作成する
いつでもバージョンアップ前のコードベースに戻せるよう、開発用ブランチを作成しておきます。
# 例:Rails 6に移行するための開発用ブランチを作成する git checkout -b rails-6-0-migration4. Rails以外のgemをバージョンアップする
Rails本体のバージョンを先に上げてしまうと、DeviseやCarrierwaveのような周辺のgemが最新のRailsに対応しておらず、思いがけないエラーが起きるかもしれません。
そもそも、古いgemが大量に混じっていると、
bundle update rails
を実行したときにバージョン番号の解決がうまくいかず、bundle update
が正常に完了できない、ということもよく起きます。なので、先にRails以外のgemを可能な限り最新版にバージョンアップしていきます。
具体的な手順は以下のとおりです。4-a. 最新ではないgemを探す
bundle outdated
というコマンドを使うと、Railsアプリ内で最新バージョンを使っていないgemの一覧が得られます。
さらに、bundle_outdated_formatterというgemを使うと、bundle outdated
の結果を見やすく整形することができます。参考:bundle outdatedコマンドの出力を汎用的な形式に変換するgemを作りました - Qiita
# bundle_outdated_formatterの出力例 bundle outdated | bof --format markdown | gem | newest | installed | requested | groups | | --- | --- | --- | --- | --- | | bootstrap-sass | 3.4.1 | 3.4.0 | | default | | capybara | 3.28.0 | 3.12.0 | | test | | childprocess | 2.0.0 | 0.9.0 | | | | chromedriver-helper | 2.1.1 | 2.1.0 | | test | | coffee-rails | 5.0.0 | 4.2.2 | | default | | dotenv | 2.7.5 | 2.5.0 | | | | dotenv-rails | 2.7.5 | 2.5.0 | | development, test |上の出力例をマークダウンのテーブルとして表示した場合↓
gem newest installed requested groups bootstrap-sass 3.4.1 3.4.0 default capybara 3.28.0 3.12.0 test childprocess 2.0.0 0.9.0 chromedriver-helper 2.1.1 2.1.0 test coffee-rails 5.0.0 4.2.2 default dotenv 2.7.5 2.5.0 dotenv-rails 2.7.5 2.5.0 development, test この結果を見ながら、どのgemがどれくらい最新バージョンから古くなっているのかを分析します。
コラム:原則としてGemfileにバージョンは指定しない
特別な理由がない限り、Gemfileにはgemのバージョンを指定しないようにします。
Gemfile# NG: バージョンを指定する gem 'devise', '~> 4.5.0' # OK: バージョンを指定しない gem 'devise'バージョンを指定しない方が、このあとで全部のgemを一気に最新版にアップデートしやすくなるためです。
バージョンを指定する明確な理由がある場合はその理由をコメントとして書いておきます。
以下はその記述例です。Gemfile# 4.6以上にするとxxxでエラーが発生する。以下のissueが解決したら最新版を使う # https://github.com/plataformatec/devise/issues/9999999 gem 'devise', '~> 4.5.0'4-b. developmentとtestグループのgemを先にアップデートする
アプリケーションの動きに影響を与える可能性が低い、developmentグループとtestグループのgemから先にアップデートします。
以下のコマンドを使うとグループ単位で一気にgemをアップデートできます。bundle update -g development -g test
アップデートしたらテストが全部パスすることを確認します。
4-c. トラブルが起きやすそうなgemを1つずつアップデートする
bundle outdated
の結果を見て、メジャーバージョン番号が変わっているgemや、自分の経験上アップデート時にトラブルが発生しやすいgemを1つずつ慎重にアップデートします。アップデートを実行する前にリポジトリのCHANGELOGを確認して、トラブルを引き起こしそうな(=後方互換性が大きく失われるような)変更履歴がないかどうか、チェックすることも重要です。
例:DeviseのCHANGELOG
https://github.com/plataformatec/devise/blob/master/CHANGELOG.mdCHANGELOGを確認したら、gemを1つずつアップデートしていきます。
# 例:deviseだけをアップデートする bundle update devisegemをアップデートしたら、テストを実行したり、実際に画面を操作したりして、今まで通り使えているかどうかを確認します。
このようにして、トラブルが起きやすそうなgemを1つずつアップデートしていきます。
4-d. その他のgemをまとめてアップデートする
トラブルが起きやすそうなgemのアップデートが一通り終わったら、その他のgemをまとめてアップデートします。
# その他のgemをまとめてアップデートする bundle updateなお、この作業を行う前に、Railsのバージョンが固定されていることを確認しておいてください。
(Railsだけは、まだバージョンを変えたくないため)Gemfile# Railsは特定のバージョンに固定されていること gem 'rails', '5.2.1'その他のgemをアップデートしたら、テストを実行したり、実際に画面を操作したりして、今まで通り使えているかどうかを確認します。
特に、何らかの理由でテストを自動化できていないロジック(たとえば、テストを書きづらい複雑なドラッグアンドドロップ機能など)は、手動テストを忘れずに行ってください。
最後に、もう一度
bundle updated
を実行して、ほぼすべてのgemが最新バージョンにアップデートされたことを確認します。
(gemをひとつ残らず最新にするのは無理だと思うので、そこにはこだわらないようにしましょう)コラム:gemは普段からこまめにバージョンアップしよう
gemのバージョンアップ作業は実際にやってみると、かなり骨が折れると思います。
古いバージョンのgemが多ければ多いほど、この作業のしんどさが増えるので、日頃からこまめにgemを最新版にアップデートしていくことをお勧めします。また、そもそもの話ですが、Gemfileに記述するgemを増やしすぎない(=gemを追加するときは、その必要性を慎重に吟味する)ということも大事だと思います。
5. Rubyのバージョンを最新にする
Railsアプリで使用しているRubyのバージョンが古い場合は、このタイミングで最新にしておくと良いかもしれません。
Rubyは後方互換性をかなり重視しているので、バージョンを上げてもトラブルが起きる可能性は低いはずです。
ですが、それでもゼロとは言えないので、Rubyのバージョンを上げたらテストがすべてパスすることを確認してください。# rbenvで最新のRubyを使うようにする # (rbenvとRuby 2.6.3のインストールはすでに終わっている前提) rbenv local 2.6.3 # gemを再インストール bundle install # テストがパスすることを確認 bundle exec rspecなお、新しいRailsは古いバージョンのRubyでは実行できません。
たとえばRails 6はRuby 2.5.0以上が必須です。バージョンごとのRailsとRubyの対応関係はRailsガイドを参照してください。
6. Railsを最新のパッチバージョンに上げる
Railsのマイナーバージョン、またはメジャーバージョンを上げる前に、パッチバージョンを最新に上げます。
たとえば、Rails 5.2.1をRails 6.0に上げる前に、Rails 5.2.3に上げる、という感じです(Rails 5.2.3は本記事執筆時点でのRails 5.2系の最新バージョン)。Gemfile# Railsのパッチバージョンを最新まで上げる -gem 'rails', '5.2.1' +gem 'rails', '5.2.3'bundle update rails
パッチバージョンを上げたら、テストがすべてパスすることを確認します。
テストの実行中に警告メッセージが出ていたら、この時点で警告をなくす修正を行います。なお、Railsのバージョン履歴は、rubygems.orgで確認できます。
https://rubygems.org/gems/rails/versions
7. Railsのメジャーバージョン、またはマイナーバージョンを上げる
さて、いよいよRailsのバージョンを上げるときがやってきました。
周辺のgemが最新版になっていれば、比較的すんなりbundle update
が完了するはずです。Gemfile# Railsのメジャーバージョンを上げる -gem 'rails', '5.2.3' +gem 'rails', '6.0.0'# 新しいバージョンのRailsをインストール bundle updateただし、バージョンを上げる際は間のバージョンをスキップせずに、1つずつアップグレードしてください。(例:5.0から6.0ではなく、5.1、5.2、6.0と順にアップグレードする)
また、上の例では"6.0.0"になっていますが(本記事執筆時点では6.0.0が最新であるため)、0より新しいパッチバージョンが出ていれば最新のパッチバージョンを指定します。
Gemfile# 0より新しいパッチバージョンが出ていれば最新のパッチバージョンを指定する gem 'rails', '6.0.2'
bundle update
が終わっても今回はまだテストを実行せず、先に以下の作業を行います。8. rails app:updateタスクを実行する
次に
rails app:update
タスクを実行します。
このタスクを実行すると、新しいバージョンで必要になる新しいファイル作成や、既存ファイルの変更を対話形式で行うことができます。# 実行例は https://railsguides.jp/upgrading_ruby_on_rails.html より引用 $ rails app:update identical config/boot.rb exist config conflict config/routes.rb Overwrite /myapp/config/routes.rb? (enter "h" for help) [Ynaqdh] force config/routes.rb conflict config/application.rb Overwrite /myapp/config/application.rb? (enter "h" for help) [Ynaqdh] force config/application.rb conflict config/environment.rb ...上書き更新されるファイルは次のように対応方法を質問されるので、 Y/n/a/q/d/hのいずれかのキーを入力します。
Overwrite /myapp/config/application.rb? (enter "h" for help) [Ynaqdh]
各キーの意味は次の通りです。
Y - Yes。上書き実行 n - No。上書きしない a - All。このファイル以降の全ファイルを上書き q - Quit。処理中断 d - Diff。新旧ファイルのdiffを表示 h - Help。入力する各キーの意味を表示
僕は
d
= diffを確認した上で、Yかnを入力することが多いです。
(でも、routes.rb以外はほとんどYを入力しているかもしれない)必要に応じて上書きされた設定を元に戻す
Yで上書き実行すると、それまで使っていた重要な設定が失わることがあります。
その場合はgitのdiffをチェックしながら、上書きされて消えてしまった設定を自力で戻していきます。config/environments/production.rb# 例:上書き更新でコメントアウトされたforce_sslの設定を元に戻す -# config.force_ssl = true +config.force_ssl = trueちなみにRubyMineを使うと、GUI上で視覚的にdiffの確認とコードの修正(ロールバック)ができるのでとても便利です。
rails app:update後に上書きされたproduction.rbの設定を、RubyMineを使って一部だけ元に戻す動画です。こんな感じでGUI上でポチポチ元に戻していけるので、とっても便利〜✨ pic.twitter.com/f0qrUewJHh
— Junichi Ito (伊藤淳一) (@jnchito) August 19, 20199. railsdiff.orgを参考にして、新しく追加されたgem等を確認する
app:update
コマンドを実行しても、Gemfileのようにまったく更新されないファイルもあります。
ですが、rails new
した直後のGemfileを比較すると、デフォルトでインストールされるgemの種類やバージョンには違いがあります。
Railsのバージョンを上げたのであれば、こういった部分も新しいRailsに合わせておく方が安心です。そういうときに便利なのが http://railsdiff.org です。
このサイトではRailsの各バージョンごとに、rails newした直後のファイルのdiffを確認することができます。たとえば以下のURLを開くとRails5.1.7と5.2.3のdiffを確認できます。
http://railsdiff.org/5.1.7/5.2.3
Gemfileを見るとbootsnapのような新しいgemがいくつか追加されているので、この情報を見ながら自力で差分を埋めていきます。
Gemfile# 例:Rails 5.2からはGemfileにbootsnap gemが追加されているので、自分のアプリにもbootsnapを追加しておく +# Reduces boot times through caching; required in config/boot.rb +gem 'bootsnap', '>= 1.1.0', require: false
他のファイルに対しても、必要に応じて自力で差分を埋めていきましょう。
10. 動作確認を行う
そろそろ新しいバージョンのRailsを起動する準備が整いました。
ですが、いきなりテストを動かしても意味不明なエラーが出て面食らうこともよくあります。
なので、僕は次のような順番で動作確認を行います。10-a. rails cが起動するか?
最初は
rails c
(rails console
)が起動することを確認します。
この時点でエラーが出て起動に失敗する場合は、エラーメッセージをよく読んでエラーを修正します。rails consoleが起動し、
User.count
のような簡単なコードが実行できればOKです。10-b. rails sが起動するか?
次は
rails s
(rails server
)が起動することを確認します。
サーバーの立ち上げ時や、サイトアクセス時にエラーが発生する場合は、エラーメッセージをよく読んでエラーを修正します。画面のデザイン崩れがなく、いくつかの画面が正常に開くようになればOKです。
10-c. 全部テストがパスするか?警告も出ないか?
ここまでくればテストコードも問題なく実行できるはずなので、テストを実行してみましょう。
パスしなかったテストがあれば、原因を調べて修正してください。
また、テストはパスしていても、ターミナルに警告文が表示されていることもよくあります。
"DEPRECATION WARNING"のような文字が出力されていないか、テスト実行後のターミナルを確認してください。警告文には警告の原因やコードの修正方法、詳細な説明ページのURL、警告が発生したコード行等が載っていることも多いので、英語が苦手な人もまずは英文をじっくり読むことが解決への近道になります。
10-d. load_defaultsやnew_framework_defaults_x_x.rbを設定する
Railsのバージョンが上がると、従来の挙動とは異なる、新しい挙動が導入される場合があります。
バージョンアップ後はすべて新しい挙動に合わせられるのが理想的ですが、場合によっては一部の挙動を古いRailsに合わせないといけないかもしれません。こうした挙動の変更は
load_defaults
やnew_framework_defaults_x_x.rb
で行います。
load_defaults
とnew_framework_defaults_x_x.rb
の関係については以下の記事で詳しく説明しているので、こちらを読んで適切に設定を変更してください。config.load_defaultsとnew_framework_defaults_x_x.rbの関係を詳しく調べてみた - Qiita
10-e. 自分の手と目でテストする
自動テストが全部パスしていても100%安心はできません。
テストはパスしていても微妙に画面の表示が崩れているケースもあるので、自分の手と目でも動作確認しておきましょう。また、画面のデザイン崩れだけでなく、自動テストで担保できていない複雑な機能も手動でテストする必要があります。
この作業が完了すれば、ローカル環境での動作確認はおしまいです。
11. ステージング環境にデプロイして動作確認する
次に、ステージング環境(本番環境と同じ構成のテスト環境)にRailsアプリをデプロイします。
ローカルではちゃんと動いていても、デプロイしたらサーバーの起動に失敗した、なんていうこともたまにあります。
その場合はエラーログを見ながら、問題を修正してください。ステージング環境でアプリケーションが動き始めたら、手動テストを行います。
Amazon S3へのファイル保存や外部APIとの連携機能など、ローカル環境では動作確認しづらい機能があれば、必ずここで動作確認しておきます。動作確認は1日で終わらせるのではなく、できれば数日間動かしてみて、何か問題が起きないか確認する方が望ましいです。
12. プルリクエストを作成し、コードレビューしてもらう
ステージング環境でも動作確認ができたら、本番リリースに向けてプルリクエストを作成し、他のメンバーにコードレビューしてもらいましょう。
もしかすると、コードの修正漏れを指摘されたり、経験者ならではのアドバイスをもらえたりするかもしれません。
13. 本番環境にデプロイして動作確認する
いよいよ最後のステップです。
プルリクエストをマージし、バージョンアップしたRailsアプリを本番環境にデプロイします。ステージング環境と本番環境がまったく同じ構成であればトラブルが発生する可能性は低いですが、念のため、可能な範囲で手動テストしておきましょう。
バージョンを上げたことに起因するトラブルが突然起きる可能性もあるので、リリース後、数日間はログやサーバーのリソース状況等を注意して監視してください。
まとめ
お疲れ様でした。Railsアプリケーションをアップグレードする手順は以上になります。
アップグレード作業の大変さ(作業開始から完了までにかかる工数)は、アプリケーションの規模やテストのカバレッジ率、gemのアップデートをサボっていた期間の長さ等によって大きく変わってきます。
ですが、運用を続ける限りは「大変そうだから、アップグレードを見送る」という選択肢はまずありません。
技術的負債が雪だるま式に膨らむ前に、早め早めにバージョンを上げていきましょう!宣伝:テストが苦手な方は「Everyday Rails - RSpecによるRailsテスト入門」をどうぞ!
この手順を最後まで読まれた方はよくわかると思いますが、Railsのアップグレード作業には自動テストが必要不可欠です。
「テストを書くのが苦手」「どうやってテストを書けばいいのかわからない」という方はぜひ、僕が翻訳した電子書籍「Everyday Rails - RSpecによるRailsテスト入門」を読んでみてください。
RSpecや自動テストは初めて、という方でもわかるよう、Railsアプリケーションのテストの書き方を詳しく、丁寧に説明します。「Everyday Rails - RSpecによるRailsテスト入門」は、以下のLeanpubのサイトから購入可能です。