- 投稿日:2020-06-19T20:59:39+09:00
【Rails】ancestryを用いた多階層カテゴリー機能の実装『seed編』
開発環境
・Ruby: 2.5.7
・Rails: 5.2.4
・Vagrant: 2.2.7
・VirtualBox: 6.1
・OS: macOS Catalina前提
下記実装済み。
・投稿機能実装
・多対多のカテゴリー機能実装
・多階層カテゴリー機能実装(準備編)実装
id name ancestry 1 ビジネス nil 2 金融 1 3 株 1/2 4 為替 1/2 5 税金 1/2 6 経済 2 7 日本経済 1/6 8 国際経済 1/6 9 経営 3 10 経営学 1/9 11 戦略・攻略 1/9 12 企業・開業 1/9 13 マーケティング 4 14 経営学 1/13 15 戦略・攻略 1/13 16 企業・開業 1/13 本のカテゴリーに上記の様な親子関係を持たせたい場合は、以下の様にデータを作成します。
seed.rbbusiness = Category.create(name: 'ビジネス') business_child_array = ['金融', '経済', '経営', 'マーケティング'] business_grandchild_array = [ ['株', '為替', '税金'], # 金融の子 ['日本経済', '国際経済'], # 経済の子 ['経営学', '戦略・管理', '起業・開業'], # 経営の子 ['広告', '営業', '開発'] # マーケティングの子 ] business_child_array.each_with_index do |child, i| child = business.children.create(name: child) business_grandchild_array[i].each do |grandchild| child.children.create(name: grandchild) end end
- 投稿日:2020-06-19T20:45:07+09:00
既読・未読判定機能の実装
既読・未読機能の実装方法
まず、簡単なブログ機能のあるrailsアプリがあるとします。
このアプリのブログ詳細画面に遷移した際に、既読となるような仕様で実装していきたいと思います。
※既読/未読機能を実装するために必要なコードのみ載せています。ER図
テーブル
- user
- blog
- read
既読機能を実装するにあたって、userテーブルとblogテーブルの中間テーブルが必要になります。
そこで、readテーブルを作成しました。readテーブルのカラム
- user_id
- blog_id
- complete(boolean型)
completeカラムをboolean型とし、既読/未読を真偽値で取得するようにしました。
モデル
user.rbclass User < ApplicationRecord has_many :blogs has_many :reads, dependent: :destroy endblog.rbclass Blog < ApplicationRecord belongs_to :user has_many :reads, dependent: :destroy endread.rbclass Read < ApplicationRecord belongs_to :user belongs_to :blog endコントローラーの設定
blogs_controllerclass BlogsController < ApplicationController def show @read = current_user.reads.update(complete: true) endshowメソッドに、「現在ログインしているユーザーがブログ詳細画面に飛んだら、既読になる。」という記述をし、@readに格納します。
complete: true = '既読'ビューの設定
show.html.erb<%= @read ? '既読' : '未読' %>「@read ? '既読' : '未読'」 は、
三項演算子という記法で、「?」の前の記述(@read)が、
true(真)であれば:の左側の処理を実行('既読'という文字列の出力を実行)し、
false(偽)であれば:の右側の処理を実行('未読'という文字列の出力を実行)します。以上のようにコードを記述してくと、ブログ詳細画面に遷移した際に
このように「既読」という文字列を出力できるようになります。
- 投稿日:2020-06-19T20:36:44+09:00
Rails 値を正規化する
値の正規化
ある規則に従うように情報を変換することを正規かと言います。
今回はフリガナとして入力された値が平仮名だった場合に正規化して
カタカナにするという正規化を行ってみます。まずapp/models/concernsディレクトリにnormalizerを作成していきます。
string_normalizer.rbrequire "nkf" module StringNormalizer def normalize_as_furigana(text) NKF.nkf("-W -w -Z1 --katakana", text).strip if text end以下のコードが実際に正規化を行っています。
NKF.nkf("-W -w -Z1 --katakana", text).strip if text指定される引数は以下のような意味です。
NKF#nkfメソッドの引数
フラグ 意味 -W 入力の文字コードがUTF-8 -w UTF-8で出力 -Z1 全角の英数字、記号、半角スペースを半角に変える --katakana ひらがなをカタカナに変換 これで準備ができました。あとはモデル側でモジュールを組み込みましょう
model.rbclass UserController < ApplicationRecord include StringNormalizer before_validation do self.name_kana = normalize_as_furigana(name_kana) endこんな感じでバリデーションを通す前にname_kanaで指定された属性を
ひらがな-> カタカナへ正規化することができました。本日は以上です!!
- 投稿日:2020-06-19T20:20:45+09:00
【Rails】ancestryを用いた多階層カテゴリー機能の実装『準備編』
開発環境
・Ruby: 2.5.7
・Rails: 5.2.4
・Vagrant: 2.2.7
・VirtualBox: 6.1
・OS: macOS Catalina前提
下記実装済み。
実装
1.Gemを導入
Gemfile# 追記 gem 'ancestry'ターミナル$ bundle2.カラムを追加
データ量がかなり多くなるので
indexを張ります。ターミナル$ rails g migration AddAncestryToCategory ancestry:string:indexターミナル$ rails db:migrateschema.rbcreate_table "categories", force: :cascade do |t| t.string "name" t.datetime "created_at", null: false t.datetime "updated_at", null: false t.string "ancestry" t.index ["ancestry"], name: "index_categories_on_ancestry" end3.モデルを編集
category.rb# 追記 has_ancestry
has_ancestry
➡︎ ancestryを使える様になる。メソッド一覧
メソッド名 返り値 parent 親レコードを取得 parent_id 親レコードのIDを取得 root レコードのルートを取得 root_id レコードのルートIDを取得 root?is_root? レコードがルートであれば、trueを返す ancestors ルートで始まり、親で終わる、レコードの祖先を返す ancestors? レコードに祖先(ルートノードではない)がある場合はtrueを返す ancestor_ids レコードの祖先のIDを返す path ルートで始まり、自己で終わる、レコードのパスを返す path_ids ルートIDで始まり、 自己のIDで終わるパスのIDをリストで返す children 子レコードを取得 child_ids 子レコードのIDを取得 has_parent?ancestors? レコードが親を持っていれば、trueを返す has_children?children? レコードが子を持っていれば、trueを返す is_childless?childless? レコードが子を持っていなければ、trueを返す siblings 兄弟レコード(同じ階層のレコード)を返す sibling_ids 兄弟レコード(同じ階層のレコード)のIDを返す has_siblings?siblings? レコードの親に複数の子がある場合はtrueを返す is_only_child?only_child? レコードが親の唯一の子である場合はtrueを返す descendants 子レコード、孫レコード、曽孫レコード... を返す descendant_ids 子レコード、孫レコード、曽孫レコード... のIDを返す indirects 孫レコード以下を返す indirect_ids 孫レコード以下のIDを返す subtree 子孫と自己のモデルを返す subtree_ids レコードのサブツリーのIDをリストで返す depth ノードの深さを返す parent_of?(node) このレコードを(node)の親にする root_of?(node) このレコードを(node)のルートにする ancestor_of?(node) (node)の祖先にはこのレコードが含まれる child_of?(node) (node)はレコードの親 descendant_of?(node) (node)はこのレコードの祖先の1つ indirect_of?(node) (node)はこのレコードの祖先の1つですが、親ではない 階層構造
親:ビジネス
子:経済
孫:日本経済、国際経済本のカテゴリーに上記の様な親子関係を持たせたい場合は、以下の様にデータを作成します。
business = Category.create(name: 'ビジネス') business_economy = business.children.create(name: '経済') business_economy.children.create([{ name: '日本経済' }, { name: '国際経済' }])カラム構造
id name ancestry 1 ビジネス nil 2 経済 1(親のid) 3 日本経済 1/2(親のid/子のid) 4 国際経済 1/2(親のid/子のid)
- 投稿日:2020-06-19T19:37:19+09:00
【enum】 rails enumを利用してデータの可読性をあげよう
【ゴール】
rails においてenumの使用
【メリット】
■ dbの可読性向上、管理しやすい
■ 日本語化にも応用が効く【開発環境】
■ Mac OS catalina
■ Ruby on Rails (5.2.4.2)
■ Virtual Box:6.1
■ Vagrant: 2.2.7【実装】
と言ってもとても簡単!!!!対象のモデルに追記するのみ
※①が一番簡単な書き方
※②だと日本語も可能model/hoge.rb① enum カラム名:[:任意の単語, :任意の単語, :任意の単語, :任意の単語] ② enum カラム名:{"任意の単語": 1,"任意の単語": 2.......}※number_field をselectに変更する
※enumで設定した値を取得して、選択できるようになります。hoge/_form.html.erb<%= form.select :カラム名, モデル名.カラム名s.keys, :selected=>モデル名.カラム名s[カラム名] %>以上
【合わせて読みたい】
■enumについて
https://web-camp.io/magazine/archives/16862■form_withについて
https://qiita.com/tanaka-yu3/items/50f54f5d4f4b8dfe19f3
- 投稿日:2020-06-19T16:57:45+09:00
Rails6でのcocoon
スクールではrails5で開発を行ってcocoonを使っていて、。同じ方法でrails6でも親子関係のテーブルに複数画像データを保存しようとしたら、追加ボタンが作動しなかった。備忘録として投稿
参考URL
https://www.botreetechnologies.com/blog/introducing-jquery-in-rails-6-using-webpacker
原因
そもそもcocooonとjqueryの導入の仕方が変わっていました。
rails5では以下のように実装をした
1.gemのインストール
Gemfile.gem 'cocoon' gem 'jquery-rails' #画像投稿するためにrefileを使用 gem 'refile', require: 'refile/rails', github: 'manfe/refile' gem 'refile-mini_magick'2.app/assets/javascripts/application.js
application.js//= require cocoon //= require jquery2.親子関係を結びつける
tour.rbhas_many :tour_photos, dependent: :destroy accepts_nested_attributes_for :tour_photos, allow_destroy: true・accepts_nested_attributes_for
一度にまとめてレコードの更新ができるようにできるメソッド。今回の場合だと、Tourレコードを更新すると同時にTourPhotoレコードも一緒に更新できる
・allow_destroy: true
accepts_nested_attributes_forで関連づけられた子レコードを削除できるようにする
tour_photo.rbbelongs_to :tour attachment :image validates :image, presence: true2.フォームを作成
new.html.erb<%= f.fields_for :tour_photos do |tour_photo| %> <%= f.label "写真(5枚選んでください)" %> <%= render 'tour_photo_fields', f: tour_photo %> <% end %> <div id = "links"> <%= link_to_add_association '写真を追加',f, :tour_photos %> </div>_tour_photo_fields.html.erb<div class = "nested-fields"> <%= f.attachment_field :image %> <%= link_to_remove_association "写真を削除", f, class: "btn btn-danger remove-photo-btn photo-btn" %> </div>以上のようにrails6で同じようにやると、cocoonの追加ボタンが反応してくれなかった
rails6でcocoonを使えるようにするために。
jqueryの導入
yarn add jquery・config/webpack/environment.jsの編集
environment.jsconst { environment } = require('@rails/webpacker') #追記ここから const webpack = require('webpack') environment.plugins.prepend('Provide', new webpack.ProvidePlugin({ $: 'jquery/src/jquery', jQuery: 'jquery/src/jquery' }) ) #追記ここまで module.exports = environmentcocoonの導入
yarn add github:nathanvda/cocoon#c24ba53上記のコマンドでpackage.jsonに以下が追加されていれば、導入できている。
package.json"cocoon": "github:nathanvda/cocoon#c24ba53",最後にapp/javascriptspacks/application.jsに追記
application.jsrequire('jquery') import "cocoon";まとめ
初めてバージョンの違うrailsを触りましたが、できてたことができなかったりするんですね。
あと、application.jsのファイルの場所が変わっていて、最初は亡くなったのかとビビリ散らかしました。Rails6でwebpackerが標準になったことにより、Railsアプリの開発環境にyarnのインストールが必要になってるみたいのでお気をつけください。
webpackerとはRailsでモダンなJSフレームワークなどを利用するためのものみたいです。これについても勉強しなければ。
- 投稿日:2020-06-19T16:41:43+09:00
payjpを使って購入機能を実装でい!!
こんにちは。
今日は雨ですね。
偏頭痛持ちの方は気をつけてください。毎年傘を10本無くす私が言うのは全然説得力が無いと思うのですが、
傘は忘れない様に!!!
さぁ今回はpayjpを使って購入機能を実装するわよ。
(フリマアプリを作成中デスゥ)payjp導入編もあるので見てない方は先にそちらをチェケラッ
payjp導入編
クレジットカード登録編
ビューなどの補足編1 まずはルーティングを決めます。
この購入機能をどのコントローラーに入れるかですわねぇ。
色んな記事を読む限り・商品コントローラーに入れる
・カードコントローラーに入れる
・購入コントローラーを新しく作るアタイ的には商品テーブルに購入者、購入された時間のカラムを入れているので商品コントローラーの中に入れることにしました。
ですが既存のアクションじゃできないっ!!
なのでこんな感じでルーティングを作りましたわ。routes.rbresources :items, only: [:index, :new, :show, :create, :destroy] do member do get 'purchase'=> 'items#purchase', as: 'purchase' patch 'pay'=> 'items#pay', as: 'pay' get 'done'=> 'items#done', as: 'done' endなぜmemberにしたかって言うと商品のidが欲しいから。
流れとしては商品詳細ページ→商品購入ページ→購入アクション→購入完了しましたページ
2 次はコントローラージャイ
商品詳細はいらんからmemberで定義したアクションのみ書いていくわよ!!
items_controller.rbdef purchase @item = Item.find(params[:id]) @card = Card.find_by(user_id: current_user.id) if @card == nil redirect_to new_card_path flash[:noCard] = "Cardが登録されていませんので登録してください" else Payjp.api_key = Rails.application.credentials[:payjp][:PAYJP_PRIVATE_KEY] customer = Payjp::Customer.retrieve(@card.customer_id) @card_information = customer.cards.retrieve(@card.card_id) # 購入確認ページでカード情報出したいからここで取得。 # 画像無い人はなくても良いかも。 @card_brand = @card_information.brand case @card_brand when "Visa" @card_src = "if-visa-2593666_86609.svg" when "JCB" @card_src = "jcbcard.png" when "MasterCard" @card_src = "mastercard.png" when "American Express" @card_src = "americancard.png" when "Diners Club" @card_src = "diners_club.png" when "Discover" @card_src = "discover.png" end # --------------------------------------------------------------- end end def pay @item = Item.find(params[:id]) card = Card.find_by(user_id: current_user.id) Payjp.api_key = Rails.application.credentials[:payjp][:PAYJP_PRIVATE_KEY] Payjp::Charge.create( amount: @item.price, # Payjpに載る金額 customer: card.customer_id, # 顧客ID currency: 'jpy' ) @item.update(buyer: current_user.id) require 'date' @item.update(bought_at: Time.now ) # アタイは購入時間を入れているからここもいらん人はなくてよし redirect_to done_item_path(@item.id) flash[:notice] = "購入が完了しました" end def done endこんな感じだわよ。
3 一応ビューファイルも
purchase.html.haml.purchaseBackground = render 'layouts/global-header-simple' %main.purchaseMain %h2.purchaseMain__content.purchaseTitle 購入内容の確認 = form_with model: @item, local: true do |f| .purchaseMain__content.purchaseItem .purchaseItem__imageArea = image_tag asset_path('curry.png'), class: 'purchaseItem__imageArea--image', alt: '購入アイテム画像' .purchaseItem__box %p = @item.name .purchaseItem__box--price %span = @item.price 円 %span.shipping-fee (税込) 送料込み %section.purchaseMain__content .purchaseMain__content__wrapper .purchaseMain__content__wrapper__price .purchaseMain__content__wrapper__price--label 支払い金額 .purchaseMain__content__wrapper__price--value = @item.price 円 .purchaseMain__content__wrapper .purchaseMain__content__wrapper__payMethod .purchaseMain__content__wrapper__payMethod--label 支払い方法 = link_to card_path(@card.id), class: 'changeBtn' do 変更する %p.user-card-info クレジットカード = "**** **** **** " + @card_information.last4 %p.user-card-info 有効期限 - exp_month = @card_information.exp_month.to_s - exp_year = @card_information.exp_year.to_s.slice(2,3) = exp_month + " / " + exp_year %figure.user-card-logo = image_tag "#{@card_src}",width:'34',height:'20', alt:'master-card' .purchaseMain__content__wrapper .purchaseMain__content__wrapper__delivery .purchaseMain__content__wrapper__delivery--label 配送先 = link_to '#', class: 'changeBtn' do 変更する %p.user-address-info .purchaseMain__content__wrapper %p.purchase-info 郵便局/コンビニ受取をご希望の方は、購入後に<strong>取引画面</strong>から受取場所を変更をすることが可能です。出品者が発送作業を開始した後は受取場所の変更ができませんので、早めに変更を行ってください。 .btn-enter = link_to pay_item_path(@item.id), method: :patch do .purchase-btn 購入する = render 'layouts/global-footer-simple'これでフリマアプリで買い放題だZE!!!
クレジット機能に関してはこんなもんですかね。
- 投稿日:2020-06-19T16:24:55+09:00
[Rails]logフォーマットを自分好みに変更する
前提
- ruby: 2.7.1
- Rails: 6.0.3
自分好みの Formatter を定義する
config/logger_my_formatter.rbclass Logger class MyFormatter < Formatter def call(severity, time, progname, msg) "[%s#%d] %5s -- %s: %s\n" % [format_datetime(time), $$, severity, progname, msg] end end end自分好みの Formatter を指定する
config/application.rbrequire_relative 'boot' require_relative 'logger_my_formatter' # 追記 # ...動作確認は
productionモードで行います(developmentモードはActiveSupport::Logger::SimpleFormatter)。config/environments/production.rbRails.application.configure do # ... config.log_formatter = ::Logger::MyFormatter.new # 追記 end動作確認
デフォルト
I, [2020-06-19T16:16:21.592424 #4688] INFO -- : [e8b5388b-e8d9-4a31-a350-1f3cafdd0dda] Completed 200 OK in 224ms (Views: 102.2ms | ActiveRecord: 40.3ms | Allocations: 65613)
変更後
[2020-06-19T16:21:53.497691 #5177] INFO -- : [d8ef0edd-4d3b-4618-bba7-050a185fa30b] Completed 200 OK in 12ms (Views: 6.3ms | ActiveRecord: 2.5ms | Allocations: 5132)
- 投稿日:2020-06-19T12:19:56+09:00
AWS☆☆☆ デプロイまでの道のり3(短いバージョン、全5回)
1)背景
第3回目です。自身のポートフォリオをデプロイするために、いよいよunicornを介してrailsを起動します。
AWS関連手順記事はすごく多いので、ここでは備忘録も含めて、非常に端的に手順を記載します。
全5話で進めます。2)環境
項目 内容 OS.Amazon Linux AMI release 2018.03 Ruby v2.5.1 Ruby On Rails v5.2.4.3 MySQL v5.6 Unicorn v5.4.1 3)内容
以下設定で75分程度かなと思います。(段取りが分かっていれば、30分)
※【ローカルマシン】指定以外は、全てAWSでの作業になります。(1)【ローカルマシン】Unicornの設定(20分)
- Gemfileにunicornを記述
- bundle installの実行(ユニコーン導入)
- 作成された設定ファイル(unicorn.rb)の編集
(2)Gitのクローニング(15分)
- 格納フォルダの配置と権限付与
- Gitからのクローニング(※)
- AWSのswap領域作成(別記事をご参照ください)
※クローニングする際には以下が必要です。
(1)先ほどのローカルunicorn設定がpushされていること
(2)最新master化
(3)本番環境(production)のDBユーザ設定(3)本番デプロイ設定(30分)
- bundlerのインストール
- bundle installの実行(時間がかかります。)
- 秘密鍵の取得
- 環境変数にdbユーザパスワード(productionと合わせる)と秘密鍵を設定する
- DB-CreateとDB-Migrateの実行
- assetsディレクトリのプレコンパイル
(4)本番Rails起動(10分)
- インスタンスの3000番ポート開放
- unicornを介してサービスの起動
ここまで完了したら、「http://ElasticIP:3000」にアクセスすると、アプリケーションのトップページに遷移するはずです。
以上、短く記載しました。
ここまで、全てストレートに行ったわけではなく、エラーも出力されました。この辺りは、環境や設定により様々ですので、別記事にてエラー対策を掲載したいと思います。
- 投稿日:2020-06-19T11:10:56+09:00
FinderのデフォルトテキストエディタをAtomに変更する方法
- 投稿日:2020-06-19T01:30:28+09:00
【後編】「Everyday Rails - RSpecによるRailsテスト入門」を Rails 6 で勉強したいので伊藤さんのブログを参考にして頑張ってみた
はじめに
この記事は、タイトルのとおり、「Everyday Rails」を Rails 6 で勉強したいので、
書籍の翻訳者である伊藤さんのブログを参考にして頑張ってみた記録を記したものである。記事自体が長くなったので、導入編・前編・中編・後編に分割している。
Rails 6 へのアップグレードは非常に時間がかかるので、いきなり挑戦するのではなく、
まず導入編を読んでいただき、本当に挑戦するのか検討することを強く勧めます。記録を見たい方は、以下を参照すること。
【導入編】「Everyday Rails - RSpecによるRailsテスト入門」を Rails 6 で勉強したいので伊藤さんのブログを参考にして頑張ってみた - Qiita
【前編】「Everyday Rails - RSpecによるRailsテスト入門」を Rails 6 で勉強したいので伊藤さんのブログを参考にして頑張ってみた - Qiita
【中編】「Everyday Rails - RSpecによるRailsテスト入門」を Rails 6 で勉強したいので伊藤さんのブログを参考にして頑張ってみた - Qiitaまた、本記事は、伊藤さんのyoutube動画を見ながら作業した内容の実況中継に
近いような形で書き進めているので、以下を必ず併せて視聴してください。
(youtube動画を視聴している前提で書いているので、この記事単体だと意味が通じない)【前編】永久保存版!?伊藤さん式・Railsアプリのアップグレード手順(youtube動画)
【後編】永久保存版!?伊藤さん式・Railsアプリのアップグレード手順(youtube動画)振り返り
Railsのバージョンを5.2.7までアップグレードした。
続いて、Railsのバージョンを6.0.0に上げていく。なお、本人はバージョンを6.0.0に上げているつもりだが、指定しきれていないので、
結果として6.0.3.1にバージョンアップされている。また、この記事は以下の伊藤さんの記事と連動するような形で章立てしている。
その記事内での5番までの作業は不要になるため、次の章は6番からスタートする。6. Railsを最新のパッチバージョンに上げる
さて、Railsの
Gemfileを開き、Railsのバージョンを6.00に上げる。
現在では、6.0.3.1が最新版だが、怖いので、とりあえず6.00に上げる。gem 'rails', '~> 6.0.0'
Gemfileを変更した後、bundle updateを行う。7. Railsのメジャーバージョン、またはマイナーバージョンを上げる
やらないつもりだったが、しれっとやっているという。。。
8. rails app:updateを実行する
ターミナルで
rails app:updateを実行する。前回と同様に、routes.rbだけ上書きをせず、
nと回答する。
そのほかは、yと回答する。必要に応じて上書きされた設定を元に戻す
Yで上書き実行すると、それまで使っていた重要な設定が失わることがあります。
その場合はgitのdiffをチェックしながら、上書きされて消えてしまった設定を自力で戻していきます。Rails5.2のバージョンアップの時と同様に対応する。
以下のファイルを変更した。config/application.rb〜 省略 〜 module Projects class Application < Rails::Application # Initialize configuration defaults for originally generated Rails version. config.load_defaults 5.2 # Settings in config/environments/* take precedence over those specified here. # Application configuration can go into files in config/initializers # -- all .rb files in that directory are automatically loaded after loading # the framework and any gems in your application. # 以下が消えていたので、戻した。 config.generators do |g| g.test_framework :rspec, view_specs: false, helper_specs: false, routing_specs: false end end endconfig/environments/test.rb# 以下のコードを最後に追加する # Keep files uploaded in tests from polluting the Rails development # environment's file uploads Paperclip::Attachment.default_options[:path] = \ "#{Rails.root}/spec/test_uploads/:class/:id_partition/:style.:extension"9. railsdiff.orgを参考にして、新しく追加されたgem等を確認する
次に以下を開き、差分を更新していく。
アプリのことをよく分かっており、かつ勘所がないと困難なので、
伊藤さんの動画の指示に従っていく。以下のファイルを変更した。
Gemfilesource 'https://rubygems.org' git_source(:github) { |repo| "https://github.com/#{repo}.git" } ruby '2.7.1' gem 'rails', '~> 6.0.0' gem 'sqlite3', '~> 1.4' # 更新 gem 'puma', '~> 3.11' gem 'sass-rails', '~> 5' # 更新 gem 'uglifier', '>= 1.3.0' gem 'coffee-rails', '~> 4.2' gem 'turbolinks', '~> 5' gem 'jbuilder', '~> 2.7' # 更新 gem 'bootsnap', '>= 1.4.2', require: false # 更新 〜 以下省略 〜config/application.rbmodule Projects class Application < Rails::Application # Initialize configuration defaults for originally generated Rails version. config.load_defaults 6.0 # ここを6.0に変更 # Settings in config/environments/* take precedence over those specified here. # Application configuration can go into files in config/initializers # -- all .rb files in that directory are automatically loaded after loading # the framework and any gems in your application. config.generators do |g| g.test_framework :rspec, view_specs: false, helper_specs: false, routing_specs: false end end end
Gemfileを反映させるため、bundle updateを実行する。
無事、成功した。10. 動作確認を行う
rails cについては、成功した。
rails sについては、動画のとおりrails db:migrateを実行すると、
無事起動することができた。挙動も問題なさそうだった。
bin/rspecを実行し、テストに失敗がないか確認する。
以下のFailuresが発生した。Failures: 1) TasksController#show responds with JSON formatted output Failure/Error: expect(response).to have_content_type :json Expected "unknown content type (application/json; charset=utf-8)" to be Content Type "application/json" (json) # ./spec/controllers/tasks_controller_spec.rb:11:in `block (3 levels) in <main>' # /Users/kentasuedomi/.rbenv/gems/2.7.0/gems/bootsnap-1.4.6/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:55:in `load' # /Users/kentasuedomi/.rbenv/gems/2.7.0/gems/bootsnap-1.4.6/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:55:in `load' # /Users/kentasuedomi/.rbenv/gems/2.7.0/gems/spring-commands-rspec-1.0.4/lib/spring/commands/rspec.rb:18:in `call' # -e:1:in `<main>' 2) TasksController#create responds with JSON formatted output Failure/Error: expect(response).to have_content_type :json Expected "unknown content type (application/json; charset=utf-8)" to be Content Type "application/json" (json) # ./spec/controllers/tasks_controller_spec.rb:21:in `block (3 levels) in <main>' # /Users/kentasuedomi/.rbenv/gems/2.7.0/gems/bootsnap-1.4.6/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:55:in `load' # /Users/kentasuedomi/.rbenv/gems/2.7.0/gems/bootsnap-1.4.6/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:55:in `load' # /Users/kentasuedomi/.rbenv/gems/2.7.0/gems/spring-commands-rspec-1.0.4/lib/spring/commands/rspec.rb:18:in `call' # -e:1:in `<main>' Finished in 56.81 seconds (files took 2.96 seconds to load) 70 examples, 2 failures動画によると、RSpecの書き方が変わったらしい。
expectで始まるコードを修正する。spec/controllers/tasks_controllers/tasks_controller_spec.rbrequire 'rails_helper' RSpec.describe TasksController, type: :controller do include_context "project setup" describe "#show" do it "responds with JSON formatted output" do sign_in user get :show, format: :json, params: { project_id: project.id, id: task.id } expect(response.content_type).to eq "application/json; charset=utf-8" # ここを修正 end end describe "#create" do it "responds with JSON formatted output" do new_task = { name: "New test task" } sign_in user post :create, format: :json, params: { project_id: project.id, task: new_task } expect(response.content_type).to eq "application/json; charset=utf-8" # ここを修正 end it "adds a new task to the project" do new_task = { name: "New test task" } sign_in user expect { post :create, format: :json, params: { project_id: project.id, task: new_task } }.to change(project.tasks, :count).by(1) end it "requires authentication" do new_task = { name: "New test task" } # Don't sign in this time ... expect { post :create, format: :json, params: { project_id: project.id, task: new_task } }.to_not change(project.tasks, :count) expect(response.content_type).to eq "application/json; charset=utf-8" # ここを修正 end end end
bin/rspecを実行し、テストに失敗がないか確認したところ、無事成功した。
ただし、動画同様に警告が出ているので、対応していく。DEPRECATION WARNING: update_attributes is deprecated and will be removed from Rails 6.1 (please, use update instead) (called from toggle at /Users/HOGE/Desktop/Github作業フォルダ/RSpecPractice/everydayrails-rspec-2017-master/app/controllers/tasks_controller.rb:67)
update_attributesをupdateに修正するとのことだった。ついては、以下のファイルを修正する。
app/controllers/tasks_controller.rbapp/controllers/projects_controller.rbspec/controllers/projects_controller.rbさて、次に以下の警告を対応する。
DEPRECATION WARNING: Single arity template handlers are deprecated. Template handlers must now accept two parameters, the view object and the source for the view object. Change: >> Coffee::Rails::TemplateHandler.call(template) To: >> Coffee::Rails::TemplateHandler.call(template, source) (called from <main> at /Users/kentasuedomi/Desktop/Github作業フォルダ/RSpecPractice/everydayrails-rspec-2017-master/Rakefile:6)動画で紹介されてないのでどうしたものかと思っていたところ、
以下の記事を発見! ありがたい!!!結論を読むと、
cofee-railsのバージョンが問題らしい。
Gemfileを以下のとおり設定し、bundle updateを行う。gem 'coffee-rails', '~> 5.0.0'警告が消えた!
ついに終了!!!最後に
RSpecの勉強がやっと開始できることを嬉しく思います。
伊藤さん、改めてお世話になります!!!大変でしたが、こんな初学者がRailsのバージョンアップを
ハンズオンで体験できるという意味ではすごい教材です!!!ただ、RSpecを純粋に勉強したい人は、バージョンアップするべきかよく考えましょう 笑
- 投稿日:2020-06-19T01:29:59+09:00
【中編】「Everyday Rails - RSpecによるRailsテスト入門」を Rails 6 で勉強したいので伊藤さんのブログを参考にして頑張ってみた
はじめに
この記事は、タイトルのとおり、「Everyday Rails」を Rails 6 で勉強したいので、
書籍の翻訳者である伊藤さんのブログを参考にして頑張ってみた記録を記したものである。記事自体が長くなったので、導入編・前編・中編・後編に分割している。
Rails 6 へのアップグレードは非常に時間がかかるので、いきなり挑戦するのではなく、
まず導入編を読んでいただき、本当に挑戦するのか検討することを強く勧めます。記録を見たい方は、以下を参照すること。
【導入編】「Everyday Rails - RSpecによるRailsテスト入門」を Rails 6 で勉強したいので伊藤さんのブログを参考にして頑張ってみた - Qiita
【前編】「Everyday Rails - RSpecによるRailsテスト入門」を Rails 6 で勉強したいので伊藤さんのブログを参考にして頑張ってみた - Qiita
【後編】「Everyday Rails - RSpecによるRailsテスト入門」を Rails 6 で勉強したいので伊藤さんのブログを参考にして頑張ってみた - Qiitaまた、本記事は、伊藤さんのyoutube動画を見ながら作業した内容の実況中継に
近いような形で書き進めているので、以下を必ず併せて視聴してください。
(youtube動画を視聴している前提で書いているので、この記事単体だと意味が通じない)【前編】永久保存版!?伊藤さん式・Railsアプリのアップグレード手順(youtube動画)
【後編】永久保存版!?伊藤さん式・Railsアプリのアップグレード手順(youtube動画)4. Rails以外のgemをバージョンアップする
4-c. トラブルが起きやすそうなgemを1つずつアップデートする
RSpecのサンプルアプリでなければ慎重にやるべきなのだが、
動画内で伊藤さんはスルーしていたので、割愛する。ただ、gemを見つつ、アップデートでトラブルが起きそうでないか確認をしていた。
そういうステップがあるということだけ確認しつつ、次へ進むことにする。4-d. その他のgemをまとめてアップデートする
伊藤さんによると、次は
bundle outdated | bof --format markdown
の実行によって取得できた default と書いてあるgemを見ていくべきとのことだが、
そもそも default と書かれているgemが存在しない。参考までに、伊藤さんの動画のスクリーンショットと、
私が取得した default と書かれていないgemの一覧を貼付しておく。勝手な推測だが、伊藤さんが動画を撮った時期と、
私がアップデートしている時期が異なるためだと思われる。
(それか何か余計な操作をしてしまったのかもしれない)【自分でやってみた結果】
gem newest installed requested groups actioncable 6.0.3.1 5.1.7 actionmailer 6.0.3.1 5.1.7 actionpack 6.0.3.1 5.1.7 actionview 6.0.3.1 5.1.7 activejob 6.0.3.1 5.1.7 activemodel 6.0.3.1 5.1.7 activerecord 6.0.3.1 5.1.7 activesupport 6.0.3.1 5.1.7 arel 9.0.0 8.0.0 autoprefixer-rails 9.7.6 6.7.7.2 bcrypt 3.1.13 3.1.12 bindex 0.8.1 0.5.0 bootstrap-sass 3.4.1 3.3.7 cocaine 0.6.0 0.5.8 coffee-rails 5.0.0 4.2.1 ~> 4.2 devise 4.7.2 4.4.3 faker 2.12.0 1.7.3 geocoder 1.6.3 1.4.9 i18n 1.8.3 0.9.5 jbuilder 2.10.0 2.6.3 ~> 2.5 jquery-rails 4.4.0 4.3.1 listen 3.2.1 3.1.5 < 3.2, >= 3.0.5 mimemagic 0.3.5 0.3.2 mini_portile2 2.5.0 2.4.0 multi_json 1.14.1 1.12.1 paperclip 6.1.0 5.1.0 puma 4.3.5 3.8.2 ~> 3.7 rails 6.0.3.1 5.1.7 ~> 5.1.1 railties 6.0.3.1 5.1.7 rb-fsevent 0.10.4 0.9.8 rb-inotify 0.10.1 0.9.8 responders 3.0.1 2.4.0 sass 3.7.4 3.4.23 sass-rails 6.0.0 5.0.6 ~> 5.0 spring 2.1.0 2.0.1 sprockets 4.0.2 3.7.2 sqlite3 1.4.2 1.3.13 thor 1.0.1 0.20.3 tilt 2.0.10 2.0.7 turbolinks 5.2.1 5.0.1 ~> 5 turbolinks-source 5.2.0 5.0.0 tzinfo 2.0.2 1.2.7 uglifier 4.2.0 3.2.0 warden 1.2.8 1.2.7 web-console 4.0.3 3.5.0 websocket-driver 0.7.2 0.6.5 この時点でyoutube動画と条件も違うのだが、ここは伊藤さんの動画でやっているとおり、
雑にbundle updateしてみることにする。けど、正直トラブルになりそうで、とても怖い。。。
とりあえず、後で戻せるようにコミットだけしておく。やってみると、
bundle updateは成功した!
続いて、RSpecでのテストを実行する。Finished in 25.46 seconds (files took 1.14 seconds to load) 70 examples, 0 failures無事、成功した!!
ただ、動画で説明のとおり、以下のような警告が出ている。Sign-ups DEPRECATION WARNING: [Devise] `DeviseHelper.devise_error_messages!` is deprecated and it will be removed in the next major version. To customize the errors styles please run `rails g devise:views` and modify the `devise/shared/error_messages` partial.ここで、警告に書かれているとおり、
rails g devise:viewsを実行する。実行すると、オーバーライトするか尋ねられる。
最初はnとして、次のファイルにてdを押して、差分を確認して以下をコピーする。- <%= devise_error_messages! %> + <%= render "devise/shared/error_messages", resource: resource %>他のファイルについては、全て
nとする。
コピーした内容を使って、関係ファイルの該当部分を修正する。
<%= devise_error_messages! %>を全て修正する。
修正後は、<%= render "devise/shared/error_messages", resource: resource %>とする。該当ファイルは以下のとおり。
修正後にRSpecにてテストを行うと、警告が消えた。
bundle outdatedを行うと、以下のとおりとなった。
gem newest installed requested groups actioncable 6.0.3.1 5.1.7 actionmailer 6.0.3.1 5.1.7 actionpack 6.0.3.1 5.1.7 actionview 6.0.3.1 5.1.7 activejob 6.0.3.1 5.1.7 activemodel 6.0.3.1 5.1.7 activerecord 6.0.3.1 5.1.7 activesupport 6.0.3.1 5.1.7 arel 9.0.0 8.0.0 coffee-rails 5.0.0 4.2.2 ~> 4.2 listen 3.2.1 3.1.5 < 3.2, >= 3.0.5 mini_portile2 2.5.0 2.4.0 puma 4.3.5 3.12.6 ~> 3.7 rails 6.0.3.1 5.1.7 ~> 5.1.1 railties 6.0.3.1 5.1.7 sass-rails 6.0.0 5.0.7 ~> 5.0 sprockets 4.0.2 3.7.2 thor 1.0.1 0.20.3 tzinfo 2.0.2 1.2.7 web-console 4.0.3 3.7.0 websocket-driver 0.7.2 0.6.5 伊藤さんの動画だと、以下のとおりとなっている。
よく見ると違うところもあるが、概ね同じ状態になった。
5. Rubyのバージョンを最新にする
動画での指示に従い、Rubyのバージョンを新しくする。
現在の最新のバージョン(安定版)は2.7.1とのことだが、試すのも怖い。
(動画では2.6.5が採用されている)とはいえ、伊藤さんによるとRubyは後方互換性を意識しているとのことなので、
commitだけ一応しておいて、バージョン2.7.1で試してみる。# ruby 2.7.1 をダウンロードする rbenv install 2.7.1 # rubyのバージョンを 2.7.1 に指定する rbenv local 2.7.1 # rubyのバージョンが 2.7.1 になっていることを確認する rbenv version改めて、
bundle installを行う。すると、
gem install bundler 2.1.4を実行せよと指示が出るので、
その指示に従った後、もう一度bundle installを行う。警告が出るが、
i18n,Paperclip,Sassに関連するものであり、
Ruby 2.4.9 を導入してbundleした時の警告と基本的には変わらない。RSpecでテストを実行する。
Users/HOGE/.rbenv/gems/2.7.0/bundler/gems/shoulda-matchers-4b160bd19ecc/lib/shoulda/matchers/active_model/validate_inclusion_of_matcher.rb:273:in `<class:ValidateInclusionOfMatcher>': undefined method `new' for BigDecimal:Class (NoMethodError)エラーとなってしまった。
動画上では警告が出るだけだったが、Rubyのバージョンを上げたためなのか、
そもそもRSpecのテストが出来なくなってしまった。ただ、動画によると、このエラーはRailsのバージョンを上げれば解決するようなので、
Railsを5.2.3にアップデートしてみる。なお、動画では
Gemfileを開き、shoulda-matchersのブランチ指定を解除していたが、
そちらについては後ほど対応することとする。6. Railsを最新のパッチバージョンに上げる
ここは、実は手順4の中で
bundle updateをしている中で済んでいる。実際のアプリでバージョンアップする場合については、
Railsと他のgemのアップデートはきちんと切り分けた方がよいのかもしれない。7. Railsのメジャーバージョン、またはマイナーバージョンを上げる
Gemfileを開き、railsのバージョンを以下のとおり設定する。gem 'rails', '~> 5.2.3'そして、
bundle updateを実行する。
無事、成功した。8. rails app: update タスクを実行する
終了した後、
rails app: updateを実行する。
routes.rbだけはnを押し、それ以外はyを押す。必要に応じて上書きされた設定を元に戻す
ここで差分を確認しながら、自力で必要な設定を戻していく。
VSCodeを使っていると、以下のとおり確認できる。動画の指示に従い、設定を以下のとおり戻した。
参考までに記す。config/application.rbmodule Projects class Application < Rails::Application # Initialize configuration defaults for originally generated Rails version. config.load_defaults 5.1 # Settings in config/environments/* take precedence over those specified here. # Application configuration can go into files in config/initializers # -- all .rb files in that directory are automatically loaded after loading # the framework and any gems in your application. # configで始まる部分を追加 config.generators do |g| g.test_framework :rspec, view_specs: false, helper_specs: false, routing_specs: false end end endconfig/environments/test.rb# 以下のコードを最後に追加する # Keep files uploaded in tests from polluting the Rails development # environment's file uploads Paperclip::Attachment.default_options[:path] = \ "#{Rails.root}/spec/test_uploads/:class/:id_partition/:style.:extension"9. railsdiff.org を参考にして、新しく追加された gem 等を確認する
以下のとおり説明があるので、対応する。
app:updateコマンドを実行しても、Gemfileのようにまったく更新されないファイルもあります。
ですが、rails newした直後のGemfileを比較すると、
デフォルトでインストールされるgemの種類やバージョンには違いがあります。
Railsのバージョンを上げたのであれば、こういった部分も新しいRailsに合わせておく方が安心です。以下を開き、動画のとおり更新する。
正直、初学者にはどれを更新すべきか、全く見当がつかない。更新した箇所は下記のとおり、3つのファイル。
.gitignore〜 上部は変更がないので省略 〜 # ---- 以下に修正を加えた ------ # Ignore uploaded files in development # これを追加 /storage/* # これを追加 !/storage/.keep # これを追加 /node_modules /yarn-error.log /public/assets # これを追加 .byebug_history # Ignore master key for decrypting credentials and more. # これを追加 /config/master.key # これを追加 # Ignore uploads from Paperclip /public/system /spec/test_uploads .ruby-versionGemfilesource 'https://rubygems.org' git_source(:github) { |repo| "https://github.com/#{repo}.git" } # ここを変更 ruby '2.7.1' # ここを追加 gem 'rails', '~> 5.2.3' gem 'sqlite3' gem 'puma', '~> 3.11' # ここを変更 gem 'sass-rails', '~> 5.0' gem 'uglifier', '>= 1.3.0' gem 'coffee-rails', '~> 4.2' gem 'turbolinks', '~> 5' gem 'jbuilder', '~> 2.5' gem 'bootsnap', '>= 1.1.0', require: false # ここを追加 〜 以下、変更がないので省略します 〜app/views/layouts/application.html.erb<!DOCTYPE html> <html> <head> <title>Projects</title> <%= csrf_meta_tags %> <%= csp_meta_tag %> <%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %> <%= javascript_include_tag 'application', 'data-turbolinks-track': 'reload' %> </head> # 以下は変更がないので、省略さて、変更を終えたので、
bundle installを実行する。
実行したところ、無事終了した。10. 動作確認を行う
動画に従い、
rails cを実行する。
すると、rails cの起動は出来たが、以下の警告メッセージが出てきた。/Users/HOGE/.rbenv/gems/2.7.0/gems/actionpack-5.2.4.3/lib/action_dispatch/middleware/stack.rb:37: warning: Using the last argument as keyword parameters is deprecated; maybe ** should be added to the call /Users/HOGE/.rbenv/gems/2.7.0/gems/actionpack-5.2.4.3/lib/action_dispatch/middleware/static.rb:111: warning: The called method `initialize' is defined hereまた、
rails cの挙動を確認したが、エラーとなった。irb(main):001:0> User.count Traceback (most recent call last): 1: from (irb):1 ActiveRecord::StatementInvalid (Could not find table 'users')動画の中で見逃したのかもしれないが、マイグレーションが必要だったのだろうか。
gitでtestというブランチを作り、保険だけ掛けておく。マイグレーションを行うと、無事
rails cは動いた。
ただ、動画とは異なり、User.countをしても 21 という数は出てこない。
きっと伊藤さんはテストか何かをしていて、それでUserが21人もいるのだろう。また、先ほど出てきた警告メッセージは、引き続き出てくる。
気になったので調べてみると、どうやらgemが対応できていないことが原因らしい。問題はなさそうなので、とりあえずスルーすることにする。
rails sにてサーバーが立ち上がるかも確認。
無事動き、機能も一通り試したところ問題がなさそうだった。
bin/rspecを実行する。
以下のエラーが出て、テストが実行できなかった。/Users/HOGE/.rbenv/gems/2.7.0/bundler/gems/shoulda-matchers-4b160bd19ecc/lib/shoulda/matchers/active_model/validate_inclusion_of_matcher.rb:273:in `<class:ValidateInclusionOfMatcher>': undefined method `new' for BigDecimal:Class (NoMethodError)
shoulda-matchersと書いてあるので、ここで放置してきた
shoulda-matchersのブランチ指定を解除を行ってみる。
Gemfileを開き、gem 'shoulda-matchers'以下に書いてある2行のブランチ指定のコードを削除する。
そして、bundle installを実行する。すると、テストが無事実行できた。
ただ、以下の失敗が起きた。
また、Rubyのバージョンが2.7.1に上がったことが原因だと推測されるが、大量の警告が出た。Failures: 1) Notes user uploads an attachment Failure/Error: fill_in "Message", with: "My book cover" Capybara::ElementNotFound: Unable to find field "Message" that is not disabled 〜 省略 〜 2) Projects user creates a new project Failure/Error: fill_in "Name", with: "Test Project" Capybara::ElementNotFound: Unable to find field "Name" that is not disabled 〜 省略 〜 Finished in 46.59 seconds (files took 3.76 seconds to load) 70 examples, 2 failures Failed examples: rspec ./spec/system/notes_spec.rb:11 # Notes user uploads an attachment rspec ./spec/system/projects_spec.rb:4 # Projects user creates a new projectなお、以下の警告も出てきた。
こちらは動画内で取り上げられていたので、Rubyが2.7.1にバージョンアップしたことが原因ではないもよう。DEPRECATION WARNING: The success? predicate is deprecated and will be removed in Rails 6.0. Please use successful? as provided by Rack::Response::Helpers. (called from block (3 levels) in <main> at /Users/HOGE/Desktop/Github作業フォルダ/RSpecPractice/everydayrails-rspec-2017-master/spec/controllers/tasks_controller_spec.rb:40) # 他の箇所にもRSpec関係のファイルにて同様の警告があり動画に従い、まず以下のFailuresから解決する。
Failures: 1) Notes user uploads an attachment Failure/Error: fill_in "Message", with: "My book cover" Capybara::ElementNotFound: Unable to find field "Message" that is not disabled 〜 省略 〜 2) Projects user creates a new project Failure/Error: fill_in "Name", with: "Test Project" Capybara::ElementNotFound: Unable to find field "Name" that is not disabledこれは
form_withに関わるエラーであり、HTMLが生成されるときにidが消えてしまうらしい。config.load_defaultsとnew_framework_defaults_x_x.rbの関係を詳しく調べてみた - Qiita
そこで、以下のファイルを修正する。
config/application.rbmodule Projects class Application < Rails::Application # Initialize configuration defaults for originally generated Rails version. # 5.1から5.2に変更する config.load_defaults 5.2 # Settings in config/environments/* take precedence over those specified here. # Application configuration can go into files in config/initializers # -- all .rb files in that directory are automatically loaded after loading # the framework and any gems in your application. config.generators do |g| g.test_framework :rspec, view_specs: false, helper_specs: false, routing_specs: false end end endRSpecのテストを実行してみると、動画のとおり、全てのテストがパスした。
Finished in 14.12 seconds (files took 1.05 seconds to load) 70 examples, 0 failures次に、警告を解決する。
改めて英文の警告を確認すると、
successをsuccessfulに書き換えろと指示があるので、
その指示に従う。すると、警告が消えるらしい。以下のファイルを開き、指示のとおり対応した。
spec/controllers/home_controller_spec.rbspec/controllers/projects_controller_spec.rbspec/controllers/tasks_controller_spec.rbspec/controllers/home_spec.rbRSpecのテストを実行してみると、警告が消えた。
(もちろん、Ruby2.7.1の導入に起因すると思われる大量の警告は残ったままであるが笑)これで、Rails5.2へのアップデートが終了した。
どこまで進んだか
動画の後編の12分30秒くらいのところまで進んだ。
【後編】「Everyday Rails - RSpecによるRailsテスト入門」を Rails 6 で勉強したいので伊藤さんのブログを参考にして頑張ってみた
- 投稿日:2020-06-19T01:29:30+09:00
【前編】「Everyday Rails - RSpecによるRailsテスト入門」を Rails 6 で勉強したいので伊藤さんのブログを参考にして頑張ってみた
はじめに
この記事は、タイトルのとおり、「Everyday Rails」を Rails 6 で勉強したいので、
書籍の翻訳者である伊藤さんのブログを参考にして頑張ってみた記録を記したものである。記事自体が長くなったので、導入編・前編・中編・後編に分割している。
Rails 6 へのアップグレードは非常に時間がかかるので、いきなり挑戦するのではなく、
まず導入編を読んでいただき、本当に挑戦するのか検討することを強く勧めます。導入編・中編・後編については、以下を参照すること。
【導入編】「Everyday Rails - RSpecによるRailsテスト入門」を Rails 6 で勉強したいので伊藤さんのブログを参考にして頑張ってみた - Qiita
【中編】「Everyday Rails - RSpecによるRailsテスト入門」を Rails 6 で勉強したいので伊藤さんのブログを参考にして頑張ってみた - Qiita
【後編】「Everyday Rails - RSpecによるRailsテスト入門」を Rails 6 で勉強したいので伊藤さんのブログを参考にして頑張ってみた - Qiitaまた、本記事は、伊藤さんのyoutube動画を見ながら作業した内容の実況中継に
近いような形で書き進めているので、以下を必ず併せて視聴してください。
(youtube動画を視聴している前提で書いているので、この記事単体だと意味が通じない)【前編】永久保存版!?伊藤さん式・Railsアプリのアップグレード手順(youtube動画)
【後編】永久保存版!?伊藤さん式・Railsアプリのアップグレード手順(youtube動画)作業を始める前に
「Everyday Rails - RSpecによるRailsテスト入門」のサンプルアプリについては、
伊藤さんのyoutube動画を見ながら作業すると、以下のとおりアップグレードできる。
変更前の環境 変更後の環境 Rails 5.1.1 6.0.0 rspec-rails 3.8.0 4.0.0.beta2(正式版は3.9.0) Ruby 2.4.9 2.6.5 その他のgem - できる限り最新化 (2019年10月時点の最新環境)
なお、私は以下のとおりアップグレードした。
なぜと思うところがあるかもしれないが、
初学者なので何となく最新版にしてみたとしか言いようがない。
変更前の環境 変更後の環境 Rails 5.1.1 6.0.3.2 rspec-rails 3.8.0 4.0.1 Ruby 2.4.9 2.7.1 その他のgem - できる限り最新化 (2020年6月18日時点の最新環境・・・と思われる)
あと、初学者なので話半分で聞いてもらいたいが、rubyは2.7.1にしない方がよいような気がする。
様々なgemとの互換性の問題があるためか、警告が大量に出てくる。覚悟して使いましょう。また、私はヒヨってRailsのバージョンは、6.0.0でよいと思って作業を進めていたが、
gem 'rails', '~> 6.0.0'と書いていたので、結果として最新版に更新できていた。ブログ内で気になる部分があるかもしれないが、
本人は、Rails 6.0.0 にアップグレードするつもりで頑張っている。生温かい目で見守ってもらいたい。
伊藤さんのyoutube動画の構成
伊藤さんは、ご自身が書いたRailsアプリのアップグレード手順を参考にして、
順を追ってRSpecのサンプルアプリをアップグレードしている。以下がそのアップグレード手順を記したQiita記事である。
この記事では、このアップグレード手順に準拠する形で章立てをする。
1. 公式のアップグレードガイドに目を通す
私はほぼ目を通しませんでしたが、通すと勉強になるかと思います。。。
2. テストが全部パスすることを確認する
動画では、テストが全てパスするか確認するよう指示が出ている。
RSpecでのテストは以下のコマンドで実行できる。bin/rspecSpecテストでいきなりパスしない!
やってみると、下記の記事で紹介されているようなエラーが出た。
どうやら、Rubyのバージョンが問題であるようなので、大人しくRubyを2.4.9に指定することにした。
私は、Rbenvを使っているのだが、使い方を忘れているので、以下を参照して対応した。# ruby 2.4.9 をダウンロードする rbenv install 2.4.9 # rubyのバージョンを 2.4.9 に指定する rbenv local 2.4.9 # rubyのバージョンが 2.4.9 になっていることを確認する rbenv version無事、Rubyのバージョンを2.4.9に合わせることができた。
また、Specテストにパスしない!
RSpecで再テストすると、以下のとおりエラーが出た。
Failures: 1) Tasks user toggles a task Got 0 failures and 2 other errors: 1.1) Failure/Error: visit root_path Selenium::WebDriver::Error::SessionNotCreatedError: session not created: This version of ChromeDriver only supports Chrome version 81 1.2) Failure/Error: Unable to infer file and line number from backtrace Selenium::WebDriver::Error::SessionNotCreatedError: session not created: This version of ChromeDriver only supports Chrome version 81 Finished in 27.03 seconds (files took 1.18 seconds to load) 70 examples, 1 failure Failed examples: rspec ./spec/system/tasks_spec.rb:12 # Tasks user toggles a taskPythonの話がベースだが、以下の記事を参考にした。
どうやら、私が使っているChromeのバージョンとの不一致が問題である可能性が高い。
Chromeのバージョンを確認すると、以下のとおりバージョンが83だった。エラーメッセージを見直してみると、Everyday Railsの方ではバージョンが81を要求している。
ここでバージョンのダウングレードをしてもよいのだが、
そもそもRailsのバージョンを6にアップグレードした際に、
chromedriver-helperをwebdriversに変更するよう指示が出ているので、
ここはスルーすることにする。3. 開発用ブランチを作成する
ちょくちょくブランチを切りましょう。
保険は大事です。4. Rails以外のgemをバージョンアップする
さて、指示のとおりブランチを作成した後、Rails以外の
gemをバージョンアップする。
なお、一度失敗しているので、ここの記述はかなり冗長である。4-a. 最新ではないgemを探す(第1チャレンジ)
gemが最新か確認するように指示があるのでbundle outdatedを実行してみる。outdated gems included in the bundle: * actioncable (newest 6.0.3.1, installed 5.1.1) * actionmailer (newest 6.0.3.1, installed 5.1.1) * actionpack (newest 6.0.3.1, installed 5.1.1) * actionview (newest 6.0.3.1, installed 5.1.1) * activejob (newest 6.0.3.1, installed 5.1.1) * activemodel (newest 6.0.3.1, installed 5.1.1) * activerecord (newest 6.0.3.1, installed 5.1.1) * activesupport (newest 6.0.3.1, installed 5.1.1) * addressable (newest 2.7.0, installed 2.5.2) * archive-zip (newest 0.12.0, installed 0.11.0) * arel (newest 9.0.0, installed 8.0.0) * autoprefixer-rails (newest 9.7.6, installed 6.7.7.2) * bcrypt (newest 3.1.13, installed 3.1.12) * bindex (newest 0.8.1, installed 0.5.0) * bootstrap-sass (newest 3.4.1, installed 3.3.7) in group "default" * builder (newest 3.2.4, installed 3.2.3) * byebug (newest 11.1.3, installed 9.0.6) in groups "development, test" * capybara (newest 3.32.2, installed 2.15.4, requested ~> 2.15.4) in group "test" * childprocess (newest 3.0.0, installed 0.8.0) * chromedriver-helper (newest 2.1.1, installed 1.2.0) in group "test" * cocaine (newest 0.6.0, installed 0.5.8) * coffee-rails (newest 5.0.0, installed 4.2.1, requested ~> 4.2) in group "default" * concurrent-ruby (newest 1.1.6, installed 1.0.5) * crass (newest 1.0.6, installed 1.0.4) * devise (newest 4.7.2, installed 4.4.3) in group "default" * erubi (newest 1.9.0, installed 1.7.1) * factory_bot (newest 5.2.0, installed 4.10.0) * factory_bot_rails (newest 5.2.0, installed 4.10.0, requested ~> 4.10.0) in groups "development, test" * faker (newest 2.12.0, installed 1.7.3) in group "development" * ffi (newest 1.13.1, installed 1.9.18) * geocoder (newest 1.6.3, installed 1.4.9) in group "default" * globalid (newest 0.4.2, installed 0.4.0) * hashdiff (newest 1.0.1, installed 0.3.4) * i18n (newest 1.8.3, installed 0.9.5) * io-like (newest 0.3.1, installed 0.3.0) * jbuilder (newest 2.10.0, installed 2.6.3, requested ~> 2.5) in group "default" * jquery-rails (newest 4.4.0, installed 4.3.1) in group "default" * launchy (newest 2.5.0, installed 2.4.3, requested ~> 2.4.3) in group "test" * listen (newest 3.2.1, installed 3.1.5, requested < 3.2, >= 3.0.5) in group "development" * loofah (newest 2.6.0, installed 2.2.2) * mail (newest 2.7.1, installed 2.6.5) * method_source (newest 1.0.0, installed 0.9.0) * mime-types (newest 3.3.1, installed 3.1) * mime-types-data (newest 3.2020.0512, installed 3.2016.0521) * mimemagic (newest 0.3.5, installed 0.3.2) * mini_mime (newest 1.0.2, installed 0.1.4) * mini_portile2 (newest 2.5.0, installed 2.3.0) * minitest (newest 5.14.1, installed 5.11.3) * multi_json (newest 1.14.1, installed 1.12.1) * nio4r (newest 2.5.2, installed 2.0.0) * nokogiri (newest 1.10.9, installed 1.8.4) * paperclip (newest 6.1.0, installed 5.1.0) in group "default" * public_suffix (newest 4.0.5, installed 3.0.0) * puma (newest 4.3.5, installed 3.8.2, requested ~> 3.7) in group "default" * rack (newest 2.2.3, installed 2.0.5) * rack-test (newest 1.1.0, installed 0.6.3) * rails (newest 6.0.3.1, installed 5.1.1, requested ~> 5.1.1) in group "default" * rails-html-sanitizer (newest 1.3.0, installed 1.0.4) * railties (newest 6.0.3.1, installed 5.1.1) * rake (newest 13.0.1, installed 12.3.1) * rb-fsevent (newest 0.10.4, installed 0.9.8) * rb-inotify (newest 0.10.1, installed 0.9.8) * responders (newest 3.0.1, installed 2.4.0) * rspec-core (newest 3.9.2, installed 3.8.0) * rspec-expectations (newest 3.9.2, installed 3.8.1) * rspec-mocks (newest 3.9.1, installed 3.8.0) * rspec-rails (newest 4.0.1, installed 3.8.0, requested ~> 3.8.0) in groups "development, test" * rspec-support (newest 3.9.3, installed 3.8.0) * rubyzip (newest 2.3.0, installed 1.2.1) * safe_yaml (newest 1.0.5, installed 1.0.4) * sass (newest 3.7.4, installed 3.4.23) * sass-rails (newest 6.0.0, installed 5.0.6, requested ~> 5.0) in group "default" * selenium-webdriver (newest 3.142.7, installed 3.6.0) in group "test" * spring (newest 2.1.0, installed 2.0.1) in group "development" * sprockets (newest 4.0.2, installed 3.7.1) * sprockets-rails (newest 3.2.1, installed 3.2.0) * sqlite3 (newest 1.4.2, installed 1.3.13) in group "default" * thor (newest 1.0.1, installed 0.20.0) * tilt (newest 2.0.10, installed 2.0.7) * turbolinks (newest 5.2.1, installed 5.0.1, requested ~> 5) in group "default" * turbolinks-source (newest 5.2.0, installed 5.0.0) * tzinfo (newest 2.0.2, installed 1.2.5) * uglifier (newest 4.2.0, installed 3.2.0) in group "default" * vcr (newest 6.0.0, installed 3.0.3) in group "test" * warden (newest 1.2.8, installed 1.2.7) * web-console (newest 4.0.2, installed 3.5.0) in group "development" * webmock (newest 3.8.3, installed 3.0.1) in group "test" * websocket-driver (newest 0.7.2, installed 0.6.5) * websocket-extensions (newest 0.1.5, installed 0.1.2) * xpath (newest 3.2.0, installed 2.1.0)悪夢のような数の
gemが。。。ここで激しい勘違いをしていたのだが、
in group developmentとin group test
のものをまずアップデートしようと伊藤さんは言っているのであって、
それに該当するのが以下の表になるということらしい。ちなみに、私はここから明後日の方向に進み出して、最終的に面倒になって、
全てのgemのバージョン指定を解除した後にbundle updateをガツンとしたら、
RSpecで以下のようなエラーが出た。There is a version mismatch between the Spring client (2.1.0) and the server (2.0.1). 〜 省略 〜 WARN Selenium [DEPRECATION] Selenium::WebDriver::Chrome#driver_path= is deprecated. Use Selenium::WebDriver::Chrome::Service#driver_path= instead. 〜 省略 〜なお、私はこのフェーズにおいて動画をほぼ見ずに作業をしていた。
動画は見ましょう、絶対に。さて、最初から頑張ってみることにする。
4-a. 最新ではないgemを探す(第2チャレンジ)
ここまでの知見を生かし、Rubyのバージョン指定まで素早くこなす。
そして素直に、
Gemfileにbundle_outdated_formatterを導入してみる。指示どおりやっていくと、以下のとおりのエラーが出る。
これは動画でも紹介されているとおりである。Resolving dependencies... Bundler could not find compatible versions for gem "bundler": In Gemfile: rails (~> 5.1.1) was resolved to 5.1.1, which depends on bundler (< 2.0, >= 1.3.0) Current Bundler version: bundler (2.1.4) This Gemfile requires a different version of Bundler. Perhaps you need to update Bundler by running `gem install bundler`? Could not find gem 'bundler (< 2.0, >= 1.3.0)', which is required by gem 'rails (~> 5.1.1)', in any of the sources.ちなみに、これは先ほど試行錯誤していく中でも出たエラーである。
私は、エラーメッセージに従う形でbundlerのバージョンを下げたりして、
ゴニョゴニョやっていったが、伊藤さんによると「bundle update railsならいけるっぽい」
ということなので、ここはこのコマンドを試してみる。やってみると、上手くアップデートできた。
動画では理屈について少し言及していたが、初学者なのでよく分からず。
ここで調べ出すとキリがなさそうなので、次のステップに行くことにした。
bundle outdated fomatterのコマンドを使って取得した表は、開発環境・テスト環境下で
あるとかそのような状況に関係なく、全てのoutdated gemsを表示する。そこで、動画の指示のとおり表計算ソフトで加工してみる。
手持ちのlibre officeで加工すると、以下のとおりの表となった。何やら、伊藤さんのものと比べて、かなりシンプルなものになった。
4-b. development と test グループの gem を先にアップデートする
Gemfileを開き、以下のgemのバージョン指定を外してみる。
外すものは、動画で言及されていたものに限定した。group :development, :test do gem 'rspec-rails' # バージョン指定を解除 gem 'factory_bot_rails' # バージョン指定を解除 gem 'byebug', platforms: [:mri, :mingw, :x64_mingw] end group :test do gem 'capybara' # バージョン指定を解除 gem 'selenium-webdriver' # バージョン指定を解除 gem 'chromedriver-helper' # Or use poltergeist and PhantomJS as an alternative to Selenium/Chrome # gem 'poltergeist', '~> 1.15.0' gem 'launchy' gem 'shoulda-matchers', git: 'https://github.com/thoughtbot/shoulda-matchers.git', branch: 'rails-5' gem 'vcr' gem 'webmock' endさて、以下を実行する。
bundle update -g development -g test無事成功した。
ちなみに、動画ではchromedriver-helperからwebdriversに移行するよう指示が出ていた。詳細は動画のとおりだが、
Gemfile内のchromedriver-helperをwebdriversに書き換えて、
bundle installすればよいらしい。私の場合、bundle installは問題なく実行できた。さて、RSpecで再テストする。
何やら、エラーが色々と出てきた。[DEPRECATED] `Bundler.with_clean_env` has been deprecated in favor of `Bundler.with_unbundled_env`. If you instead want the environment before bundler was originally loaded, use `Bundler.with_original_env` (called at /Users/kentasuedomi/.rbenv/gems/2.4.0/gems/spring-2.0.1/lib/spring/application_manager.rb:95) 2020-06-17 18:31:22 WARN Selenium [DEPRECATION] Selenium::WebDriver::Chrome#driver_path= is deprecated. Use Selenium::WebDriver::Chrome::Service#driver_path= instead. /Users/kentasuedomi/.rbenv/gems/2.4.0/gems/factory_bot-5.2.0/lib/factory_bot/definition_proxy.rb:99:in `method_missing': undefined method 'message' in 'note' factory Did you mean? 'message { "My important note." }' (NoMethodError) 〜 以下、省略 〜この記事に詳細があるらしい。
動画で紹介されているとおり、まず以下を実行する。
gem install rubocop-rspecそして、以下を実行する。
rubocop \ --require rubocop-rspec \ --only FactoryBot/AttributeDefinedStatically \ --auto-correct 〜 省略 〜 104 files inspected, 10 offenses detected, 10 offenses correctedRSpecでテストする。
詳細は省略するが、以下の部分だけテストで失敗した。Failures: 1) Tasks user toggles a task Got 0 failures and 2 other errors: 1.1) Failure/Error: visit root_path VCR::Errors::UnhandledHTTPRequestError: 1.2) Failure/Error: raise VCR::Errors::UnhandledHTTPRequestError.new(vcr_request) VCR::Errors::UnhandledHTTPRequestError:ただ、このFailuresは動画で紹介されているものである。
詳細は動画で確認してもらいたいが、以下のとおり設定すればテストでの失敗は回避できるらしい。# spec/support/vcr.rb VCR.configure do |config| config.cassette_library_dir = "#{::Rails.root}/spec/cassettes" config.hook_into :webmock config.ignore_localhost = true # 下記の config.ignore_hosts で始まる1行を追加 config.ignore_hosts 'chromedriver.storage.googleapis.com' config.configure_rspec_metadata! endRSpecでテストする。
すると、何と全てのテストが通る!!!Finished in 9.03 seconds (files took 1.11 seconds to load) 70 examples, 0 failuresどこまで進んだか
動画だと、前編の17分ぐらい経過したところまで進んだ。
続編はこちらは
【中編】「Everyday Rails - RSpecによるRailsテスト入門」を Rails 6 で勉強したいので伊藤さんのブログを参考にして頑張ってみた - Qiita
- 投稿日:2020-06-19T01:29:08+09:00
【導入編】「Everyday Rails - RSpecによるRailsテスト入門」を Rails 6 で勉強したいので伊藤さんのブログを参考にして頑張ってみた
はじめに
この記事は、タイトルのとおり、「Everyday Rails」を Rails 6 で勉強したいので、
書籍の翻訳者である伊藤さんのブログを参考にして頑張ってみた記録を記したものである。ただ、記事自体が長くなったので、導入編ではその記録を記していない。
Rails 6 で勉強する場合は時間がかかるので覚悟した方がよいという注意喚起のみしか記載していない。記録を見たい方は、以下を参照すること。
【前編】「Everyday Rails - RSpecによるRailsテスト入門」を Rails 6 で勉強したいので伊藤さんのブログを参考にして頑張ってみた - Qiita
【中編】「Everyday Rails - RSpecによるRailsテスト入門」を Rails 6 で勉強したいので伊藤さんのブログを参考にして頑張ってみた - Qiita
【後編】「Everyday Rails - RSpecによるRailsテスト入門」を Rails 6 で勉強したいので伊藤さんのブログを参考にして頑張ってみた - Qiita「Everyday Rails - RSpecによるRailsテスト入門」 とは
Railsを勉強している初学者にとって、RSpecの勉強は避けて通れない道だ。
以下の書籍は、Railsを勉強している初学者の誰もがお世話になるのではないか。Everyday Railsは、2017年度にアップデートが行われおり、RSpec3.6やRails 5.1に対応している。
とはいえ、もう2020年度である。私が6月18日付で調べると、最新版は以下のとおりであった。
- RSpec 3.9.0 - October 08, 2019
- RSpec-rails 4.0.1 - May 16, 2020
- Rails 6.0.3.2 - June 17, 2020
何となく、Rails6系で勉強したいと思う人もいるのではないだろうか。
そう考えていたところ、伊藤さんの記事を発見した。【動画付き】Everyday RailsのサンプルアプリをRails 6で動かす際に必要なテストコードの変更点 - give IT a try
私は、この記事を見つけて、軽い気持ちで「やってみよー」と思った。
だが、Rails 6でのバージョンアップをやり出したら、相当長くかかった。幸か不幸か、その過程でメモも取っていたので、それを編集して、
Qiitaという形で公開することにした。初学者なんだから、こんなブログ書かずに勉強しろという話だが、
もう書きたいという思いが強過ぎるので仕方がない。Rails 6 で本当にチャレンジする?
伊藤さんのブログでは、以下のとおり記されている。
まとめ(というか結論):Everyday Railsの基本的な内容はほとんど古くなっていません!
というわけで、この記事ではEveryday Railsのサンプルアプリケーションを
Rails 6にアップグレードした際に発生する、テストコード関連の変更点についてまとめました。Rails 5.1からRails 6にアップグレードするためにはgemのアップデート等、
いろいろな作業が必要になりますが、 テストコードだけに着目すればそれほど大きな変更点はありません。
実際、テストコードで変更する必要があるのはfactory_botの記法と、コントローラスペックの一部だけです。これはすなわち、Everyday Railsの内容が現在でもほとんど古くなっていないことを意味しています。
ですので、Everyday Railsでテストコードの書き方を学べば、Rails 6環境でも
十分しっかりしたテストを書けるようになるはずです。これからも安心してEveryday RailsをRSpecの参考書としてご活用ください!
すなわち。
Railsのバージョンを上げないと、factory_botの記法とコントローラスペックの一部だけ古い書き方になるが、
内容にほとんど変更はないからRails5.1で勉強したことが通用する、ということだ。つまり、Rails5.1でRSpecを勉強することのデメリットはほとんどないということだ。
冷静になって天秤にかけて欲しい。
初学者のみなさん、このデメリット、受け入れちゃってもよいのではないですか。受け入れたくない方はよく考えていただきたい。
それは、Rails 6 にアップグレードすることのデメリットである。このデメリットは非常にシンプルで、とにかく時間がかかるということである。
私は、無駄にこのアップグレードの戦いについてノートを取ったり、
よく分からない失敗をしてしまったというのはあるが、作業時間が14時間かかった。明らかに時間がかかり過ぎであるが、スムーズに進んだとしても6時間はみる必要があると思う。
そもそも伊藤さんのyoutube動画自体が1時間あるのだから、初学者が3時間程度で終わるはずがない。もちろん、アプリのバージョンアップは現場で必ず行うことなので、
この知見自体は役に立つものである。ただ、初学者がやるべき優先順位としては低いような気がする。
(それこそ、初学者なのでその判断もつきませんが)とりあえず、気軽な気持ちで挑戦するのは、絶対に避けましょう!
RSpecを爆速で勉強したい方は、少なくとも現時点においては、Rails5.1で頑張った方がよいです!それでもやりたい方へ
結論: youtube動画を見て、その動画のとおり作業しましょう!!!
私のように気軽に取り組もうという方は、伊藤さんが提供している以下の情報源に辿り着くはずだ。
【動画付き】Everyday RailsのサンプルアプリをRails 6で動かす際に必要なテストコードの変更点 - give IT a try
【2019年10月版】「Everyday Rails - RSpecによるRailsテスト入門」のセットアップ解説動画を作成しました - give IT a try
【Qiita記事】永久保存版!?伊藤さん式・Railsアプリのアップグレード手順
【前編】永久保存版!?伊藤さん式・Railsアプリのアップグレード手順(youtube動画)
【後編】永久保存版!?伊藤さん式・Railsアプリのアップグレード手順(youtube動画)伊藤さんがQiitaに投稿している記事は、あくまでRSpecのテストアプリを事例として扱いつつ、
Railsアプリのアップグレード手順を説明するものなので、
その性質上、細かい手順等はQiita記事内に書かれていない。私はあまりそのあたりを意識せず、Qiita記事のみを見ながらチャレンジしたので、
色々と失敗に見舞われて、最初からやり直すハメになった。知識がない人がQiita記事だけの情報でチャレンジすると、色々と勘違いをする可能性や、
Qiita記事に細かく書いていないエラーに対応できない可能性が高いだろう。(私だけですかね 笑)繰り返しになるが、youtube動画は絶対に見て、その動画のとおり作業しよう!!!
バージョンアップはしない方へ
伊藤さんが環境作成の手順をyoutube動画にして公開している。
参照してみてはどうでしょう?【2019年10月版】「Everyday Rails - RSpecによるRailsテスト入門」の環境作成手順 - YouTube
補足
「ですます調」だと単調になるので「である調」としましたが、
偉そうに感じられた方、すみません。あと、私と同じような沼にハマる初学者の方が今後発生するかもしれない
という思いでこの記事を書いていますが、伊藤さんを責める気持ちは全くありません。チェリー本も大好きです。お世話になってます。
タダにもかかわらず、ブログで積極的に情報発信してくださっているのは非常にありがたいです。あと、どうでもよいですが、バンド活動をやっていて、
ひょんなきっかけでIT業界に入ってきたにもかかわらず、
今では第一人者として情報発信されているのが不思議で仕方ありません!いつもありがとうございます!!!










