Rubyの演算でハマったこと
Rubyの演算でハマったこと
開発中にRubyの演算でとてもハマったことがあったので、備忘録としてこちらにまとめます。
下記のようなコードで具体例を示します。
((count / cookware_capacity).ceil -1) * cooking_time + cooking_total_time [1] pry(#<CalculateCookingTime>)> count => 40 [2] pry(#<CalculateCookingTime>)> cookware_capacity => 20.0 [3] pry(#<CalculateCookingTime>)> (count / cookware_capacity) => 2.0 [4] pry(#<CalculateCookingTime>)> (count / cookware_capacity).ceil => 2 [5] pry(#<CalculateCookingTime>)> ((count / cookware_capacity).ceil -1) => 10
ん?。。。
((40 / 20.0).ceil -1)
だから2 -1
になって、1になるはずなんだが。。。
実際に数値を入れて計算させると以下のようになる。
[1] pry(#<CalculateCookingTime>)> ((40 / 20.0).ceil -1) => 10
やはり10になる。。。
色々試したところ、((count / cookware_capacity).ceil -1)
の-
と1
の間にスペースを入れ忘れており、これが原因になっていた。
[1] pry(#<CalculateCookingTime>)> ((count / cookware_capacity).ceil - 1) => 1 [2] pry(#<CalculateCookingTime>)> ((40 / 20.0).ceil - 1) => 1
スペースを入れるのと入れないので、演算結果が異なる原因は分からなかったが、それで演算結果が変わるという事実を知りました!!
試しに-
の左右両方にスペースを入れずに試した結果が以下になる。
[1] pry(#<CalculateCookingTime>)> ((count / cookware_capacity).ceil-1) => 1 [2] pry(#<CalculateCookingTime>)> ((40 / 20.0).ceil-1) => 1
上記より正しい結果になることが分かった!!
マイナス-
の左右でスペースを入れたり、入れなかったりで混ぜてしまうと演算結果が正しくならないらしい。。。
herokuでのデプロイ
herokuでのデプロイ
herokuでのデプロイ時にエラーになり、つまってしまったので備忘録としてまとめます。
herokuデプロイ時のログは、以下のようになります。
-----> Building on the Heroku-22 stack -----> Determining which buildpack to use for this app ! Warning: Multiple default buildpacks reported the ability to handle this app. The first buildpack in the list below will be used. Detected buildpacks: Ruby,Node.js See https://devcenter.heroku.com/articles/buildpacks#buildpack-detect-order -----> Ruby app detected -----> Installing bundler 2.3.10 -----> Removing BUNDLED WITH version in the Gemfile.lock -----> Compiling Ruby/Rails -----> Using Ruby version: ruby-3.1.2 -----> Installing dependencies using bundler 2.3.10 Running: BUNDLE_WITHOUT='development:test' BUNDLE_PATH=vendor/bundle BUNDLE_BIN=vendor/bundle/bin BUNDLE_DEPLOYMENT=1 bundle install -j4 Fetching gem metadata from https://rubygems.org/......... Fetching rake 13.0.6 Installing rake 13.0.6 Fetching concurrent-ruby 1.1.9 Fetching thread_safe 0.3.6 Fetching minitest 5.14.4 Fetching zeitwerk 2.4.2 Installing minitest 5.14.4 Installing thread_safe 0.3.6 Installing concurrent-ruby 1.1.9 Fetching builder 3.2.4 Installing zeitwerk 2.4.2 Fetching erubi 1.10.0 Installing builder 3.2.4 Fetching mini_portile2 2.6.1 Fetching racc 1.5.2 Installing erubi 1.10.0 Installing mini_portile2 2.6.1 Fetching crass 1.0.6 Fetching rack 2.2.3 Fetching nio4r 2.5.8 Installing rack 2.2.3 Installing crass 1.0.6 Fetching websocket-extensions 0.1.5 Installing racc 1.5.2 with native extensions Installing nio4r 2.5.8 with native extensions Installing websocket-extensions 0.1.5 Fetching marcel 1.0.2 Installing marcel 1.0.2 Fetching mini_mime 1.1.1 Fetching bcrypt 3.1.17 Installing mini_mime 1.1.1 Installing bcrypt 3.1.17 with native extensions Fetching msgpack 1.4.2 Installing msgpack 1.4.2 with native extensions Using bundler 2.3.10 Fetching coderay 1.1.3 Installing coderay 1.1.3 Using digest 3.1.0 Fetching faraday-em_http 1.0.0 Installing faraday-em_http 1.0.0 Fetching faraday-em_synchrony 1.0.0 Installing faraday-em_synchrony 1.0.0 Fetching faraday-excon 1.1.0 Installing faraday-excon 1.1.0 Fetching faraday-httpclient 1.0.1 Installing faraday-httpclient 1.0.1 Fetching multipart-post 2.1.1 Fetching faraday-net_http 1.0.1 Installing multipart-post 2.1.1 Installing faraday-net_http 1.0.1 Fetching faraday-net_http_persistent 1.2.0 Fetching faraday-patron 1.0.0 Installing faraday-net_http_persistent 1.2.0 Fetching faraday-rack 1.0.0 Installing faraday-patron 1.0.0 Fetching faraday-retry 1.0.3 Installing faraday-rack 1.0.0 Using ruby2_keywords 0.0.5 Fetching ffi 1.15.4 Installing faraday-retry 1.0.3 Fetching hpricot 0.8.6 Installing hpricot 0.8.6 with native extensions Installing ffi 1.15.4 with native extensions Fetching mini_magick 4.11.0 Installing mini_magick 4.11.0 Fetching jwt 2.3.0 Installing jwt 2.3.0 Fetching kaminari-core 1.2.2 Installing kaminari-core 1.2.2 Fetching matrix 0.4.2 Installing matrix 0.4.2 Fetching method_source 1.0.0 Installing method_source 1.0.0 Fetching multi_json 1.15.0 Installing multi_json 1.15.0 Fetching multi_xml 0.6.0 Installing multi_xml 0.6.0 Fetching timeout 0.3.0 Installing timeout 0.3.0 Fetching oauth 0.5.8 Installing oauth 0.5.8 Fetching pg 1.4.3 Installing pg 1.4.3 with native extensions Fetching psych 3.3.3 Installing psych 3.3.3 with native extensions Fetching thor 1.1.0 Installing thor 1.1.0 Fetching tilt 2.0.10 Installing tilt 2.0.10 Fetching temple 0.8.2 Installing temple 0.8.2 Fetching tzinfo 1.2.9 Installing tzinfo 1.2.9 Fetching i18n 1.8.10 Installing i18n 1.8.10 Fetching websocket-driver 0.7.5 Installing websocket-driver 0.7.5 with native extensions Fetching rack-test 1.1.0 Installing rack-test 1.1.0 Fetching rack-proxy 0.7.0 Installing rack-proxy 0.7.0 Fetching sprockets 4.0.2 Installing sprockets 4.0.2 Fetching mail 2.7.1 Installing mail 2.7.1 Fetching nokogiri 1.12.5 Installing nokogiri 1.12.5 with native extensions Fetching faraday-multipart 1.0.3 Installing faraday-multipart 1.0.3 Fetching puma 4.3.8 Installing puma 4.3.8 with native extensions Fetching pry 0.14.1 Installing pry 0.14.1 Fetching net-protocol 0.1.3 Installing net-protocol 0.1.3 Fetching bootsnap 1.9.1 Installing bootsnap 1.9.1 with native extensions Fetching slim 4.1.0 Installing slim 4.1.0 Fetching activesupport 6.0.4.1 Installing activesupport 6.0.4.1 Fetching ruby-vips 2.1.4 Installing ruby-vips 2.1.4 Fetching sassc 2.4.0 Installing sassc 2.4.0 with native extensions Fetching faraday 1.10.0 Installing faraday 1.10.0 Fetching pry-rails 0.3.9 Installing pry-rails 0.3.9 Fetching net-smtp 0.3.1 Installing net-smtp 0.3.1 Fetching globalid 0.5.2 Installing globalid 0.5.2 Fetching activemodel 6.0.4.1 Installing activemodel 6.0.4.1 Fetching jbuilder 2.11.2 Installing jbuilder 2.11.2 Fetching image_processing 1.12.2 Installing image_processing 1.12.2 Fetching oauth2 1.4.9 Installing oauth2 1.4.9 Fetching activejob 6.0.4.1 Installing activejob 6.0.4.1 Fetching activerecord 6.0.4.1 Installing activerecord 6.0.4.1 Fetching sorcery 0.16.3 Installing sorcery 0.16.3 Fetching kaminari-activerecord 1.2.2 Installing kaminari-activerecord 1.2.2 Fetching ransack 2.4.1 Installing ransack 2.4.1 Fetching html2slim 0.2.0 Installing html2slim 0.2.0 Fetching rails-dom-testing 2.0.3 Fetching loofah 2.12.0 Installing loofah 2.12.0 Installing rails-dom-testing 2.0.3 Fetching rails-html-sanitizer 1.4.2 Installing rails-html-sanitizer 1.4.2 Fetching actionview 6.0.4.1 Installing actionview 6.0.4.1 Fetching actionpack 6.0.4.1 Fetching kaminari-actionview 1.2.2 Installing kaminari-actionview 1.2.2 Fetching kaminari 1.2.2 Installing actionpack 6.0.4.1 Installing kaminari 1.2.2 Fetching actionmailer 6.0.4.1 Fetching activestorage 6.0.4.1 Fetching actioncable 6.0.4.1 Installing actionmailer 6.0.4.1 Installing activestorage 6.0.4.1 Installing actioncable 6.0.4.1 Fetching railties 6.0.4.1 Fetching sprockets-rails 3.2.2 Fetching actionmailbox 6.0.4.1 Installing railties 6.0.4.1 Installing sprockets-rails 3.2.2 Fetching actiontext 6.0.4.1 Installing actionmailbox 6.0.4.1 Installing actiontext 6.0.4.1 Fetching rails 6.0.4.1 Fetching rails-i18n 6.0.0 Fetching slim-rails 3.3.0 Installing rails 6.0.4.1 Installing slim-rails 3.3.0 Fetching webpacker 4.3.0 Installing rails-i18n 6.0.0 Installing webpacker 4.3.0 Fetching sassc-rails 2.1.2 Installing sassc-rails 2.1.2 Fetching sass-rails 6.0.0 Installing sass-rails 6.0.0 Bundle complete! 32 Gemfile dependencies, 98 gems now installed. Gems in the groups 'development' and 'test' were not installed. Bundled gems are installed into `./vendor/bundle` Post-install message from sorcery: As of version 1.0 oauth/oauth2 won't be automatically bundled so you may need to add those dependencies to your Gemfile. You may need oauth2 if you use external providers such as any of these: https://github.com/Sorcery/sorcery/tree/master/lib/sorcery/providers Bundle completed (115.74s) Cleaning up the bundler cache. -----> Installing node-v16.13.1-linux-x64 -----> Installing yarn-v1.22.17 -----> Detecting rake tasks -----> Preparing app for Rails asset pipeline Running: rake assets:precompile Calling `DidYouMean::SPELL_CHECKERS.merge!(error_name => spell_checker)' has been deprecated. Please call `DidYouMean.correct_error(error_name, spell_checker)' instead. yarn install v1.22.17 [1/4] Resolving packages... [2/4] Fetching packages... [3/4] Linking dependencies... warning " > webpack-dev-server@4.10.1" has unmet peer dependency "webpack@^4.37.0 || ^5.0.0". warning "webpack-dev-server > webpack-dev-middleware@5.3.3" has unmet peer dependency "webpack@^4.0.0 || ^5.0.0". [4/4] Building fresh packages... error /tmp/build_fa395875/node_modules/node-sass: Command failed. ① Exit code: 1 Command: node scripts/build.js Arguments: Directory: /tmp/build_fa395875/node_modules/node-sass Output: Building: /tmp/build_fa395875/bin/node /tmp/build_fa395875/node_modules/node-gyp/bin/node-gyp.js rebuild --verbose --libsass_ext= --libsass_cflags= --libsass_ldflags= --libsass_library= gyp info it worked if it ends with ok gyp verb cli [ gyp verb cli '/tmp/build_fa395875/bin/node', gyp verb cli '/tmp/build_fa395875/node_modules/node-gyp/bin/node-gyp.js', gyp verb cli 'rebuild', gyp verb cli '--verbose', gyp verb cli '--libsass_ext=', gyp verb cli '--libsass_cflags=', gyp verb cli '--libsass_ldflags=', gyp verb cli '--libsass_library=' gyp verb cli ] gyp info using node-gyp@3.8.0 gyp info using node@16.13.1 | linux | x64 gyp verb command rebuild [] gyp verb command clean [] gyp verb clean removing "build" directory gyp verb command configure [] gyp verb check python checking for Python executable "python2" in the PATH gyp verb `which` failed Error: not found: python2 gyp verb `which` failed at getNotFoundError (/tmp/build_fa395875/node_modules/which/which.js:13:12) gyp verb `which` failed at F (/tmp/build_fa395875/node_modules/which/which.js:68:19) gyp verb `which` failed at E (/tmp/build_fa395875/node_modules/which/which.js:80:29) gyp verb `which` failed at /tmp/build_fa395875/node_modules/which/which.js:89:16 gyp verb `which` failed at /tmp/build_fa395875/node_modules/isexe/index.js:42:5 gyp verb `which` failed at /tmp/build_fa395875/node_modules/isexe/mode.js:8:5 gyp verb `which` failed at FSReqCallback.oncomplete (node:fs:198:21) gyp verb `which` failed python2 Error: not found: python2 gyp verb `which` failed at getNotFoundError (/tmp/build_fa395875/node_modules/which/which.js:13:12) gyp verb `which` failed at F (/tmp/build_fa395875/node_modules/which/which.js:68:19) gyp verb `which` failed at E (/tmp/build_fa395875/node_modules/which/which.js:80:29) gyp verb `which` failed at /tmp/build_fa395875/node_modules/which/which.js:89:16 gyp verb `which` failed at /tmp/build_fa395875/node_modules/isexe/index.js:42:5 gyp verb `which` failed at /tmp/build_fa395875/node_modules/isexe/mode.js:8:5 gyp verb `which` failed at FSReqCallback.oncomplete (node:fs:198:21) { gyp verb `which` failed code: 'ENOENT' gyp verb `which` failed } gyp verb check python checking for Python executable "python" in the PATH gyp verb `which` succeeded python /usr/bin/python gyp ERR! configure error gyp ERR! stack Error: Command failed: /usr/bin/python -c import sys; print "%s.%s.%s" % sys.version_info[:3]; gyp ERR! stack File "<string>", line 1 gyp ERR! stack import sys; print "%s.%s.%s" % sys.version_info[:3]; gyp ERR! stack ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ gyp ERR! stack SyntaxError: Missing parentheses in call to 'print'. Did you mean print(...)? gyp ERR! stack gyp ERR! stack at ChildProcess.exithandler (node:child_process:397:12) gyp ERR! stack at ChildProcess.emit (node:events:390:28) gyp ERR! stack at maybeClose (node:internal/child_process:1064:16) gyp ERR! stack at Process.ChildProcess._handle.onexit (node:internal/child_process:301:5) gyp ERR! System Linux 4.4.0-1104-aws gyp ERR! command "/tmp/build_fa395875/bin/node" "/tmp/build_fa395875/node_modules/node-gyp/bin/node-gyp.js" "rebuild" "--verbose" "--libsass_ext=" "--libsass_cflags=" "--libsass_ldflags=" "--libsass_library=" gyp ERR! cwd /tmp/build_fa395875/node_modules/node-sass gyp ERR! node -v v16.13.1 gyp ERR! node-gyp -v v3.8.0 gyp ERR! not ok Build failed with error code: 1 info Visit https://yarnpkg.com/en/docs/cli/install for documentation about this command. ! ! Precompiling assets failed. ! ! Push rejected, failed to compile Ruby app. ! Push failed
ログがすごい長いけど①が怪しい。。。
node-sassのコマンドが失敗したとのことで、これ関係のエラーをググってみると、nodeとnode-sassのバージョンの違いによるものとの事で、以下で解決できました。
①webpackerのバージョンアップ
- gem 'webpacker', '~> 4.0' + gem 'webpacker', '~> 5.0'
②yarn.lockの削除
ファイルを削除する
③package.jsonで以下のようにwebpackerのバージョンを指定
"@rails/webpacker": "5.4.3",
④yarn installを実行
$ yarn install
⑤node-sassのバージョンをnode.jsに合わせる
$ yarn add node-sass
⑥再度デプロイ
$ git push heroku main
※ポイント
・herokuにデプロイするとGemfile.lock
のBUNDLED WITH
が削除されて、heroku指定のBundlerのバージョンが使われる。(自分でbundlerのバージョン指定はできない)
そのため、ローカル環境とheroku環境でbundlerのバージョンが異なるが、bundlerのバージョンの違いによる不具合は、基本的に起こらないとのこと。
・herokuのログは、以下のようにheroku画面でも確認できる
①以下のDashboardをクリック
↓
↓
↓
④以下のLatest activityにログが記載されている
参考記事
RailsをHerokuにデプロイするときのBundlerバージョン(2020年版)|TechRacho by BPS株式会社
【heroku】herokuにてデプロイエラー【The engine "node" is incompatible with this..】
rubocopの設定
rubocopの設定
rubocopの設定方法がイマイチ分からず調べたので、こちらに備忘録として残します。
rubocopでは、最初からLintチェックのレベルが設定されているが特定のファイルだけLintチェックを行わないようにしたい場合がある。(特定のファイルのみどうしてもLintチェックを通過するようにコードを書けない場合など。。)
そんな時に、そのファイルのみ特定のLintチェックをパスするようにする方法を以下に示します。
以下のように記載することで特定のLintチェックを指定したファイルでパスするようにできます。
[.rubocop.yml] inherit_from: .rubocop_todo.yml AllCops: TargetRubyVersion: 2.5 # 除外 Exclude: - 'bin/**' - 'lib/**' - 'db/migrate/*' - 'db/schema.rb' - 'config/puma.rb' - 'config/spring.rb' - 'config/application.rb' - 'config/environments/*' - 'config/initializers/*' - 'script/**/*' - 'node_modules/**/*' - Gemfile - 'vendor/**/*' - 'spec/**/*' CyclomaticComplexity: # ① Exclude: - 'app/forms/calculate_cooking_time.rb'
①を記載しないと以下のようになる。
% rubocop The following cops were added to RuboCop, but are not configured. Please set Enabled to either `true` or `false` in your `.rubocop.yml` file. Please also note that you can opt-in to new cops by default by adding this to your config: AllCops: NewCops: enable Gemspec/DateAssignment: # new in 1.10 Enabled: true Layout/LineEndStringConcatenationIndentation: # new in 1.18 Enabled: true Layout/SpaceBeforeBrackets: # new in 1.7 Enabled: true Lint/AmbiguousAssignment: # new in 1.7 Enabled: true Lint/AmbiguousOperatorPrecedence: # new in 1.21 Enabled: true Lint/AmbiguousRange: # new in 1.19 Enabled: true Lint/DeprecatedConstants: # new in 1.8 Enabled: true Lint/DuplicateBranch: # new in 1.3 Enabled: true Lint/DuplicateRegexpCharacterClassElement: # new in 1.1 Enabled: true Lint/EmptyBlock: # new in 1.1 Enabled: true Lint/EmptyClass: # new in 1.3 Enabled: true Lint/EmptyInPattern: # new in 1.16 Enabled: true Lint/IncompatibleIoSelectWithFiberScheduler: # new in 1.21 Enabled: true Lint/LambdaWithoutLiteralBlock: # new in 1.8 Enabled: true Lint/NoReturnInBeginEndBlocks: # new in 1.2 Enabled: true Lint/NumberedParameterAssignment: # new in 1.9 Enabled: true Lint/OrAssignmentToConstant: # new in 1.9 Enabled: true Lint/RedundantDirGlobSort: # new in 1.8 Enabled: true Lint/RequireRelativeSelfPath: # new in 1.22 Enabled: true Lint/SymbolConversion: # new in 1.9 Enabled: true Lint/ToEnumArguments: # new in 1.1 Enabled: true Lint/TripleQuotes: # new in 1.9 Enabled: true Lint/UnexpectedBlockArity: # new in 1.5 Enabled: true Lint/UnmodifiedReduceAccumulator: # new in 1.1 Enabled: true Security/IoMethods: # new in 1.22 Enabled: true Style/ArgumentsForwarding: # new in 1.1 Enabled: true Style/CollectionCompact: # new in 1.2 Enabled: true Style/DocumentDynamicEvalDefinition: # new in 1.1 Enabled: true Style/EndlessMethod: # new in 1.8 Enabled: true Style/HashConversion: # new in 1.10 Enabled: true Style/HashExcept: # new in 1.7 Enabled: true Style/IfWithBooleanLiteralBranches: # new in 1.9 Enabled: true Style/InPatternThen: # new in 1.16 Enabled: true Style/MultilineInPatternThen: # new in 1.16 Enabled: true Style/NegatedIfElseCondition: # new in 1.2 Enabled: true Style/NilLambda: # new in 1.3 Enabled: true Style/NumberedParameters: # new in 1.22 Enabled: true Style/NumberedParametersLimit: # new in 1.22 Enabled: true Style/QuotedSymbols: # new in 1.16 Enabled: true Style/RedundantArgument: # new in 1.4 Enabled: true Style/RedundantSelfAssignmentBranch: # new in 1.19 Enabled: true Style/SelectByRegexp: # new in 1.22 Enabled: true Style/StringChars: # new in 1.12 Enabled: true Style/SwapValues: # new in 1.1 Enabled: true For more information: https://docs.rubocop.org/rubocop/versioning.html Inspecting 31 files ..........C.................... Offenses: app/forms/calculate_cooking_time.rb:18:3: C: Metrics/PerceivedComplexity: Perceived complexity for calculate_cooking_total_time is too high. [27/8] ② def calculate_cooking_total_time ... ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 31 files inspected, 1 offense detected
Metrics/PerceivedComplexity
のLintチェックに引っかかる。
②のMetrics/PerceivedComplexity
を.rubocop.yml
に記載して除外ファイルを設定することで、このファイルではMetrics/PerceivedComplexity
のLintチェックが行われなくなる。
外部キーにnullを入れる方法
外部キーにnullを入れる方法
1対多
の関係で、通常通り外部キーを持つレコードと外部キーを持たないレコードがある時に外部キーにnullを入れる方法を
備忘録としてこちらにまとめます。
以下のようなアソシエーション関係のモデルがあります。
[app/models/cookware.rb] class Cookware < ApplicationRecord has_many :cooking_informations end
[app/models/cook_information.rb] class CookingInformation < ApplicationRecord belongs_to :cookware, optional: true end
cook_information
のレコードには、外部キーのcookware_id
が入るレコードと入らないレコードがあります。
そんな時は、optional: true
オプションを付与することで外部キーにnullを許容することができます。
参考記事
メーラーのRSpecテスト
メーラーのRSpecテストでハマったことがあったので、備忘録としてこちらにまとめます。
コードは、以下のようになります。
[app/mailers/user_mailer.rb] class UserMailer < ApplicationMailer # Subject can be set in your I18n file at config/locales/en.yml # with the following lookup: # # en.user_mailer.reset_password_email.subject # def reset_password_email(user) @user = User.find user.id @url = edit_password_reset_url(@user.reset_password_token) mail(:to => user.email, :subject => "パスワード再発行のお知らせ") end end
[app/views/user_mailer/reset_password_email.html.slim] doctype html html head meta[content="text/html; charset=UTF-8" http-equiv="Content-Type"] body p = "#{@user.name} 様" p パスワード再発行の依頼を受け付けました。 p こちらのリンクからパスワードの再発行を行ってください。 p = link_to nil, @url
[app/views/user_mailer/reset_password_email.text.slim] = "#{@user.name} 様" パスワード再発行の依頼を受け付けました。 こちらのリンクからパスワードの再発行を行ってください。 = @url
[app/mailers/user_mailer_spec.rb] require "rails_helper" RSpec.describe UserMailer, type: :mailer do describe 'パスワードリセットのメール送信の検証' do let(:user) { create(:user) } let(:mail) { UserMailer.reset_password_email(user) } before do user.generate_reset_password_token! mail.deliver_now end context 'メールを送信した時' do it 'ヘッダー情報,ボディ情報が正しい' do expect(mail.subject).to eq 'パスワード再発行のお知らせ' expect(mail.to).to eq [user.email] expect(mail.from).to eq ['from@example.com'] end it 'メール本文が正しい' do expect(mail.html_part.body.to_s).to have_content "#{user.name} 様" expect(mail.html_part.body.to_s).to have_content 'パスワード再発行の依頼を受け付けました。' expect(mail.html_part.body.to_s).to have_content 'こちらのリンクからパスワードの再発行を行ってください。' expect(mail.html_part.body.to_s).to have_content "http://localhost:3000/password_resets/#{user.reset_password_token}/edit" expect(mail.text_part.body.to_s).to have_content "#{user.name} 様" expect(mail.text_part.body.to_s).to have_content 'パスワード再発行の依頼を受け付けました。' expect(mail.text_part.body.to_s).to have_content 'こちらのリンクからパスワードの再発行を行ってください。' expect(mail.text_part.body.to_s).to have_content "http://localhost:3000/password_resets/#{user.reset_password_token}/edit" end end end end
上記のテストを実行すると以下のようなエラーになります。
higmonta@higuchiyuunoMBP fishing_cooking % bundle exec rspec spec/mailers/user_mailer_spec.rb DEPRECATION WARNING: Initialization autoloaded the constants ActionText::ContentHelper and ActionText::TagHelper. Being able to do this is deprecated. Autoloading during initialization is going to be an error condition in future versions of Rails. Reloading does not reboot the application, and therefore code executed during initialization does not run again. So, if you reload ActionText::ContentHelper, for example, the expected changes won't be reflected in that stale Module object. These autoloaded constants have been unloaded. Please, check the "Autoloading and Reloading Constants" guide for solutions. (called from <top (required)> at /Users/higmonta/workspace/fishing_cooking/config/environment.rb:5) UserMailer パスワードリセットのメール送信の検証 メールを送信した時 ヘッダー情報,ボディ情報が正しい メール本文が正しい (FAILED - 1) Failures: 1) UserMailer パスワードリセットのメール送信の検証 メールを送信した時 メール本文が正しい Failure/Error: expect(mail.text_part.body.to_s).to have_content 'パスワード再発行の依頼を受け付けました。' expected to find text "パスワード再発行の依頼を受け付けました。" in "大野 莉子 様。パスワード再発行の依頼を受け付けました>。こちらのリンクからパスワードの再発行を行ってください>http://localhost:3000/password_resets/hf6PPCGouyRVPfAzi3i3/edit" # ./spec/mailers/user_mailer_spec.rb:25:in `block (4 levels) in <top (required)>' Finished in 0.36584 seconds (files took 3.99 seconds to load) 2 examples, 1 failure Failed examples: rspec ./spec/mailers/user_mailer_spec.rb:19 # UserMailer パスワードリセットのメール送信の検証 メールを送信した時 メール本文が正しい
デバッグして確認してみます。
higmonta@higuchiyuunoMBP fishing_cooking % bundle exec rspec spec/mailers/user_mailer_spec.rb DEPRECATION WARNING: Initialization autoloaded the constants ActionText::ContentHelper and ActionText::TagHelper. Being able to do this is deprecated. Autoloading during initialization is going to be an error condition in future versions of Rails. Reloading does not reboot the application, and therefore code executed during initialization does not run again. So, if you reload ActionText::ContentHelper, for example, the expected changes won't be reflected in that stale Module object. These autoloaded constants have been unloaded. Please, check the "Autoloading and Reloading Constants" guide for solutions. (called from <top (required)> at /Users/higmonta/workspace/fishing_cooking/config/environment.rb:5) UserMailer パスワードリセットのメール送信の検証 メールを送信した時 ヘッダー情報,ボディ情報が正しい ^A^BFrom:^A^B /Users/higmonta/workspace/fishing_cooking/spec/mailers/user_mailer_spec.rb:24 : 19: it 'メール本文が正しい' do 20: expect(mail.html_part.body.to_s).to have_content "#{user.name} 様" 21: expect(mail.html_part.body.to_s).to have_content 'パスワード再発行の依頼を受け付けました。' 22: expect(mail.html_part.body.to_s).to have_content 'こちらのリンクからパスワードの再発行を行ってください。' 23: expect(mail.html_part.body.to_s).to have_content "http://localhost:3000/password_resets/#{user.reset_password_token}/edit" => 24: binding.pry 25: expect(mail.text_part.body.to_s).to have_content "#{user.name} 様" 26: expect(mail.text_part.body.to_s).to have_content 'パスワード再発行の依頼を受け付けました。' 27: expect(mail.text_part.body.to_s).to have_content 'こちらのリンクからパスワードの再発行を行ってください。' 28: expect(mail.text_part.body.to_s).to have_content "http://localhost:3000/password_resets/#{user.reset_password_token}/edit" 29: end [1] pry(#<RSpec::ExampleGroups::UserMailer::Nested::Nested>)> mail.html_part.body.to_s => "<!DOCTYPE html><html><head><meta content=\"text/html; charset=utf-8\" http-equiv=\"Content-Type\" /><style> /* Email styles need to be inline */ </style></head><body><!DOCTYPE html><html><head><meta content=\"text/html; charset=UTF-8\" http-equiv=\"Content-Type\" /></head><body><p>村上 美穂 様</p><p>パスワード再発行の依頼を受け付けました。</p><p>こちらのリンクからパスワードの再発行を行ってください。</p><p><a href=\"http://localhost:3000/password_resets/BtLzvHUukixrNqAQoJJx/edit\">http://localhost:3000/password_resets/BtLzvHUukixrNqAQoJJx/edit</a></p></body></html></body></html>" [2] pry(#<RSpec::ExampleGroups::UserMailer::Nested::Nested>)> mail.text_part.body.to_s => "村上 美穂 様<パスワード再発行の依頼を受け付けました>。</パスワード再発行の依頼を受け付けました><こちらのリンクからパスワードの再発行を行ってください>。</こちらのリンクからパスワードの再発行を行ってください>http://localhost:3000/password_resets/BtLzvHUukixrNqAQoJJx/edit" [3] pry(#<RSpec::ExampleGroups::UserMailer::Nested::Nested>)> expect(mail.text_part.body.to_s).to have_content "#{user.name} 様" => true [4] pry(#<RSpec::ExampleGroups::UserMailer::Nested::Nested>)> expect(mail.text_part.body.to_s).to have_content 'パスワード再発行の依頼を受け付けました [4] pry(#<RSpec::ExampleGroups::UserMailer::Nested::Nested>)> expect(mail.text_part.body.to_s).to have_content 'パスワード再発行の依頼を受け付けました。' RSpec::Expectations::ExpectationNotMetError: expected to find text "パスワード再発行の依頼を受け付けました。" in "村上 美穂 様。パスワード再発行の依頼を受け付けました>。こちらのリンクからパスワードの再発行を行ってください>http://localhost:3000/password_resets/BtLzvHUukixrNqAQoJJx/edit" from /Users/higmonta/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/rspec-support-3.11.0/lib/rspec/support.rb:102:in `block in <module:Support>' [5] pry(#<RSpec::ExampleGroups::UserMailer::Nested::Nested>)> expect(mail.text_part.body.to_s).to have_content 'こちらのリンクからパスワードの再発行を [5] pry(#<RSpec::ExampleGroups::UserMailer::Nested::Nested>)> expect(mail.text_part.body.to_s).to have_content 'こちらのリンクからパスワードの再発行を行ってください。' RSpec::Expectations::ExpectationNotMetError: expected to find text "こちらのリンクからパスワードの再発行を行ってください。" in "村上 美穂 様。パスワード再発行の依頼を受け付けました>。こちらのリンクからパスワードの再発行を行ってください>http://localhost:3000/password_resets/BtLzvHUukixrNqAQoJJx/edit" from /Users/higmonta/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/rspec-support-3.11.0/lib/rspec/support.rb:102:in `block in <module:Support>' [6] pry(#<RSpec::ExampleGroups::UserMailer::Nested::Nested>)> expect(mail.text_part.body.to_s).to have_content "http://localhost:3000/password_resets/#{user.reset_password_token}/edit"n}/edit" => true
下記2つだけがエラーになっています。(ユーザー名の文章部分とURLの部分はエラーになっていません。)
expect(mail.text_part.body.to_s).to have_content 'パスワード再発行の依頼を受け付けました。'
expect(mail.text_part.body.to_s).to have_content 'こちらのリンクからパスワードの再発行を行ってください。'
下記のように期待している文章が入っているのでエラーにならないはずだが。。。。
[2] pry(#<RSpec::ExampleGroups::UserMailer::Nested::Nested>)> mail.text_part.body.to_s => "村上 美穂 様<パスワード再発行の依頼を受け付けました>。</パスワード再発行の依頼を受け付けました><こちらのリンクからパスワードの再発行を行ってください>。</こちらのリンクからパスワードの再発行を行ってください>http://localhost:3000/password_resets/BtLzvHUukixrNqAQoJJx/edit"
上記を確認するとエラーになっている文章の部分だけ<
や</
や>
が入っており、これに問題がありそうと考えました。
そもそも、なぜここの文章だけが<
や</
や>
が入っているのか再度メールのビューを確認しました。
[app/views/user_mailer/reset_password_email.text.slim] = "#{@user.name} 様" パスワード再発行の依頼を受け付けました。 ① こちらのリンクからパスワードの再発行を行ってください。 ② = @url
そもそもこれってslim形式→text形式に変換されるファイルなはずなのだが、①、②にhtmlタグを記載せずに文章だけ書いてしまっている。(textのように記載してしまっている。)
下記のように編集したところ、テストが通りました。
p = "#{@user.name} 様" p パスワード再発行の依頼を受け付けました。 p こちらのリンクからパスワードの再発行を行ってください。 p = @url
デバッグで確認したら以下のようになり、<
や</
や>
が無くなっていました。
higmonta@higuchiyuunoMBP fishing_cooking % bundle exec rspec spec/mailers/user_mailer_spec.rb DEPRECATION WARNING: Initialization autoloaded the constants ActionText::ContentHelper and ActionText::TagHelper. Being able to do this is deprecated. Autoloading during initialization is going to be an error condition in future versions of Rails. Reloading does not reboot the application, and therefore code executed during initialization does not run again. So, if you reload ActionText::ContentHelper, for example, the expected changes won't be reflected in that stale Module object. These autoloaded constants have been unloaded. Please, check the "Autoloading and Reloading Constants" guide for solutions. (called from <top (required)> at /Users/higmonta/workspace/fishing_cooking/config/environment.rb:5) UserMailer パスワードリセットのメール送信の検証 メールを送信した時 ヘッダー情報,ボディ情報が正しい ^A^BFrom:^A^B /Users/higmonta/workspace/fishing_cooking/spec/mailers/user_mailer_spec.rb:24 : 19: it 'メール本文が正しい' do 20: expect(mail.html_part.body.to_s).to have_content "#{user.name} 様" 21: expect(mail.html_part.body.to_s).to have_content 'パスワード再発行の依頼を受け付けました。' 22: expect(mail.html_part.body.to_s).to have_content 'こちらのリンクからパスワードの再発行を行ってください。' 23: expect(mail.html_part.body.to_s).to have_content "http://localhost:3000/password_resets/#{user.reset_password_token}/edit" => 24: binding.pry 25: expect(mail.text_part.body.to_s).to have_content "#{user.name} 様" 26: expect(mail.text_part.body.to_s).to have_content 'パスワード再発行の依頼を受け付けました。' 27: expect(mail.text_part.body.to_s).to have_content 'こちらのリンクからパスワードの再発行を行ってください。' 28: expect(mail.text_part.body.to_s).to have_content "http://localhost:3000/password_resets/#{user.reset_password_token}/edit" 29: end [1] pry(#<RSpec::ExampleGroups::UserMailer::Nested::Nested>)> mail.text_part.body.to_s => "<p>酒井 仁 様</p><p>パスワード再発行の依頼を受け付けました。</p><p>こちらのリンクからパスワードの再発行を行ってください。</p><p>http://localhost:3000/password_resets/mwxXk4h9vCMZfHwvXnRz/edit</p>" [2] pry(#<RSpec::ExampleGroups::UserMailer::Nested::Nested>)> expect(mail.text_part.body.to_s).to have_content "#{user.name} 様"ame} 様" => true [3] pry(#<RSpec::ExampleGroups::UserMailer::Nested::Nested>)> expect(mail.text_part.body.to_s).to have_content 'パスワード再発行の依頼を受け付けました [3] pry(#<RSpec::ExampleGroups::UserMailer::Nested::Nested>)> expect(mail.text_part.body.to_s).to have_content 'パスワード再発行の依頼を受け付けました。' => true [4] pry(#<RSpec::ExampleGroups::UserMailer::Nested::Nested>)> expect(mail.text_part.body.to_s).to have_content 'こちらのリンクからパスワードの再発行を [4] pry(#<RSpec::ExampleGroups::UserMailer::Nested::Nested>)> expect(mail.text_part.body.to_s).to have_content 'こちらのリンクからパスワードの再発行を行ってください。' => true [5] pry(#<RSpec::ExampleGroups::UserMailer::Nested::Nested>)> expect(mail.text_part.body.to_s).to have_content "http://localhost:3000/password_resets/#{user.reset_password_token}/edit" => true
※ポイント
mail.html_part.body.to_s
:マルチパートメールにしている場合にhtml形式のメール本文の検証ができる。
mail.text_part.body.to_s
:マルチパートメールにしている場合にtext形式のメール本文の検証ができる。
それぞれのメソッドがどのような動きになっているのか気になったので、デバッグして確認した結果が以下になります。
higmonta@higuchiyuunoMBP fishing_cooking % bundle exec rspec spec/mailers/user_mailer_spec.rb DEPRECATION WARNING: Initialization autoloaded the constants ActionText::ContentHelper and ActionText::TagHelper. Being able to do this is deprecated. Autoloading during initialization is going to be an error condition in future versions of Rails. Reloading does not reboot the application, and therefore code executed during initialization does not run again. So, if you reload ActionText::ContentHelper, for example, the expected changes won't be reflected in that stale Module object. These autoloaded constants have been unloaded. Please, check the "Autoloading and Reloading Constants" guide for solutions. (called from <top (required)> at /Users/higmonta/workspace/fishing_cooking/config/environment.rb:5) UserMailer パスワードリセットのメール送信の検証 メールを送信した時 ヘッダー情報,ボディ情報が正しい ^A^BFrom:^A^B /Users/higmonta/workspace/fishing_cooking/spec/mailers/user_mailer_spec.rb:24 : 19: it 'メール本文が正しい' do 20: expect(mail.html_part.body.to_s).to have_content "#{user.name} 様" 21: expect(mail.html_part.body.to_s).to have_content 'パスワード再発行の依頼を受け付けました。' 22: expect(mail.html_part.body.to_s).to have_content 'こちらのリンクからパスワードの再発行を行ってください。' 23: expect(mail.html_part.body.to_s).to have_content "http://localhost:3000/password_resets/#{user.reset_password_token}/edit" => 24: binding.pry 25: expect(mail.text_part.body.to_s).to have_content "#{user.name} 様" 26: expect(mail.text_part.body.to_s).to have_content 'パスワード再発行の依頼を受け付けました。' 27: expect(mail.text_part.body.to_s).to have_content 'こちらのリンクからパスワードの再発行を行ってください。' 28: expect(mail.text_part.body.to_s).to have_content "http://localhost:3000/password_resets/#{user.reset_password_token}/edit" 29: end [1] pry(#<RSpec::ExampleGroups::UserMailer::Nested::Nested>)> mail => #<Mail::Message:70296108227480, Multipart: true, Headers: <Date: Sun, 11 Sep 2022 04:46:08 +0900>, <From: from@example.com>, <To: delmer_brekke@hudson-hilll.co>, <Message-ID: <631ce980c1322_1665e3fef12436e6c5881e@higuchiyuunoMBP.mail>>, <Subject: パスワード再発行のお知らせ>, <Mime-Version: 1.0>, <Content-Type: multipart/alternative; boundary="--==_mimepart_631ce980c0d0a_1665e3fef12436e6c5879e"; charset=UTF-8>, <Content-Transfer-Encoding: 7bit>> [2] pry(#<RSpec::ExampleGroups::UserMailer::Nested::Nested>)> mail.html_part => #<Mail::Part:70296108194240, Multipart: false, Headers: <Content-Type: text/html>, <Content-Transfer-Encoding: base64>> [3] pry(#<RSpec::ExampleGroups::UserMailer::Nested::Nested>)> mail.html_part.body => #<Mail::Body:0x00007fde2d1d1f88 @ascii_only=false, @boundary=nil, @charset=nil, @encoding="8bit", @epilogue=nil, @part_sort_order=["text/plain", "text/enriched", "text/html"], @parts=[], @preamble=nil, @raw_source= "<!DOCTYPE html><html><head><meta content=\"text/html; charset=utf-8\" http-equiv=\"Content-Type\" /><style> /* Email styles need to be inline */ </style></head><body><!DOCTYPE html><html><head><meta content=\"text/html; charset=UTF-8\" http-equiv=\"Content-Type\" /></head><body><p>千葉 一輝 様</p><p>パスワード再発行の依頼を受け付けました。</p><p>こちらのリンクからパスワードの再発行を行ってください。</p><p><a href=\"http://localhost:3000/password_resets/xyD6ASVsM1w6G-gXedCS/edit\">http://localhost:3000/password_resets/xyD6ASVsM1w6G-gXedCS/edit</a></p></body></html></body></html>"> [4] pry(#<RSpec::ExampleGroups::UserMailer::Nested::Nested>)> mail.html_part.body.to_s => "<!DOCTYPE html><html><head><meta content=\"text/html; charset=utf-8\" http-equiv=\"Content-Type\" /><style> /* Email styles need to be inline */ </style></head><body><!DOCTYPE html><html><head><meta content=\"text/html; charset=UTF-8\" http-equiv=\"Content-Type\" /></head><body><p>千葉 一輝 様</p><p>パスワード再発行の依頼を受け付けました。</p><p>こちらのリンクからパスワードの再発行を行ってください。</p><p><a href=\"http://localhost:3000/password_resets/xyD6ASVsM1w6G-gXedCS/edit\">http://localhost:3000/password_resets/xyD6ASVsM1w6G-gXedCS/edit</a></p></body></html></body></html>" [5] pry(#<RSpec::ExampleGroups::UserMailer::Nested::Nested>)> mail.text_part => #<Mail::Part:70296108178900, Multipart: false, Headers: <Content-Type: text/plain>, <Content-Transfer-Encoding: base64>> [6] pry(#<RSpec::ExampleGroups::UserMailer::Nested::Nested>)> mail.text_part.body => #<Mail::Body:0x00007fde2d1d0f70 @ascii_only=false, @boundary=nil, @charset=nil, @encoding="8bit", @epilogue=nil, @part_sort_order=["text/plain", "text/enriched", "text/html"], @parts=[], @preamble=nil, @raw_source= "千葉 一輝 様<パスワード再発行の依頼を受け付けました>。</パスワード再発行の依頼を受け付けました><こちらのリンクからパスワードの再発行を行ってください>。</こちらのリンクからパスワードの再発行を行ってください>http://localhost:3000/password_resets/xyD6ASVsM1w6G-gXedCS/edit"> [7] pry(#<RSpec::ExampleGroups::UserMailer::Nested::Nested>)> mail.text_part.body.to_s => "千葉 一輝 様<パスワード再発行の依頼を受け付けました>。</パスワード再発行の依頼を受け付けました><こちらのリンクからパスワードの再発行を行ってください>。</こちらのリンクからパスワードの再発行を行ってください>http://localhost:3000/password_resets/xyD6ASVsM1w6G-gXedCS/edit"
参考記事
RSpecでメーラーのテスト実行時にメールの本文がなぜか空になっている問題を解決する - Qiita
rspec2 - rspec-email - How to get the body text? - Stack Overflow
ビューファイル毎に読み込ませるjsファイルを変えたい
ビューファイル毎に読み込ませるjsファイルを変えたい
ビューファイル毎に読み込ませるjsファイルを分ける方法を自分の備忘録として、こちらにまとめます。
Railsでは、アセットパイプラインによりマニフェストファイルからアセット(CSSファイルやJSファイル)をまとめて読み込み、アセットをまとめて読み込んでいるマニフェストファイルをレイアウトファイルで読み込んでいるというロジックになっている為、特定のページでのみで使用するjsファイルも違うページで読み込んでしまい存在しないDOMに対してaddEventListenerなどが実行されてしまい開発者ツール上で以下のようなエラーになってしまう。
これの解決方法としては、ビュー毎に読み込むjsファイルを分ければ良い。
方法は、以下のようになります。
現時点では、以下のようになっています。
app/javascripts
フォルダ以下にそれぞれの機能毎のjsファイルが以下のように存在します。
上記の機能毎のjsファイルを以下のようにマニフェストファイルで読み込んでいる。
[app/javascript/packs/application.js] // This file is automatically compiled by Webpack, along with any other files // present in this directory. You're encouraged to place your actual application logic in // a relevant structure within app/javascript and only use these pack files to reference // that code so it'll be compiled. require('jquery') require("@rails/ujs").start() require("@rails/activestorage").start() require("channels") require('bootstrap') import 'bootstrap'; import '@fortawesome/fontawesome-free/js/all'; import '../javascripts/search_cooking_select_box'; # ここで読み込んでいる import '../javascripts/search_calculate_cooking_time_select_box'; # ここで読み込んでいる import '../javascripts/search_cooking_memory'; # ここで読み込んでいる import '../javascripts/image_preview'; # ここで読み込んでいる window.$ = $; // Uncomment to copy all static images under ../images to the output folder and reference // them with the image_pack_tag helper in views (e.g <%= image_pack_tag 'rails.png' %>) // or the `imagePath` JavaScript helper below. // // const images = require.context('../images', true) // const imagePath = (name) => images(name, true)
上記のマニフェストファイルを以下のようにレイアウトファイルで読み込んでいる。
[app/views/layouts/application.html.slim] doctype html html head title = page_full_title(yield(:title)) = csrf_meta_tags = csp_meta_tag = stylesheet_link_tag 'application', media: 'all' ここでCSSのマニフェストファイルを読み込んでいる = javascript_pack_tag 'application' ここでJava Scriptのマニフェストファイルを読み込んでいる body - if logged_in? = render partial: 'shared/after_login_header' - else = render partial: 'shared/before_login_header' = render partial: 'shared/flash_message' = yield
このような過程で全てのビューファイルで全てのjsファイルが読み込まれてしまっている為、以下のように変更する。
まず以下のようにマニフェストファイルから特定のビューでしか使用しないjsファイルを削除する。
[app/javascript/packs/application.js] // This file is automatically compiled by Webpack, along with any other files // present in this directory. You're encouraged to place your actual application logic in // a relevant structure within app/javascript and only use these pack files to reference // that code so it'll be compiled. require('jquery') require("@rails/ujs").start() require("@rails/activestorage").start() require("channels") require('bootstrap') import 'bootstrap'; import '@fortawesome/fontawesome-free/js/all'; # ここで読み込んでいたビュー毎のjsファイルを削除 window.$ = $; // Uncomment to copy all static images under ../images to the output folder and reference // them with the image_pack_tag helper in views (e.g <%= image_pack_tag 'rails.png' %>) // or the `imagePath` JavaScript helper below. // // const images = require.context('../images', true) // const imagePath = (name) => images(name, true)
レイアウトファイル(app/views/layouts/application.html.slim)からは、そのままマニフェストファイルを読み込むようにする。
[app/javascript/packs]フォルダ以下に以下のように自分でマニフェストファイルを作成する。
以下のように作成したマニフェストファイルからビュー毎に使用するjsファイルを読み込む。
[app/javascript/packs/image_preview.js] import '../javascripts/image_preview';
[app/javascript/packs/search_calculate_cooking_time_select_box.js] import '../javascripts/search_calculate_cooking_time_select_box';
[app/javascript/packs/search_cooking_memory.js] import '../javascripts/search_cooking_memory';
[app/javascript/packs/search_cooking_select_box.js] import '../javascripts/search_cooking_select_box';
※読み込むjsファイルは相対パスで記載する必要がある。
上記のようなマニフェストファイルを以下のようにjsを使用するビューファイル毎で直接読み込むようにする。
[app/views/cooking_informations/index.html.slim] = javascript_pack_tag 'search_cooking_select_box' = content_for(:title, (t '.title')) .search-wrapper .container .row.justify-content-md-center .col-md-10 = search_form_for @q, url: cooking_informations_path do |f| .mt-4 = f.collection_select :fish_kind_eq, @fishes, :kind, :kind, { include_blank: "#{t 'defaults.search_for_fish'}" }, {class: 'search-select-form'} = f.collection_select :handle_pattern_eq, @handles, :pattern, :pattern, { include_blank: "#{t 'defaults.search_for_fish'}" }, {class: 'search-select-form'} = button_tag type: 'submit', class: 'btn btn-primary search-button' do i.fas.fa-search = render @cooking_informations = paginate @cooking_informations
これで使用するビューファイルだけでjsファイルを読み込むようになるため、開発者ツールでもエラーにならなくなる。
参考記事
webpacker でページごとにスタイルを分ける - Qiita
WebpackerでJavaScriptを使ってハマった話 - sasaboの生活
Webpacker::Manifest::MissingEntryErrorの対処法 | ゆみしん夫婦のブログ
Railsで特定のページのみJavaScriptを読み込む方法を現役エンジニアが解説【初心者向け】 | TechAcademyマガジン
Rails6で、アプリの特定のビューでJavaScriptを動かす。 : リア充キラキラ系のnoteです。@kuromitsu_ka
javascript — ビューごとのJavaScriptファイルRails
http://www.code-magagine.com/?p=4609
Railsでページごとのscssを管理する方法 -- blog.10rane.com
Ruby on Rails のアセットパイプラインの挙動を環境ごとに学ぶ - 30歳からのプログラミング
RailsでcssファイルとJavascriptファイルをマニフェストファイルから読み込む | Boys Be Engineer 非エンジニアよ、エンジニアになれ
RSpecでセレクトボックスの選択文字を出力する方法
RSpecでセレクトボックスの選択文字を出力する方法
RSpecでセレクトボックスの選択文字を出力する方法を自分の備忘録としてこちらにまとめます。
以下のようなセレクトボックスがあります。
<select class="search-select-form" name="q[fish_kind_eq]" id="q_fish_kind_eq"> <option value="">魚の種類(必須)</option> <option value="アジ">アジ</option> <option value="マメアジ">マメアジ</option> <option value="イカ">イカ</option> <option value="サバ">サバ</option> <option value="マハゼ">マハゼ</option> <option value="カサゴ">カサゴ</option> <option value="タチウオ">タチウオ</option> <option value="カワハギ">カワハギ</option> <option value="イシモチ">イシモチ</option> <option value="メジナ">メジナ</option> <option value="タコ">タコ</option> </select>
この時にセレクトボックスの中にある選択肢は、以下のようにして取り出せます。
[1] pry(#<RSpec::ExampleGroups::SearchCookings::Nested::Nested::Nested_4>)> within('#q_fish_kind_eq') do [1] pry(#<RSpec::ExampleGroups::SearchCookings::Nested::Nested::Nested_4>)* texts = all('option').map(&:text) [1] pry(#<RSpec::ExampleGroups::SearchCookings::Nested::Nested::Nested_4>)* end => ["魚の種類(必須)", "アジ", "マメアジ", "イカ", "サバ", "マハゼ", "カサゴ", "タチウオ", "カワハギ", "イシモチ", "メジナ", "タコ"]
上記のイメージは、以下のようになる。
within('#q_fish_kind_eq') do〜end
で範囲を指定する。
↓
all('option')
で全てのoption要素を取得して、mapメソッドにtextメソッドを引数で渡すことにより選択肢の中身が配列として取得できる。
※
textメソッドの動きは、以下のようになる。
[1] pry(#<RSpec::ExampleGroups::SearchCookings::Nested::Nested::Nested_4>)> all('option').first #全てのoption要素を取得 => #<Capybara::Node::Element tag="option" path="/HTML/BODY[1]/DIV[1]/DIV[1]/DIV[1]/DIV[1]/FORM[1]/DIV[1]/SELECT[1]/OPTION[1]"> [1] pry(#<RSpec::ExampleGroups::SearchCookings::Nested::Nested::Nested_4>)> all('option').first.text #全てのoption要素の内1番最初のものを取得して、それにtextメソッドを実行 => "魚の種類(必須)"
mapメソッドの動きは、以下のようになる。(ブロック内の処理をした新しい配列が取得できる)
[1] pry(main)> a = ['a', 'b', 'c', 'd'].map do |f| [1] pry(main)* f.upcase [1] pry(main)* end => ["A", "B", "C", "D"] [2] pry(main)> a => ["A", "B", "C", "D"]