20210428のRailsに関する記事は25件です。

Rails6 デプロイ エラーのメモ

急にデプロイできなくなった場合 こういうエラーs warning "webpack-dev-server > webpack-dev-middleware@3.7.3" has unmet peer dependency "webpack@^4.0.0 || ^5.0.0". warning "admin-lte > bootstrap-switch@3.3.4" has incorrect peer dependency "bootstrap@^3.1.1". warning " > tempusdominus-bootstrap-4@5.39.0" has unmet peer dependency "moment@^2.29.0". warning " > tempusdominus-bootstrap-4@5.39.0" has unmet peer dependency "moment-timezone@^0.5.31". warning " > tempusdominus-bootstrap-4@5.39.0" has unmet peer dependency "tempusdominus-core@5.19.0". warning " > bootstrap4-datetimepicker@5.2.3" has incorrect peer dependency "bootstrap@4.0.0-alpha.6". warning " > bootstrap4-datetimepicker@5.2.3" has unmet peer dependency "moment@^2.10". warning " > bootstrap4-datetimepicker@5.2.3" has unmet peer dependency "moment-timezone@^0.4.0 || ^0.5.0". warning " > webpack-dev-server@3.11.2" has unmet peer dependency "webpack@^4.0.0 || ^5.0.0". warning "webpack-dev-server > webpack-dev-middleware@3.7.3" has unmet peer dependency "webpack@^4.0.0 || ^5.0.0". 1: from /Users/XXX/path_to_app/vendor/bundle/ruby/2.7.0/gems/sshkit-1.21.2/lib/sshkit/runners/parallel.rb:11:in `block (2 levels) in execute' /Users/XXX/path_to_app/vendor/bundle/ruby/2.7.0/gems/sshkit-1.21.2/lib/sshkit/runners/parallel.rb:15:in `rescue in block (2 levels) in execute': Exception while executing as deploy_user@153.126.207.212: rake exit status: 1 (SSHKit::Runner::ExecuteError) rake stdout: yarn install v1.22.5 [webpack-cli] Failed to load '/var/www/app/releases/20210428091806/config/webpack/production.js' config [webpack-cli] TypeError: Cannot read property 'plugins' of undefined at Object.<anonymous> (/var/www/app/releases/20210428091806/config/webpack/environment.js:4:13) at Module._compile (/var/www/app/releases/20210428091806/node_modules/v8-compile-cache/v8-compile-cache.js:192:30) at Object.Module._extensions..js (internal/modules/cjs/loader.js:789:10) at Module.load (internal/modules/cjs/loader.js:653:32) at tryModuleLoad (internal/modules/cjs/loader.js:593:12) at Function.Module._load (internal/modules/cjs/loader.js:585:3) at Module.require (internal/modules/cjs/loader.js:692:17) at require (/var/www/app/releases/20210428091806/node_modules/v8-compile-cache/v8-compile-cache.js:159:20) at Object.<anonymous> (/var/www/app/releases/20210428091806/config/webpack/production.js:3:21) at Module._compile (/var/www/app/releases/20210428091806/node_modules/v8-compile-cache/v8-compile-cache.js:192:30) Caused by: SSHKit::Command::Failed: rake exit status: 1 rake stdout: Nothing written rake stderr: /var/www/app/shared/bundle/ruby/2.7.0/gems/faraday-0.15.4/lib/faraday/options.rb:166: warning: Capturing the given block using Proc.new is deprecated; use `&block` instead /var/www/app/shared/bundle/ruby/2.7.0/gems/faraday-0.15.4/lib/faraday/options.rb:166: warning: Capturing the given block using Proc.new is deprecated; use `&block` instead /var/www/app/shared/bundle/ruby/2.7.0/gems/faraday-0.15.4/lib/faraday/options.rb:166: warning: Capturing the given block using Proc.new is deprecated; use `&block` instead /var/www/app/shared/bundle/ruby/2.7.0/gems/faraday-0.15.4/lib/faraday/options.rb:166: warning: Capturing the given block using Proc.new is deprecated; use `&block` instead /var/www/app/shared/bundle/ruby/2.7.0/gems/faraday-0.15.4/lib/faraday/options.rb:166: warning: Capturing the given block using Proc.new is deprecated; use `&block` instead Tasks: TOP => deploy:assets:precompile (See full trace by running task with --trace) The deploy has failed with an error: Exception while executing as deploy_user@133.125.60.37: rake exit status: 1 rake stdout: Nothing written rake stderr: /var/www/app/shared/bundle/ruby/2.7.0/gems/faraday-0.15.4/lib/faraday/options.rb:166: warning: Capturing the given block using Proc.new is deprecated; use `&block` instead /var/www/app/shared/bundle/ruby/2.7.0/gems/faraday-0.15.4/lib/faraday/options.rb:166: warning: Capturing the given block using Proc.new is deprecated; use `&block` instead /var/www/app/shared/bundle/ruby/2.7.0/gems/faraday-0.15.4/lib/faraday/options.rb:166: warning: Capturing the given block using Proc.new is deprecated; use `&block` instead /var/www/app/shared/bundle/ruby/2.7.0/gems/faraday-0.15.4/lib/faraday/options.rb:166: warning: Capturing the given block using Proc.new is deprecated; use `&block` instead /var/www/app/shared/bundle/ruby/2.7.0/gems/faraday-0.15.4/lib/faraday/options.rb:166: warning: Capturing the given block using Proc.new is deprecated; use `&block` instead bundle stdout: Nothing written bundle stderr: master failed to start, check stderr log for details 1: from /Users/XXX/path_to_app/vendor/bundle/ruby/2.7.0/gems/sshkit-1.21.2/lib/sshkit/runners/parallel.rb:11:in `block (2 levels) in execute' /Users/XXX/path_to_app/vendor/bundle/ruby/2.7.0/gems/sshkit-1.21.2/lib/sshkit/runners/parallel.rb:15:in `rescue in block (2 levels) in execute': Exception while executing as deploy_user@xx.xx.xx.xx: bundle exit status: 1 (SSHKit::Runner::ExecuteError) bundle stdout: Nothing written bundle stderr: master failed to start, check stderr log for details (Backtrace restricted to imported tasks) cap aborted! SSHKit::Runner::ExecuteError: Exception while executing as deploy_user@xx.xx.xx.xx.: bundle exit status: 1 bundle stdout: Nothing written bundle stderr: master failed to start, check stderr log for details Caused by: SSHKit::Command::Failed: bundle exit status: 1 bundle stdout: Nothing written bundle stderr: master failed to start, check stderr log for details /Users/XXX/path_to_app/lib/capistrano/tasks/unicorn.rake:8:in `block in start_unicorn' /Users/XXX/path_to_app/lib/capistrano/tasks/unicorn.rake:7:in `start_unicorn' /Users/XXX/path_to_app/lib/capistrano/tasks/unicorn.rake:53:in `block (3 levels) in <top (required)>' Tasks: TOP => unicorn:force_restart (See full trace by running task with --trace) The deploy has failed with an error: Exception while executing as deploy_user@153.126.207.212: bundle exit status: 1 bundle stdout: Nothing written bundle stderr: master failed to start, check stderr log for details webpacker 再設定 % bin/rails webpacker:install identical config/webpacker.yml Copying webpack core config exist config/webpack identical config/webpack/development.js conflict config/webpack/environment.js Overwrite /Users/XXX/path_to_app/config/webpack/environment.js? (enter "h" for help) [Ynaqdhm] force config/webpack/environment.js identical config/webpack/production.js identical config/webpack/test.js Copying postcss.config.js to app root directory identical postcss.config.js Copying babel.config.js to app root directory identical babel.config.js Copying .browserslistrc to app root directory identical .browserslistrc The JavaScript app source directory already exists apply /Users/XXX/path_to_app/vendor/bundle/ruby/2.7.0/gems/webpacker-4.3.0/lib/install/binstubs.rb Copying binstubs exist bin identical bin/webpack identical bin/webpack-dev-server 各ファイルが書き変わってしまうので注意。 確認 package.json "dependencies": { "@fortawesome/fontawesome-free": "^5.15.2", "@rails/ujs": "^6.0.0", - "@rails/webpacker": "^6.0.0-beta.7", + "@rails/webpacker": "4.3.0", "admin-lte": "3.0.5", "bootstrap": "^4.5.3", "bootstrap4-datetimepicker": "^5.2.3", }, "version": "0.1.0", "devDependencies": { - "webpack-dev-server": "^3.11.0" + "webpack-dev-server": "^3.11.2" } }
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

アプリ制作で参考にしたリンク集(バックエンド編)(随時更新)

Devise(gem) git fatal: object {hash} is corrupt
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[反省]RailsAdminでundefind method ‘properties’ for nil:NilClassが発生した件について

始めに 反省含めて、記述します。 より詳しいことがわかる方いたら、コメントしてくださると嬉しいです。 エラー内容 今回、RailsAdminを導入しました。導入後、画面の表示までは成功したのですが、一部のモデルにアクセスしようとするとエラーが発生しました。 試したこと 正直、何も心あたりがなかったので、まずは仮説すら立てられず、、、、が、とりあえずアクセスできないモデルとアクセス可能なモデルの比較を行いました。また、ネット等でひたすら調べました。 わかったこと ひとまず比較してみると、ActiveHashとアソシエーションを結んでいるものにエラーが出ていると言うところまで突き止めました。そこで、ActiveHashを使わずenumを使用するとうまくいくことはわかりました。 わからないこと 依然として、なぜActiveHashが使えないのか不明のままです。また、使ってもうまくいくような対処法もわからないままです。 今回のエラー対応で学んだこと エラーに対して、すぐ人に聞く、あるいは誰かに丸投げというのはあまり好きではない私ですが、さすがに6時間以上粘ってもダメなものはダメなんだなと感じました(実は今回、課金してプロエンジニアさんに相談しました)。時には、諦めて人に聞いたり、もしかしすると諦めることも”進める”ためには大切な選択肢なのかもしれません。 これから、転職してプロのエンジニアとして働いていくことを目指しておりますが、現場ではもっとスピードと正確性が求められるはずなので、今自分にできることとできないことの切り分けをしっかり行い、次に何ができるかを考えることが重要なんだと、感じました。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Railsチュートリアルまとめ 第3章

第3章について 第3章では簡単なテストを実行しリファクタリングを行う。Railsではデフォルトでminitestがあるのでrails testコマンドですぐにテストを実行することが可能。 目次 1.Railsコマンドの短縮形 2.rails generateについて 3.httpメソッドについて 4.テストについて 5.DRY 6.Guard 1. Railsコマンドの短縮形 rails generateやrails serverなどのコマンドには短縮形がある。 rails server → rails s rails console → rails c rails generate → rails g rails test → rails t bundle install → bundle 2. rails generateについて 例えばrails generateコマンドでコントローラを生成すると自動的に関連ファイル(viewやテスト、ルートなど)を自動生成する。この機能は便利ではあるが、コントローラを削除したくなった場合にコントローラだけではなく関連ファイルも削除しなくてはならない。そういった場合にrails destroyコマンドを実行すると関連ファイルも含めて削除してくれる。モデルの作成についても同様。 3. httpメソッドについて httpメソッドはブラウザからサーバに送られるリクエストのこと。 主に以下の4つがよく使われる。 GET ... 最も使われるリクエストでweb上のデータを取得する時に使われる。 POST ... 何らかのリソースを生成する時や更新する時によく使われる。 PATCH ... リソースを更新する時に使われる。 DELETE ... リソースを削除する時使われる。 ちなみに一般のブラウザではGETとPOSTしかサポートしておらずPATCHとDELETEに関してはJavascriptなどであたかもPATCHやDELETEリクエストであるかのように偽装、送信して利用する。 4. テストについて テストは開発においてバグ追跡やリファクタリングの観点から重要であるが、テストを行う上で「テスト駆動(TDD)」にするか「一括テスト」にするか決めるのに以下のような基準で判断すると良いらしい。 テストを先に書く場合 * アプリケーションのコードよりもテストこーどの方が短くシンプルになる場合 * セキュリティ周りのエラーが発生した場合 * バグを見つけてバグを再現する場合 * リファクタリングする時 テストを後に書く場合 * 動作の仕様が固まりきっていない場合 * すぐに変更しそうなコードに対するテスト railsではデフォルトでminitestというテストが有効になっている。 rails testでtestディレクトリ下に書かれているtest.rbファイルに基づいてテストを実行する。 実行時に結果が失敗するとエラーメッセージが表示されるのでそれを参考にコードの修正点を探す。 5. DRY DRYは"Don't Repeat Yourself"の略でRubyの原則。 情報の繰り返しを避けてよりコードや仕様を明確にするべし。 6. Guard Guardを使うとシステムの変更を監視し、テストを自動的に実行させることができる。 bundle exec guard initコマンドを実行すると統合テストとビューが更新される。その後Guardfileをrailstutorial.org/guardfileを参照し編集しbundle exec guardでguardで自動テストを実行する。 この際、ターミナルを占有するので新しいターミナルを開いて実行した方が良い。 参考文献 PUTかPOSTかPATCHか? get,post,delete,putそしてmatchでルーティングを頑張る DRY原則をもう一度 -コンカレント・エンジニアリング-
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Rails初学者によるRailsチュートリアル学習記録⑤ 第3章

目次 1. はじめに 2. 第3章の概要 3. 学習内容 4. 終わりに 1. はじめに この記事は、Rails初学者の工業大学三年生がRailsチュートリアルの学習記録をつけるための記事です。 筆者自体がRailsやWebについて知識が少ないので、内容の解釈などに間違いがある可能性があります。(その時はコメントで指摘してくださると助かります!) Railsチュートリアル内ではRailsの内容以外にも、gitでのバージョン管理やHerokuを使ったデプロイも学習しますが、gitに関しては既に私が学習済みのため学習記録には記述しません。 演習の記録も省略します。 2. 第3章の概要 第3章からは本格的なサンプルアプリケーションを1から開発していきます。 まずは静的なページを自分で作成して少しずつ動的なコンテンツを追加という流れです。 この章ではほんの少しの動的なコンテンツを追加して、プログラミングに必要な自動化テストを学んでいきます。 ほぼ静的なページの作成 コントローラの生成 テスト駆動開発 テストコードの書き方 コードのリファクタリング リファクタリングとは HTMLファイルの内容のテスト HTMLにRubyを埋め込む 3. 学習内容 1. ほぼ静的なページの作成 1-1. コントローラの生成 ①コントローラを生成するコマンド 静的なページの作成に必要なコントローラは、scaffoldでも使用したrails generateコマンドを使用します。 今回はコントローラ名を「StaticPages」に設定して、Homeページ、Helpページ、Aboutページ、という3つのページを作成します。 つまりそれに対応するアクションをStaticPagesコントローラを作成するということです。 そのためのコマンドはrails generate controller StaticPages home helpです。 このコマンドではaboutアクションは作成されませんが、aboutアクションはコマンドを使わず1から作成していきます。 ②生成されるページ コントローラを作成した段階でルーティングが設定されるので、そのURLにアクセスすればページが表示されます。 今回は以下のようなルーティングと、アクション、ビューが設定されています。 config/routes.rb Rails.application.routes.draw do get 'static_pages/home' #homeアクションのURL get 'static_pages/help' #helpアクションのURL root 'application#hello' end app/controllers/static_pages_controller.rb class StaticPagesController < ApplicationController def home #homeアクション end def help #helpアクション end end 出典 https://railstutorial.jp/chapters/static_pages?version=5.1 1-2. テスト駆動開発 サンプルアプリでは変更を行う際に、自動化テストも同時に作成して機能が正しく実装されているかを確認するようにします。 テストコードを書くタイミングには変更の内容や、テストを作成する開発者の技量によって変わりますが、 大きく分けて以下の2つのタイミングでテストコードを書きます。 「テストコードを先に書いてからアプリの変更を行う」 「アプリの変更を行ってからテストコードを書く」 この2つのタイミングの内、テストコードを先に書く方法をテスト駆動開発と呼びます。 テスト駆動開発は開発に慣れてくると扱えるようになるのですが、Railsチュートリアルでも必要に応じてテスト駆動開発を採用しています。 1-3. テストコードの書き方 ①デフォルトのテストコード テストコードはコントローラ作成用のコマンドを実行時に、テストファイルが作成されるのでそこにテスト内容を記述していきます。 以下のコードはStaticPaagesコントローラのデフォルトのテストです。 test/app/controllers/static_pages_controller_test.rb require 'test_helper' class StaticPagesControllerTest < ActionDispatch::IntegrationTest test "should get home" do get static_pages_home_url assert_response :success end test "should get help" do get static_pages_help_url assert_response :success end end この2つのテストは、それぞれhomeページとhelpページがリクエストに対して正常にレスポンスを返すかをテストするコードです。 get static_pages_home_urlで指定したURLにgetリクエストを送っていて、 assert_response :successでレスポンスが成功になっているかを確かめています。 ②テスト駆動開発をやってみる ここからは、aboutアクションをテスト駆動開発で作成していきます。 まずは、homeアクションとhelpアクションと同じ内容のテストを作成します。 test/app/controllers/static_pages_controller_test.rb require 'test_helper' class StaticPagesControllerTest < ActionDispatch::IntegrationTest test "should get about" do get static_pages_about_url assert_response :success end end テストコードを追記してテストを実行すると $ rails test NameError: undefined local variable or method static_pages_about_url' 上記のようにエラーが返ってきます。 これはaboutページへのURLが見つからないというエラーなので、ルーティングファイルにURLを追加すると解消されます。 追記した後、またテストを実行すると以下のエラーが返ってきます。 $ rails test AbstractController::ActionNotFound: The action 'about' could not be found for StaticPagesController' このエラーはaboutアクションがコントローラーにないというエラーです。 これはコントローラにaboutアクションを追記すれば解消されます。 またテストを実行すると、 $ rails test ActionController::UnknownFormat: StaticPagesController#about is missing a template for this request format and variant. このようなエラーが返ってきます。 このエラーはビューファイルがないため発生しています。 よって、about.html.erbというビューファイルを作成して内容を記述するとこのエラーは解消されます。 もう一度テストを実行するとテストは成功となります。 $ rails test 3 tests, 3 assertions, 0 failures, 0 errors, 0 skips 2. コードのリファクタリング 2-1. リファクタリングとは リファクタリングとはプログラムの動作を変えずに、 コードの構造を変更して動作速度を速めたり、可読性を高めたりといった改善を行うことです。 2-2. HTMLファイル内容のテスト ①リファクタリングの内容 今回のリファクタリングはビューファイルのタイトルタグの内容をページごとに自動で変更されるようにします。 この変更もテスト駆動開発で行っていくため、まずテストを作成していきます。 ②タイトルをテストする このテストではtitleタグに指定した文字列が入っているかをテストします。 以下のコードがhomeビューのtitleタグの内容が、 「"Home | Ruby on Rails Tutorial Sample App」となっているかを確かめるテストです。 test/app/controllers/static_pages_controller_test.rb require 'test_helper' class StaticPagesControllerTest < ActionDispatch::IntegrationTest test "should get home" do get static_pages_home_url assert_response :success assert_select "title", "Home | Ruby on Rails Tutorial Sample App" #タイトルタグのテスト end 上記のコードのassert_select "title", "Home | Ruby on Rails Tutorial Sample App"の部分で titleタグの内容を確認しています。 第一引数が内容を確認したいタグを指定していて、第二引数が存在しているか確かめたい内容です。 このようなテストを他のページにも同様に書きます。 2-3. HTMLにRubyを埋め込む リファクタリングで実装したいページごとに自動でタイトルが変わるようにする変更は、 HTMLにRubyを埋め込むことで実装していく。 以下のコードが埋め込みRubyによってタイトルが自動的に変更されるようになったビューです。 app/views/layouts/application.html.erb <!DOCTYPE html> <html> <head> <title><%= yield(:title) %> | Ruby on Rails Tutorial Sample App</title> <%= csrf_meta_tags %> <%= csp_meta_tag %> <%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %> <%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload' %> </head> <body> <%= yield %> </body> </html> このファイルはビューファイルのheadタグ等の共通部分を記述して、<%= yield %>の部分で各ページの内容を挿入します。 これによって各ビューファイルの共通部分を一箇所にまとめています。 titleタグの下の4行はRailsが作成してくれるJavascriptを扱えるようにするためのコードや、 クロスサイトスクリプティング攻撃の対策用のコード等です。 titleタグの中の<%= yield(:title) %>で各ページのタイトルを自動的に挿入しています。 これは各ビューファイルで<% provide(:title, "Home") %>のように記述することで第一引数でラベルを定義して、 第二引数で値を入力することで、その値を受け取って挿入してくれるコードです。 この2つのコードによって、各ビューファイルごとに入力されたタイトルが挿入されて、タイトルが自動的に変更されるようになります。 4. 終わりに 第三章から、本格的なWebアプリケーションの開発が始まりました。 内容もこれまでの2つの章と比べると濃くなっており、記事の内容も大分長くなってしまいました。 これでも端折ったほうなのですが、記事の作成が大変です:( テストやリファクタリングといった、Progateなどでは触れてこなかった内容が出てきましたが、 難易度としてはまだ躓くほどではないので、内容が難しくなってくる前に記事の作成に慣れることができればと思います。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Rails】carrierwaveで画像アップロードするとクラッシュした

環境 MacOS Rails 6.1.3 carrierwave rmagic Problem いつものように画像をアップロードして登録しようとするとおびただしい数のエラーが表示されてrails serverが落ちました。railsでクラッシュしたのは初めてです。 ... /Users/xxx/Projects/xxx/vendor/bundle/ruby/3.0.0/gems/carrierwave-2.2.1/lib/carrierwave/processing/rmagick.rb:352: [BUG] Segmentation fault at 0x000000000000332e ruby 3.0.0p0 (2020-12-25 revision 95aff21468) [x86_64-darwin19] -- Crash Report log information -------------------------------------------- See Crash Report log file under the one of following: * ~/Library/Logs/DiagnosticReports * /Library/Logs/DiagnosticReports for more details. Don't forget to include the above Crash Report log file in bug reports. -- Control frame information ----------------------------------------------- ... [IMPORTANT] Don't forget to include the Crash Report log file under DiagnosticReports directory in bug reports. rmagickでエラーが出てるので画像をリサイズする工程でうまく行ってないみたいです。 Solve 原因には心当たりがありました。 最近「brew upgrade」を実行した際に「imagemagick@6」がアップデートされたのです。 rmagickとimagemagickは関係しています。 恐らくimagemagickのアップデートの影響だと思われます。試行錯誤した結果以下で落ち着きました。 # 6系を削除して7系を入れます brew uninstall imagemagick@6 brew install imagemagick # 一応gemも総入れ替えしました rm Gemfile.lock rm -rf vendor/bundle/ bundle install 6系じゃないと動かない的な記事を見ましたが、今や7系でもちゃんと動くみたいです。 これで今まで通り画像をアップロードしてリサイズする事ができるようになりました。 バージョンアップで今回のようなことが起きないようにバージョンを固定したほうが良いかもしれないですね。 # アップデートされないようにフリーズしておきます brew pin imagemagick Summary かなりハマったのでどなたかの助けになれたなら幸いです。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

RSpec のsystem spec 実行時にselenium でEnter キーの押下をシュミレートする

RSpec のsystem spec 実行時にselenium でEnter キーの押下をシュミレートする 環境 macOS 10.15.6 Ruby 2.5.7 Rails 5.2.3 rspec-rails 4.0.1 capybara 3.32.2 selenium-webdriver 3.142.7 参照 Keyboard :: Documentation for Selenium send_keys(special)-Ruby ruby on rails - How to simulate pressing Enter in Rspec - Stack Overflow 使えるRSpec入門・その4「どんなブラウザ操作も自由自在!逆引きCapybara大辞典」 - Qiita 目標 上記のような検索実行ボタンの無い検索フォームでテキスト入力後にEnter キーを押して検索を実行する動作をシュミレートしたい 解決策 send_keys メソッドを使う。 下記のような検索フォームに検索テキストとしてkeyword を入力後にEnter キー押下した際の検索結果のテストを想定しています。 <form> <input placeholder='Search' id="keyword_search"> </form> it '検索結果のテスト', js: true do #検索フォームにkeyword を入力 fill_in 'Search , with: 'keyword' #テキスト入力後のEnter キー押下 find("#keyword_search").send_keys :return #検索結果の検証 expect(page).to have_content 'keyword' end ポイント selenium 以外のヘッドレスブラウザとの情報が色々と混ざってしまったので整理 :return は:enter でも可 :return は小文字でないとNG js: true でJavaScript を有効にする find("#keyword_search").native.send_keys :return ではNG, .native はseleniumでは不要 学び Poltergeist, capybara-webkit 等の他のヘッドレスブラウザ毎に微妙に記述が異なるので使用する環境できちんと調べる事が重要
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[Rails]deviseのモジュールについて

はじめに deviseを自作のRailsアプリケーションで使用したので備忘録ととして残しておきます。 今回はdeviseで定義されているモジュールについて記述していきます。 deviseの導入方法は以下を確認ください [Rails] devise導入方法 モジュールの説明 マイグレーションファイルを確認すると以下のようになっています。 class DeviseCreateUsers < ActiveRecord::Migration[6.0] def change create_table :users do |t| ## Database authenticatable t.string :email, null: false, default: "" t.string :encrypted_password, null: false, default: "" ## Recoverable t.string :reset_password_token t.datetime :reset_password_sent_at ## Rememberable t.datetime :remember_created_at ## Trackable t.integer :sign_in_count, default: 0, null: false t.datetime :current_sign_in_at t.datetime :last_sign_in_at t.inet :current_sign_in_ip t.inet :last_sign_in_ip ## Confirmable t.string :confirmation_token t.datetime :confirmed_at t.datetime :confirmation_sent_at t.string :unconfirmed_email # Only if using reconfirmable ## Lockable t.integer :failed_attempts, default: 0, null: false # Only if lock strategy is :failed_attempts t.string :unlock_token # Only if unlock strategy is :email or :both t.datetime :locked_at t.timestamps null: false end add_index :users, :email, unique: true add_index :users, :reset_password_token, unique: true # add_index :users, :confirmation_token, unique: true # add_index :users, :unlock_token, unique: true end end 「#」が2つ付いているところがモジュール名になります。 これを上から順に説明していきます。 1.DatabaseAuthenticatable データベースに保存されたパスワードが合っているか検証をします。 同時にパスワードの暗号化も行う。 2.Recoverable パスワードリセットを行います。 3.Rememberable クッキーにログイン情報を保持します。 4.Trackable ログインした回数、最終ログイン日時、前回ログイン日時、最終ログインIP、前回ログインIPを保存する。 5.Confirmable 新規登録時によるメール認証機能の付加。 6.Lockable ログインに何度も失敗すると、アカウントをロックする。 何回失敗するとロックするかはLockable内で指定できる。 その他のモジュール マイグレーションファイルに記述されている以外にもモジュールが用意されています。 7.Timeoutable ログインしたままの状態で一定時間経つと自動でログアウトさせます。 デフォルトだと30分になっています。 8.Registerable 登録処理を通してユーザーをサインアップします。また、ユーザーに自身のアカウントを編集したり削除することを許可します。 9.Validatable Emailやパスワードのバリデーションを追加する。独自に定義したバリデーションを追加することもできます。 omniauthable twitterやFacebookなどのSNS認証を追加します。 モジュールの使い方 モジュールを使う場合はapp/models/users.rbで下記のように記述します。 app/models/users.rb devise :database_authenticatable, :registerable, :recoverable, :rememberable, :validatable 以上でモジュールの紹介は終わりです。 情報が足りないんじゃないか?などがあればコメントくださると嬉しいです。 参考
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Rails リファクタリングへの意識

はじめに ポートフォリオがひとまず形になりrspecも書いたため、リファクタリングを行った際、 コントローラのアクション1つだけでも考える事がたくさんあったため、それをまとめたものです。 まだまだ最適解では無いかもしれないため、いい方法があれば誰か教えていただけると幸いです。 リファクタリング前のコード 下記は企業登録を行うアクションとなります。 簡単に流れを説明すると、 フォームから送信された物が問題なければ企業を登録し、従業員を一人追加するアクションとなります。 コントローラ def create @company = Company.new(company_params) #従業員の中に同じEメールが無いかチェックし、いたら登録をせずフォームに返す if Employee.find_by(email: @company.email) @company.errors.add(:email, "はすでに存在します") return render 'new' end @company.usage_status = true if @company.save #企業登録時に、1人管理者権限を持った従業員を登録 @company.employees.create(name: self.responsible_name, email: self.email, password: 'password', department: '管理者', joining_date: Date.today, admin: true, enrollment_status: true) flash[:success] = '登録完了しました。' redirect_to admin_companies_path else render 'new' end end ① @company.employees.createをモデルにて定義 コントローラの中で行数が多い記述となっており見栄えが悪かったため、モデル内に記載しました。 コントローラ @company.employee_admin_create # @company.employees.create(name: self.responsible_name, # email: self.email, # password: 'password', # department: '管理者', # joining_date: Date.today, # admin: true, # enrollment_status: true) モデル #企業登録時に、1人管理者権限を持った従業員を登録 def employee_admin_create employees.create(name: self.responsible_name, email: self.email, password: 'password', department: '管理者', joining_date: Date.today, admin: true, enrollment_status: true) end ② if Employee.find_by(email: @company.email)をprivate内に記載 アクション内では1行で記載できるように、privateに記述を引っ越し、 またその際に、ネストが深くならないようにGuard Clauseと呼ばれる技法にて記載。 コントローラ . . check_duplicate_email_in_employees and return # if Employee.find_by(email: @company.email) # @company.errors.add(:email, "はすでに存在します") # return render 'new' # end . . private def check_duplicate_email_in_employees return unless Employee.find_by(email: @company.email) @company.errors.add(:email, "はすでに存在します") render 'new' end ③ そもそも必要の無い記述の削除 下記は、データベース登録時にdefaultでtrueになるカラムであったため、 コントローラでは記述が不要で有ると考え削除 コントローラ # @company.usage_status = true ④ flashメッセージとredirectを1行にまとめる コントローラ redirect_to admin_companies_path, flash: { success: '登録完了しました。' } # flash[:success] = '登録完了しました。' # redirect_to admin_companies_path リファクタリング後のコード コントローラ def create @company = Company.new(company_params) check_duplicate_email_in_employees and return if @company.save @company.employee_admin_create redirect_to admin_companies_path, flash: { success: '登録完了しました。' } else render 'new' end end private def check_duplicate_email_in_employees return unless Employee.find_by(email: @company.email) @company.errors.add(:email, "はすでに存在します") render 'new' end モデル def employee_admin_create employees.create(name: self.responsible_name, email: self.email, password: 'password', department: '管理者', joining_date: Date.today, admin: true, enrollment_status: true) end 最後に 最初は自分でも醜いコードだなと思っていましたが、少し意識するだけで、見違えるほど綺麗になりました。 また、リファクタリングは家の中を掃除しているような感覚で、綺麗なコードになると爽快感があるため、 今後も散らかした部屋を一つ一つ掃除していきます。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Rails6 x Google Maps API】フォームから住所を入力してviewのGoogle Mapで複数のマーカーを表示する方法

実現したいこと GIFやスクリーンショットのように、view上のGoogle Mapにおいて複数のマーカー(赤いピン)を立てることを目標とします。 データの流れとしては、 フォームから住所を入力 -> Geocoding APIで住所を緯度経度に変換 -> 緯度経度をデータベースに保存 -> 保存した緯度経度 Railsのバージョン/使ったAPI この記事では、以下のバージョンを使用しました Ruby on Rails 6.1.3 Google Maps JavaScript API -> webアプリケーション上でGoogle Mapをカスタマイズして表示するために必要 Geocoding API -> 住所を緯度経度に変換するために必要 記事を読む前に終わっておくべきこと 以下のことについては本記事では解説しないので本編では終わっている前提で進めていきます。 Google Maps JavaScript API/ Geocoding APIの導入 APIを導入するには下記記事が参考になると思います。 モデル/テーブルの作成 今回は Cafeモデル に cafesテーブル を持たせることを想定しています。 cafesテーブルには以下のレコードが存在します 後で緯度(longitude), 経度(latitude)は使います. scheme.rb 省略 create_table "cafes", force: :cascade do |t| t.string "address" t.float "longitude" t.float "latitude" t.datetime "created_at", precision: 6, null: false t.datetime "updated_at", precision: 6, null: false t.string "name" end 省略 任意のviewでGoogle Mapが表示されている状態 ↑までが終わった状態で本編へお進みください 本編 実装の確認 今回は以下のような実装を目指します。 フォームから住所を入力すると、viewのGoogle Mapで複数のマーカーが表示されているという状態 フォームから住所を入力する まずはフォームから作っていきましょう. form_withを使って実装します 非同期なのでlocal: trueを忘れずに. new.html.slim = form_with model:@cafe, url: admin_cafes_path, local: true do |f| .form-group p 店舗名を入力 = f.text_field :name, placeholder: "XX COFFEE ROASTER", class: "form-control" br p 住所を入力 = f.text_field :address, placeholder: "東京都港区芝公園4-2−8", class: "form-control" br = f.submit "登録する", class: "btn btn-primary" そうするとこのようなフォームが完成します。 住所の緯度経度にを取得 APIを叩いて帰ってくる結果を確認 Geocoding APIを使って住所を緯度経度に変換する処理を書く前に、APIを使って取得できる結果を確認しておきましょう。 https://maps.googleapis.com/maps/api/geocode/json?address=東京都港区芝公園4-2-8&key=取得したAPIキー にアクセスすると、レスポンスが返ってきます { "results" : [ { "address_components" : [ { "long_name" : "8", "short_name" : "8", "types" : [ "premise" ] }, { "long_name" : "2", "short_name" : "2", "types" : [ "political", "sublocality", "sublocality_level_4" ] }, { "long_name" : "4丁目", "short_name" : "4丁目", "types" : [ "political", "sublocality", "sublocality_level_3" ] }, { "long_name" : "芝公園", "short_name" : "芝公園", "types" : [ "political", "sublocality", "sublocality_level_2" ] }, { "long_name" : "港区", "short_name" : "港区", "types" : [ "locality", "political" ] }, { "long_name" : "東京都", "short_name" : "東京都", "types" : [ "administrative_area_level_1", "political" ] }, { "long_name" : "日本", "short_name" : "JP", "types" : [ "country", "political" ] }, { "long_name" : "105-0011", "short_name" : "105-0011", "types" : [ "postal_code" ] } ], "formatted_address" : "日本、〒105-0011 東京都港区芝公園4丁目2−8", "geometry" : { "location" : { "lat" : 35.6585769, "lng" : 139.7454506 }, "location_type" : "ROOFTOP", "viewport" : { "northeast" : { "lat" : 35.6599258802915, "lng" : 139.7467995802915 }, "southwest" : { "lat" : 35.6572279197085, "lng" : 139.7441016197085 } } }, "place_id" : "ChIJL9dIIZeLGGARMHFc9xtDEhM", "plus_code" : { "compound_code" : "MP5W+C5 日本、東京都港区", "global_code" : "8Q7XMP5W+C5" }, "types" : [ "street_address" ] } ], "status" : "OK" } 今回欲しいのは、["geometry"]["location"]の["lat"]と["lng"]です。 フォームで入力した住所をもとに緯度経度を取得し、データベースに保存する処理を書いていきます。 入力された住所の緯度経度を取得して保存する ↑で叩いたように入力された住所の緯度経度を取得します。 map_query.rb というモデルを作ってある程度のロジックを書いていきます。 map_query.rb # app > models > map_query.rb を作成 class MapQuery # 変数を初期化 def initialize(cafe_param) @cafe_param = cafe_param end   def uri # フォームから飛んできた住所をエスケープして変数に格納 address = URI.encode_www_form({address: @cafe_param}) # Geocoding APIを叩く URI.parse("https://maps.googleapis.com/maps/api/geocode/json?#{address}&key=#{ENV["MAP_API_KEY"]}") end def result # 返ってきたJSONをパースしてapi_response という変数に格納 api_response = Net::HTTP.get_response(uri) response_body = JSON.parse(api_response.body) response_body["results"][0]["geometry"]["location"] end end 続いてコントローラ cafes_controller.rb class Admin::CafesController < Admin::BaseController # Cafeクラスのインスタンスを作成 def new @cafe = Cafe.new end # 住所、緯度、経度をデータベースに保存 def create # MapQueryのresultメソッドを呼び出して@resultに格納 @result = MapQuery.new(params[:cafe]).result # Cafeモデルの各カラムに住所、緯度、経度を格納 @cafe = Cafe.new( name: cafe_params["name"], address: cafe_params["address"], latitude: @result["lat"], longitude: @result["lng"] ) # 保存 if @cafe.save flash[:notice] = "保存しました" redirect_to cafes_path else flash.now[:danger] = "保存に失敗しました" render action: :new end end private def cafe_params params.require(:cafe).permit(:name, :address, :latitude, :longitude) end end 緯度経度をviewで取り出してGoogle Map上で表示する ここまでで、フォームから住所を入力 -> 緯度経度を取得 -> データベースに保存 までは実装できました. ここからは保存したデータをもとに、任意のviewのGoogle Mapで複数のマーカーを立てるように実装していきます. まず、どういう処理が必要か考えていきます データベースから緯度経度を取りだす 取り出した緯度経度をviewに渡す 渡された緯度経度をもとにGoogle Map上に複数のマーカーを立てる データベースから緯度経度を取りだす Google Mapを表示させたいviewと紐付いているコントローラに以下のように記述します。 cafes_controller.rb class CafesController < ApplicationController def index # pluckを使って緯度経度を取り出し、JSONにして変数に格納 # 保存されているすべてのlatitudeカラムとlongitudeカラムを配列として取得し、JSONに変換 @all_cafe_position = Cafe.all.pluck(:latitude, :longitude).to_json end end pluckメソッドについて カラムを指定して、配列として取得することが出来ます 説明: 指定したカラムのレコードの配列を取得 使い方: モデル.pluck(カラム名 [, ...]) 取り出した緯度経度をviewに渡す 緯度経度がJSONになって変数に格納されています それをviewで取り出します 任意のview.html.slim #roaster h1 コーヒーロースター一覧 #map /データ属性として@all_cafe_positionを渡す #marker-data data-position=@all_cafe_position /GoogleMapをカスタマイズするためのJavaScriptファイルを別で定義してここで読み込む =javascript_pack_tag 'home/index' /viewでGoogleMapを表示させるため script src="https://maps.googleapis.com/maps/api/js?key=#{ENV['MAP_API_KEY']}&callback" 渡された緯度経度をもとにGoogle Map上に複数のマーカーを立てる viewにはDOMとして緯度経度が渡っています Google Maps JavaScript APIのドキュメントを参照しながら複数のマーカーを立てるという実装をしていきます ループ以外の書き方はドキュメントに従っています index.js //app > javascript > packs > home > index.js let marker = []; //DOMの #marker-data に緯度経度が渡っているので、取得してmarkerData変数に格納 let markerData = JSON.parse(document.querySelector("#marker-data").dataset.position); function initMap() { //ループを使ってすべての緯度経度を変数に格納 for (var i = 0; i < markerData.length; i++) { markerLatLng = new google.maps.LatLng({ lat: markerData[i][0], lng: markerData[i][1] }); marker[i] = new google.maps.Marker({ position: markerLatLng, map: map }); } }); } window.onload = function() { initMap(); } まとめ データベースに保存する処理まではWeb APIを叩いて保存するというよくある流れなのですんなりと実装することができると思います 個人的に解決するまでに時間がかかったポイント pluckメソッドを使って緯度経度を取得する点 data属性としてviewに渡す点 この2点は糸口を掴むまでかなり時間を要しました。 controllerやviewなど個人のプロジェクトで違うと思いますが、この記事が何かの参考になれば幸いです。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[Rails] devise導入方法

はじめに 自作のRailsアプリケーションでdeviseを使用したので備忘録として残しておきます。 deviseとは railsのgemの一つでログイン認証機能を簡単に実装することができる。 インストール Gemfileに以下のように記述してください gem 'devise' ターミナルで以下コマンドを実行します。 $ bundle install $ rails g devise:install 以上でインストールは終わりです ビューファイルの作成 以下のコマンドでdeviseの認証周りが実装されたビューファイルが作成されます。 $ rails g devise:views 見た目はかなり簡素になっているのでビューファイルを編集する必要があります。 Userモデルの作り方 deviseをインストールをすると認証が使えるモデルを作成することができます。 rails g model userではなく以下のコマンドを使います。 $ rails g devise user このコマンドを実行すればログイン認証ができるファイルが自動で作成されます。 同時にroutes.rbにdevise_for :usersが追記されサインアップやログイン、ログアウトのルーティングが自動で作成されます。 マイグレーションファイルは以下になっています。 最初はnameカラムがないので入れておきましょう。 class DeviseCreateUsers < ActiveRecord::Migration[6.0] def change create_table :users do |t| ## Database authenticatable t.string :email, null: false, default: "" t.string :encrypted_password, null: false, default: "" ## Recoverable t.string :reset_password_token t.datetime :reset_password_sent_at ## Rememberable t.datetime :remember_created_at ## Trackable t.integer :sign_in_count, default: 0, null: false t.datetime :current_sign_in_at t.datetime :last_sign_in_at t.inet :current_sign_in_ip t.inet :last_sign_in_ip ## Confirmable t.string :confirmation_token t.datetime :confirmed_at t.datetime :confirmation_sent_at t.string :unconfirmed_email # Only if using reconfirmable ## Lockable t.integer :failed_attempts, default: 0, null: false # Only if lock strategy is :failed_attempts t.string :unlock_token # Only if unlock strategy is :email or :both t.datetime :locked_at t.string :name  #ここにnameを追加 t.timestamps null: false end add_index :users, :email, unique: true add_index :users, :reset_password_token, unique: true # add_index :users, :confirmation_token, unique: true # add_index :users, :unlock_token, unique: true end end またマイグレーションファイルを追記した場合はuserカラムを受け入れてくれるようにapplication_controller.rbに以下の記述をしておきましょう # 以下を追加 before_action :configure_permitted_parameters, if: :devise_controller? def configure_permitted_parameters # サインアップ時にusernameのストロングパラメータを追加 devise_parameter_sanitizer.permit(:sign_up, keys: [:username, :image]) # アカウント編集の時にnameとprofileのストロングパラメータを追加 devise_parameter_sanitizer.permit(:account_update, keys: [:username,:image,:profile]) end
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Rails6】アプリ名を変更したい

開発中にrailsアプリ名を変更した際に行った手順です。 renameというgemを使用しました。  開発環境 Rails 6.1.1 Ruby 2.7.2 mac 0S Big Sur 11.2.3 renameを導入 Gemfileに以下を追記します。 Gemfile gem 'rename' ターミナルでインストール。 ターミナル $ bundle install インストールが確認できれば古い方のデータベースを破棄します。 ターミナル $ rails db:drop 変更したいアプリ名を入力 ここで renameのコマンドで新規のアプリ名を入力します。 ターミナル $ rails g rename:into 変更後のアプリ名 今回はold_app → new_appへ変更して以下の通りになりました。 ターミナル $ rails g rename:into new_app Search and replace module in... gsub config.ru gsub README.md gsub Rakefile gsub yarn.lock gsub babel.config.js gsub package.json gsub Gemfile gsub Gemfile.lock gsub postcss.config.js gsub config/routes.rb gsub config/environments/production.rb gsub config/environments/development.rb gsub config/environments/test.rb gsub config/spring.rb gsub config/environment.rb gsub config/application.rb gsub config/puma.rb gsub config/boot.rb gsub config/initializers/application_controller_renderer.rb gsub config/initializers/backtrace_silencers.rb gsub config/initializers/active_admin.rb gsub config/initializers/mime_types.rb gsub config/initializers/filter_parameter_logging.rb gsub config/initializers/wrap_parameters.rb gsub config/initializers/assets.rb gsub config/initializers/cookies_serializer.rb gsub config/initializers/devise.rb gsub config/initializers/content_security_policy.rb gsub config/initializers/inflections.rb gsub config/initializers/session_store.rb Error: No such file or directory @ rb_sysopen - /Users/*****/ディレクトリ名/old_app/config/initializers/session_store.rb gsub config/database.yml Renaming references... Renaming directory...Done! New application path is '/Users/*****/ディレクトリ名/new_app ターミナルを再起動してアプリのディレクトリ名が変更できていれば成功です。 新規のデータベースを作成するのも忘れずに。 ターミナル $ rails db:create ターミナル $ rails db:migrate 最後にrails serverが起動するか確認します。 ターミナル $ rails s 追記 アプリをGithubに連携している場合はGithub側でも変更が必要です。 package.json、HTMLで直接記載した旧アプリ名も別途変更が必要です。 まとめ アプリ名はなるべく変更しないよう計画的に運用したいですね! 参考: [Rails]rails newした後からアプリ名を変更する方法
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

rails ActiveHashを導入しよう

基本的に変更されないデータを、データベースに保存せずに取り扱う方法 初心者なので、使い方を忘れないように残しておこうと思います。 間違ってたりしたらすいません。 例えば、都道府県名一覧やカテゴリーなど「基本的に変更されないデータ」があったとします。「基本的に変更されないデータ」は、データベースに保存する必要性がありません。一方、ビューファイルなどにそれらのデータを直接書いてしまうと、可読性に欠けます。 そのようなケースでは、ActiveHashが有用です。 ActiveHash Active_Hashとは、都道府県名などの変更されないデータをモデルファイル内に直接記述することで、データベースへ保存せずにデータを取り扱うことができるGemです。 すなわち、Active_Hashを用いることで、モデルファイルに直接記述した変更されないデータに対して、ActiveRecordのようなメソッドを用いることができます。(例えば、allやcreateメソッドのことを指しています。) ActiveHashを導入しよう Gemfileを編集しましょう gem 'active_hash' 記述したらbundle installを実行しましょう。 bundle install モデルを作成しましょう ActiveHashでは自分でファイルを作成します。 app/modelsディレクトリ配下にファイル名.rbを作成します。 前持ってDB設計していると思うので、ファイル名は紐付けたいテーブルのカラム名になるようにする そのファイルの中に ActiveHash::Baseクラスを継承します。 ActiveHash::Baseは、あるモデル内(クラス内)でActiveHashを用いる際に必要となるクラスです。ActiveHashのGemに定義されています。 また、ActiveHash::Baseを継承することで、ActiveRecordと同じようなメソッドを使用できるようになります。 以下のように記述する class Genre < ActiveHash::Base self.data = [ { id: 1, name: '--' }, { id: 2, name: '経済' }, { id: 3, name: '政治' }, { id: 4, name: '地域' }, { id: 5, name: '国際' }, { id: 6, name: 'IT' }, { id: 7, name: 'エンタメ' }, { id: 8, name: 'スポーツ' }, { id: 9, name: 'グルメ' }, { id: 10, name: 'その他' } ] end ジャンルのデータは、配列にハッシュ形式で格納しています。 マイグレーションファイルは先程言った通り class CreateArticles < ActiveRecord::Migration[6.0] def change create_table :articles do |t| t.string :title , null: false t.text :text , null: false t.integer :genre_id , null: false t.timestamps end end end 上記で言えば t.integer :genre_id ,null:false これが紐付けされるように準備されたカラム名です。 型はintegerになります。 してなければ rails db:migrate アソシエーションを設定しよう ActiveHashを用いてアソシエーションを設定する場合は、ActiveHashで定義されているmoduleをモデルに取り込む必要があります。 投稿する記事は、1つのジャンルに紐付いています。そのため、紐付いてるモデルにはbelongs_toを設定します。 ActiveHashを用いて、belongs_toを設定するには、 extend ActiveHash::Associations::ActiveRecordExtensionsと記述してmoduleを取り込みます。 例 class Article < ApplicationRecord extend ActiveHash::Associations::ActiveRecordExtensions belongs_to :genre end ActiveHashを用いてのbelongs_toが設定できました。 ActiveHashを用いて、has_manyを設定するには、 include ActiveHash::Associationsと記述してmoduleを取り込みます。 例 class Genre < ActiveHash::Base self.data = [ { id: 1, name: '--' }, { id: 2, name: '経済' }, { id: 3, name: '政治' }, { id: 4, name: '地域' }, { id: 5, name: '国際' }, { id: 6, name: 'IT' }, { id: 7, name: 'エンタメ' }, { id: 8, name: 'スポーツ' }, { id: 9, name: 'グルメ' }, { id: 10, name: 'その他' } ] include ActiveHash::Associations has_many :articles end バリデーションを設定しよう numericality」というバリデーション のヘルパーを使用します。 numericalityとは、数値かどうかを検証するバリデーションの一種です。 数値であればデータベースに保存を許可して、それ以外では保存が許可されないようにできます。 今回のアプリケーションでは、--を保存されないようにしたいので、id: 1以外であれば保存できるように設定します。 例 class Article < ApplicationRecord extend ActiveHash::Associations::ActiveRecordExtensions belongs_to :genre #空の投稿を保存できないようにする validates :title, :text, presence: true #ジャンルの選択が「--」の時は保存できないようにする validates :genre_id, numericality: { other_than: 1 } end このバリデーションは、genre_idのid:1以外のときに保存できるという意味です。 記事一覧表示機能を実装しよう ストロングパロメーターにもActiveHashで紐付けたカラム名をいれる 例 class ArticlesController < ApplicationController def index @articles = Article.order("created_at DESC") end def new @article = Article.new end def create @article = Article.new(article_params) if @article.save redirect_to root_path else render :new end end private def article_params params.require(:article).permit(:title,:text,:genre_id) end end collection_select collection_selectとは、データをプルダウン形式で表示することができるメソッドです。 collection_selectは、下記のような順番で記述します。 例 <%= form.collection_select(保存されるカラム名, オブジェクトの配列, カラムに保存される項目, 選択肢に表示されるカラム名, オプション, htmlオプション) %> こんな感じです <%= f.collection_select(:genre_id, Genre.all, :id, :name, {}, {class:"genre-select"}) %> 第五引数で、ビュー側で{include_blank: "--"}というオプションを指定する場合もあります。しかし、今回はgenre.rbで{ id: 1, name: '--' }の記述があるため、指定なしとしています。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

プログラミングの知識ゼロからrailsを学ぶ

「プログラミングの知識ゼロからrailsを学ぶ」 Rails初めて2週間。自分的にハマった勉強の仕方をキタる。 前提知識 ・HTMLとCSSまあまあ知ってる。 ・Javascriptも少しだけ。(onClickぐらい) 最初やったこと ・とりまRails Tutorialを買って7章まで読んで爆死。 (ウェブデザインしかしたことないから意味不・お経) 爆死理由 ・Rubyを知らない ・テストって何それ美味しいの病にかかる 解決方法 1.プログラミングの勉強の仕方をめちゃ調べる ようつべのケンタとか良かった。 2.Rubyをかじる。  ・ようつべの「キノコード」とかのやつを見る  ・Qiita、テックアカデミー、なんとか侍で「ルビー初心者」の記事を読む ※50パーぐらいわかったら次へ 3.Railsを勉強  ・適当にネットで「rails初心者」みたいなやつをする おすすめ→ https://openbook4.me/projects/92/  ・レールズチュートは訳分からんから今はせん  ・テストもやらん  ・大丈夫少しずつ理解してるから、勉強とティックトックを行き来したら3日ぐらいで分かるようになる 4. 適当に演習をやる  ・rails課題、演習、練習、アプリを作ろうとか調べると何個か出る 5.テスト ・ここでRails tutorialを守備表示で特殊召喚(くどいからふぁーーーって流し読み) ・「何それ美味しいの?」から→「全然美味しくないやん」ってなったらおk 6.実際に作る ・チームのバックエンド組に合流 ・自分でウェブアプリ作ってみる ・クラウドソーシングで仕事探してみる
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

param is missing or the value is empty: というエラーが発生した時の対処法

事象 rails にてアプリを作成中に以下のエラー発生しました。 param is missing or the value is empty: task 問題点 ストロングパラメーターに関する内容でした。このエラーの意味はparamsが存在しない、もしくは空とのことです。 requireメソッドとはパラメーターの中にモデルに対応するキーが存在するかを確認し、存在する場合にそのバリューを返します。 tasks_controller.rb private def task_params params.require(:task).permit(:title, :description, :image) end 解決策 対処としてtasks_controller.rb のparams.require(:task)の箇所を削除し、以下のように修正します。これでエラーは出なくなりました。 tasks_controller.rb private def task_params params.permit(:title, :description, :image) end 参考 参考にさせていただきました。ありがとうございました。 ・【Rails】param is missing or the value is empty:について https://qiita.com/Takka_Log/items/32dae78d7e3892e7b051 ・【Rails】permitメソッドを使ってストロングパラメーターにしよう https://pikawaka.com/rails/permit
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

rails ActiveStorageを用いての画像投稿方法

ActiveStorageの導入方法は前回の記事を参考に・・ https://qiita.com/on97-nakamatsu-mayumi/items/9ca9f3a081b3cf6289cf 画像を保存しよう Active Storageのテーブルに、画像を保存するための実装を行います。 保存したいテーブルのレコードと画像を紐づけるためにhas_one_attachedというメソッドを利用します 各レコードとファイルを1対1の関係で紐づけるメソッドです。 has_one_attachedメソッドを記述したモデルの各レコードは、それぞれ1つのファイルを添付できます。 【例】has_one_attachedメソッド class モデル < ApplicationRecord has_one_attached :ファイル名 end :ファイル名には、添付するファイルがわかる名前をつけましょう テーブルに画像ファイルを紐付けましょう テーブルとActive Storageのテーブルで管理された画像ファイルのアソシエーションを記述します。 ここでは例でMessagesテーブルに紐づけます app/models/message.rb class Message < ApplicationRecord belongs_to :room belongs_to :user has_one_attached :image validates :content, presence: true end 画像の保存を許可するストロングパラメーターにしましょう imageという名前でアクセスできるようになった画像ファイルの保存を許可する実装を行います。 ここではすでに作られストロングパロメーターに追加する感じです。 まだ紐付けるテーブルの保存実装をしていなく、ストロングパロメーターを作っていなければ1から作る app/controllers/messages_controller.rb # 中略 private def message_params params.require(:message).permit(:content, :image).merge(user_id: current_user.id) end 保存した画像を表示しよう 画像の表示には、HTMLのimg要素を使用しますが、今回はRailsのヘルパーメソッドであるimage_tagを使用して、簡単に画像を参照します。 image_tagメソッドでは、複雑なRailsのディレクトリパスを指定しなくても、モデルから画像ファイルを呼び出して引数に記述するだけで、画像を表示するimg要素を生成します。 例】image_tagメソッド # ファイルをモデルから指定する場合 <%= image_tag モデル.画像ファイル %> <%= image_tag user.avatar %> # app/assets/ディレクトリ下の画像ファイルパスでも指定できる <%= image_tag 画像ファイルのパス %> <%= image_tag "avatar.png" %> シンプルに記述できるため、ビューでは積極的にヘルパーメソッドを使用しましょう。 例えば以下のように記述します。 <div class="message"> <div class="upper-message"> <div class="message-user"> <!-- 投稿したユーザー名情報を出力する --> <%= message.user.name %> </div> <div class="message-date"> <!-- 投稿した時刻を出力する --> <%= l message.created_at %> </div> </div> <div class="lower-message"> <div class="message-content"> <!-- 投稿したメッセージ内容を記述する --> <%= message.content %> </div> <%= image_tag message.image, class: 'message-image' %> </div> </div> しかし、このままの記述では、画像が存在しない場合でも、画像を表示する記述が読み込まれて、エラーを引き起こしてしまいます。 この問題を解決するために、メッセージに画像が添付されているかをチェックするattached?というメソッドを使用します。 attached?メソッド レコードにファイルが添付されているかどうかで、trueかfalseを返すメソッドです。 ifを使って、要素の生成に条件をつけ、attached?メソッドで画像の添付をチェックします。 <div class="message"> <div class="upper-message"> <div class="message-user"> <!-- 投稿したユーザー名情報を出力する --> <%= message.user.name %> </div> <div class="message-date"> <!-- 投稿した時刻を出力する --> <%= l message.created_at %> </div> </div> <div class="lower-message"> <div class="message-content"> <!-- 投稿したメッセージ内容を記述する --> <%= message.content %> </div> <%= image_tag message.image, class: 'message-image' if message.image.attached? %> </div> </div> 注意するのが現時点の実装では、画像のみの投稿はできない 拡張子が「.png」または「.jpeg」の画像を投稿してください。 画像の大きさを調節しよう 表示される画像の大きさを調節する実装です。 画像の大きさを調節する方法はたくさんありますが、今回はvariantというメソッドを用いて画像の大きさの調節をします。 variantメソッド Active Storageを導入している場合に使用可能なメソッドです。 【例】variantメソッド モデル.ファイル名.variant(resize: '幅x高さ') 画像の横幅と高さを指定しましょう <div class="message"> <div class="upper-message"> <div class="message-user"> <!-- 投稿したユーザー名情報を出力する --> <%= message.user.name %> </div> <div class="message-date"> <!-- 投稿した時刻を出力する --> <%= l message.created_at %> </div> </div> <div class="lower-message"> <div class="message-content"> <!-- 投稿したメッセージ内容を記述する --> <%= message.content %> </div> <%= image_tag message.image.variant(resize: '500x500'), class: 'message-image' if message.image.attached? %> </div> </div>
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Railsのloggerについてメモる

たまにこんがらがるのでメモ。 間違ってたら申し訳ない。 loggerを指定する変数 Rails.logger (→config.loggerのやつね) ActiveRecord::Base.logger (デフォルトだと何が代入されているんだろう...?) 存在するLoggerたち 標準出力するためのLogger ActiveSupport::Logger.new(STDOUT) ログファイルに書き出すLogger ActiveSupport::Logger.new('log/development.log', 'daily') # 引数なしで初期化したら、log/*.logが指定されるっぽい?? これらにより、 ActiveRecordのログを標準出力に書き出す ActiveRecord::Base.logger = Logger.new(STDOUT) その他 どうやらloggerを複数指定することもできるみたい → https://qiita.com/QUANON/items/8b212c04f2f3457eec87 参考 https://railsguides.jp/debugging_rails_applications.html
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

rails Active Storageの導入方法

rails で使用できるgem ActiveStorageの導入方法を書きます。 初心者の勉強用になります。 画像加工のために必要なImageMagickという画像変換ツールと、それをRailsから使うためのGemをインストールしましょう。 ImageMagick コマンドラインから画像に処理を加えることができるツールです。 処理としては、画像の作成やサイズ変更、保存形式の変更などがあります。 ImageMagickはGemではなく、ソフトウェアです。 そのため、Homebrewからインストールします。 GemではないImageMagickをRubyやRailsで扱うには、MiniMagickというGemが必要となります。 MiniMagick ImageMagickの機能をRubyで扱えるようにしてくれるGemです。 RailsでImageMagickを扱うために必要となります。 MiniMagickによって、ImageMagickの機能がRailsで使用できるようになりますが、画像サイズの変更には、もう1つImageProcessingというGemを追加する必要があります。 ImageProcessing MiniMagickでは提供できない、画像サイズを調整する機能を提供するGemです。 たくさんのツールとGemを紹介しましたが、それぞれの関係性は把握しておきましょう。 それでは、これらのツールとGemを導入します。 ImageMagickをインストールしましょう まずはImageMagickをHomebrewからインストールします。 brew install imagemagick Gemをインストールしましょう MiniMagickとImageProcessingをインストールします。以下のようにGemfileに追記しましょう。 # Gemfileの一番下に記述する gem 'mini_magick' gem 'image_processing', '~> 1 ターミナルでbundle installします。 bundle install もし、ローカルサーバーを立ち上げていたら、再起動させましょう。反映させる為になります。 Active Storageを使用する為に必要なツールのインストールは完了しました。 Active Storageをインストールしましょう Active Storageをアプリケーション内で使用する準備を行います。 rails active_storage:install rails active_storage:installコマンドを実行すると、Active Storageに関連したマイグレーションが作成されます。続けてマイグレートしましょう。 rails db:migrate Sequel Proを確認 Active Storageと画像加工ツールの導入は完了です。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【メモ】Gitで元に戻すときのコマンド【随時更新】

はじめに  アプリ開発中、リセットしたい時にいつもググっていたので自分用にまとめます。新しくコマンドを使うたびに更新していく予定です。 ステージング(git add .)前の編集を削除 Changes not staged for commit の編集を削除 これらはgit add .する前のファイルで git checkout .のコマンドで一つ前のコミットした状態に戻せる。 Untracked files の削除 これらはまだ一度もcommitしたことがないファイルで git clean -fのコマンドで削除可能。 おわりに Gitコマンドが覚えられない(泣) 随時更新予定
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Railsチュートリアル】第7章 ユーザー登録 演習と解答

Ruby on Railsチュートリアル 第7章の演習問題と解答をまとめました。 第7章 ユーザー登録 - Railsチュートリアル 演習と解答 7.1.1 デバッグとRails環境 7.1.1 - 1 ブラウザから /about にアクセスし、デバッグ情報が表示されていることを確認してください。このページを表示するとき、どのコントローラとアクションが使われていたでしょうか?paramsの内容から確認してみましょう。 7.1.1 - 2 Railsコンソールを開き、データベースから最初のユーザー情報を取得し、変数userに格納してください。 ① その後、puts user.attributes.to_yamlを実行すると何が表示されますか? ② ここで表示された結果と、yメソッドを使ったy user.attributesの実行結果を比較してみましょう。 コンソール $ rails console >> user = User.first (0.3ms) SELECT sqlite_version(*) User Load (1.0ms) SELECT "users".* FROM "users" ORDER BY "users"."id" ASC LIMIT ? [["LIMIT", 1]] => #<User id: 1, name: "Rails Tutorial", email: "michael@example.com", created_at: "2021-04-02 13:48:48", updated_at: "2021-04-02 13:58:42", password_digest: [FILTERED]> # ① puts user.attributes.to_yamlを実行すると何が表示されますか? >> puts user.attributes.to_yaml --- id: 1 name: Rails Tutorial email: michael@example.com created_at: !ruby/object:ActiveSupport::TimeWithZone utc: &1 2021-04-02 13:48:48.571772000 Z zone: &2 !ruby/object:ActiveSupport::TimeZone name: Etc/UTC time: *1 updated_at: !ruby/object:ActiveSupport::TimeWithZone utc: &3 2021-04-02 13:58:42.900038000 Z zone: *2 time: *3 password_digest: "$2a$12$heBkuvsV5p8QD5OxqBydgO6q3Wtkzf2EAUow0JhynlgNOSfFROXWq" => nil # ② yメソッドを使ったy user.attributesの実行結果を比較してみましょう。 >> y user.attributes --- id: 1 name: Rails Tutorial email: michael@example.com created_at: !ruby/object:ActiveSupport::TimeWithZone utc: &1 2021-04-02 13:48:48.571772000 Z zone: &2 !ruby/object:ActiveSupport::TimeZone name: Etc/UTC time: *1 updated_at: !ruby/object:ActiveSupport::TimeWithZone utc: &3 2021-04-02 13:58:42.900038000 Z zone: *2 time: *3 password_digest: "$2a$12$heBkuvsV5p8QD5OxqBydgO6q3Wtkzf2EAUow0JhynlgNOSfFROXWq" => nil ①と②の実行結果は同じ。 YAML(ヤメル)とは YAML(ヤメル) - wikipedia YAMLは再帰的に定義された頭字語であり "YAML Ain't a Markup Language"(YAMLはマークアップ言語じゃない)の意味である。 構造化データを人間の目にわかりやすいように表現できるように設計された言語。とのことです。 ターミナル >> user => #<User id: 1, name: "Rails Tutorial", email: "michael@example.com", created_at: "2021-04-02 13:48:48", updated_at: "2021-04-02 13:58:42", password_digest: [FILTERED]> ↓ターミナルに出力された内容をYAML形式で表現すると YAML id: 1 name: Rails Tutorial email: michael@example.com created_at: !ruby/object:ActiveSupport::TimeWithZone utc: &1 2021-04-02 13:48:48.571772000 Z zone: &2 !ruby/object:ActiveSupport::TimeZone name: Etc/UTC time: *1 updated_at: !ruby/object:ActiveSupport::TimeWithZone utc: &3 2021-04-02 13:58:42.900038000 Z zone: *2 time: *3 password_digest: "$2a$12$heBkuvsV5p8QD5OxqBydgO6q3Wtkzf2EAUow0JhynlgNOSfFROXWq" このように見やすく、分かりやすく表現されます。 プログラマーのための YAML 入門 (初級編) - るびま 7.1.2 Usersリソース 7.1.2 - 1 埋め込みRubyを使って、マジックカラム(created_atとupdated_at)の値をshowページに表示してみましょう(リスト 7.4)。 app/views/users/show.html.erb <%= @user.name %>, <%= @user.email %>, <%= @user.created_at %>, <%= @user.updated_at %> 7.1.2 - 2 埋め込みRubyを使って、Time.nowの結果をshowページに表示してみましょう。ページを更新すると、その結果はどう変わっていますか? 確認してみてください。 app/views/users/show.html.erb <%= @user.name %>, <%= @user.email %>, <%= @user.created_at %>, <%= @user.updated_at %> <br> <%= Time.now %> 7.1.3 debuggerメソッド 7.1.3 - 1 showアクションの中にdebuggerを差し込み(リスト 7.6)、ブラウザから /users/1 にアクセスしてみましょう。その後コンソールに移り、putsメソッドを使ってparamsハッシュの中身をYAML形式で表示してみましょう。ヒント: 7.1.1.1の演習を参考にしてください。その演習ではdebugメソッドで表示したデバッグ情報を、どのようにしてYAML形式で表示していたでしょうか? app/controllers/users_controller.rb class UsersController < ApplicationController def show @user = User.find(params[:id]) debugger end def new end end コンソール $ rails s # debbugerを差し込んだ状態で/users/1 にアクセス [1, 10] in /home/ubuntu/environment/sample_app/app/controllers/users_controller.rb 1: class UsersController < ApplicationController 2: 3: def show 4: @user = User.find(params[:id]) 5: debugger => 6: end 7: 8: def new 9: end 10: end (byebug) puts params.to_yaml --- !ruby/object:ActionController::Parameters parameters: !ruby/hash:ActiveSupport::HashWithIndifferentAccess controller: users action: show id: '1' permitted: false 7.1.3 - 2 newアクションの中にdebuggerを差し込み、/users/new にアクセスしてみましょう。@userの内容はどのようになっているでしょうか? 確認してみてください。 ターミナル [1, 10] in /home/ubuntu/environment/sample_app/app/controllers/users_controller.rb 1: class UsersController < ApplicationController 2: 3: def show 4: @user = User.find(params[:id]) 5: end 6: 7: def new 8: debugger => 9: end 10: end (byebug) @user nil 7.1.4 Gravatar画像とサイドバー 7.1.4 - 1 (任意)Gravatar上にアカウントを作成し、あなたのメールアドレスと適当な画像を紐付けてみてください。メールアドレスをMD5ハッシュ化して、紐付けた画像がちゃんと表示されるかどうか試してみましょう。 ターミナル $ rails c >> user = User.first User Load (0.2ms) SELECT "users".* FROM "users" ORDER BY "users"."id" ASC LIMIT ? [["LIMIT", 1]] => #<User id: 1, name: "Example User", email: "example@railstutorial.org", created_at: "2021-04-02 13:48:48", updated_at: "2021-04-03 13:55:44", password_digest: [FILTERED]> >> user.update(name: "Example User", ?> email: "Gravatarに登録したメールアドレス", ?> password: "foobar", ?> password_confirmation: "foobar") => true /users/1 にアクセス 7.1.4 - 2 7.1.4で定義したgravatar_forヘルパーをリスト 7.12のように変更して、sizeをオプション引数として受け取れるようにしてみましょう。うまく変更できると、gravatar_for user, size: 50といった呼び出し方ができるようになります。重要: この改善したヘルパーは10.3.1で実際に使います。忘れずに実装しておきましょう。 app/helpers/users_helper.rb module UsersHelper # 引数で与えられたユーザーのGravatar画像を返す def gravatar_for(user, options = { size: 80 }) size = options[:size] gravatar_id = Digest::MD5::hexdigest(user.email.downcase) gravatar_url = "https://secure.gravatar.com/avatar/#{gravatar_id}?s=#{size}" image_tag(gravatar_url, alt: user.name, class: "gravatar") end end 7.1.4 - 3 オプション引数は今でもRubyコミュニティで一般的に使われていますが、Ruby 2.0から導入された新機能「キーワード引数(Keyword Arguments)」でも実現することができます。先ほど変更したリスト 7.12を、リスト 7.13のように置き換えてもうまく動くことを確認してみましょう。この2つの実装方法はどういった違いがあるのでしょうか? 考えてみてください。 app/helpers/users_helper.rb module UsersHelper # 引数で与えられたユーザーのGravatar画像を返す def gravatar_for(user, size: 80) gravatar_id = Digest::MD5::hexdigest(user.email.downcase) gravatar_url = "https://secure.gravatar.com/avatar/#{gravatar_id}?s=#{size}" image_tag(gravatar_url, alt: user.name, class: "gravatar") end end オプション引数 オプション引数は引数に指定した、変数optionsにハッシュを代入する app/helpers/users_helper.rb module UsersHelper # 引数で与えられたユーザーのGravatar画像を返す def gravatar_for(user, options = { size: 80 }) size = options[:size] gravatar_id = Digest::MD5::hexdigest(user.email.downcase) gravatar_url = "https://secure.gravatar.com/avatar/#{gravatar_id}?s=#{size}" image_tag(gravatar_url, alt: user.name, class: "gravatar") end end p options[:size] {:size=>80} キーワード引数 キーワード引数はメソッドに引数を実装する際に、引数を”キー: 値”という形で設定 example.rb def test(key1: value1, key2: value2) end 実際にコードを書いて実行 example.rb def sale(title: 'DRAGON QUEST XII', price: 9800) p "タイトル:#{title}" p "価格:#{price}円" end irb > require './lib/example.rb' => true > sale "タイトル:DRAGON QUEST XII" "価格:9800円" # 引数を省略してメソッドを呼び出すとデフォルトの引数で実行される # sale(title: 'DRAGON QUEST XII', price: 9800) > sale(title: 'FINAL FANTASY XVI') "タイトル:FINAL FANTASY XVI" "価格:9800円" # 省略した引数pricenにはデフォルトの引数が渡される # sale(title: 'FINAL FANTASY XVI', price: 9800) > sale(title: 'MONSTER HUNTER RIZE', price: 7990) "タイトル:MONSTER HUNTER RIZE" "価格:7990円" 7.2.1 form_withを使用する 7.2.1 - 1 試しに、ブロックの変数fをすべてfoobarに置き換えてみて、結果が変わらないことを確認してみてください。確かに結果は変わりませんが、変数名をfoobarとするのはあまり良い変更ではなさそうですね。その理由について考えてみてください。 動作は変わりません app/views/users/new.html.erb <% provide(:title, 'Sign up') %> <h1>Sign up</h1> <div class="row"> <div class="col-md-6 col-md-offset-3"> <%= form_with(model: @user, local: true) do |foobar| %> <%= foobar.label :name %> <%= foobar.text_field :name %> <%= foobar.label :email %> <%= foobar.email_field :email %> <%= foobar.label :password %> <%= foobar.password_field :password %> <%= foobar.label :password_confirmation, "Confirmation" %> <%= foobar.password_field :password_confirmation %> <%= foobar.submit "Create my account", class: "btn btn-primary" %> <% end %> </div> </div> 変数名をfoobarとするのはあまり良い変更ではなさそうですね。その理由について考えてみてください。 変数名は一目で意味が理解できるように命名するのが適切だと考えます。 ブロック変数 f は「form」の「f」 (7.2.2) 7.2.2 フォームHTML 7.2.2 - 1 『Web基礎編: HTML』ではHTMLをすべて手動で書き起こしていますが、なぜformタグを使わなかったのでしょうか? 理由を考えてみてください 割愛 7.3.1 正しいフォーム なし 7.3.2 Strong Parameters 7.3.2 - 1 /signup?admin=1 にアクセスし、paramsの中にadmin属性が含まれていることをデバッグ情報から確認してみましょう。 7.3.3 エラーメッセージ 7.3.3 - 1 最小文字数を5に変更すると、エラーメッセージも自動的に更新されることを確かめてみましょう。 app/models/user.rb class User < ApplicationRecord before_save { email.downcase! } validates :name, presence: true, length: { maximum: 50 } VALID_EMAIL_REGEX = /\A[\w+\-.]+@[a-z\d\-]+(\.[a-z\d\-]+)*\.[a-z]+\z/i validates :email, presence: true, length: { maximum: 255 }, format: { with: VALID_EMAIL_REGEX }, uniqueness: true has_secure_password validates :password, presence: true, length: { minimum: 5 } #←minimum: の値を変更する end 7.3.3 - 2 未送信のユーザー登録フォーム(図 7.13)のURLと、送信済みのユーザー登録フォーム(図 7.19)のURLを比べてみましょう。なぜURLは違っているのでしょうか? 考えてみてください。 /usersにフォームの情報がPOSTされるから 7.3.4 失敗時のテスト 7.3.4 - 1 リスト 7.20で実装したエラーメッセージに対するテストを書いてみてください。どのくらい細かくテストするかはお任せします。リスト 7.25にテンプレートを用意しておいたので、参考にしてください。 name: "", email: "user@invalid", password: "foo", confirmation: "bar" でSignupすると以下↓ test/integration/users_signup_test.rb require 'test_helper' class UsersSignupTest < ActionDispatch::IntegrationTest test "invalid signup information" do get signup_path assert_no_difference 'User.count' do post users_path, params: { user: { name: "", email: "user@invalid", password: "foo", password_confirmation: "bar" } } end assert_template 'users/new' # エラーメッセージに対するテスト ----------------------------- assert_select 'div.alert', 'The form contains 4 errors.' assert_select 'div#error_explanation' do assert_select 'li', 'Name can\'t be blank' assert_select 'li', 'Email is invalid' assert_select 'li', 'Password confirmation doesn\'t match Password' assert_select 'li', 'Password is too short (minimum is 6 characters)' end # ------------------------------------------------------ end end 7.4.1 登録フォームの完成 7.4.1 - 1 有効な情報を送信し、ユーザーが実際に作成されたことを、Railsコンソールを使って確認してみましょう。 動作確認のため、省略 7.4.1 - 2 リスト 7.26を更新し、redirect_to user_url(@user)とredirect_to @userが同じ結果になることを確認してみましょう。 動作確認のため、省略 7.4.2 flash 7.4.2 - 1 コンソールに移り、文字列内の式展開(4.2.1)でシンボルを呼び出してみましょう。例えば"#{:success}"といったコードを実行すると、どんな値が返ってきますか? 確認してみてください。 ターミナル $ rails console >> "#{:success}" => "success" 7.4.2 - 2 先ほどの演習で試した結果を参考に、リスト 7.28のflashはどのような結果になるか考えてみてください。 rails_console >> flash = { success: "It worked!", danger: "It failed." } => {:success=>"It worked!", :danger=>"It failed."} >> "#{flash[:success]}" => "It worked!" >> "#{flash[:danger]}" => "It failed." 7.4.3 実際のユーザー登録 7.4.3 - 1 Railsコンソールを使って、新しいユーザーが本当に作成されたのかもう一度チェックしてみましょう。結果は、リスト 7.30のようになるはずです。 rails_console >> User.find_by(email: "example@railstutorial.org") User Load (0.3ms) SELECT "users".* FROM "users" WHERE "users"."email" = ? LIMIT ? [["email", "example@railstutorial.org"], ["LIMIT", 1]] => #<User id: 1, name: "Rails Tutorial", email: "example@railstutorial.org", created_at: "2021-04-28 02:52:06", updated_at: "2021-04-28 02:52:06", password_digest: [FILTERED]> >> 7.4.3 - 2 自分のメールアドレスでユーザー登録を試してみましょう。既にGravatarに登録している場合、適切な画像が表示されているか確認してみてください。 Gravatorに登録した自分のメールアドレスで登録↓ 7.4.4 成功時のテスト 7.4.4 - 1 7.4.2で実装したflashに対するテストを書いてみてください。どのくらい細かくテストするかはお任せします。リスト 7.32に最小限のテンプレートを用意しておいたので、参考にしてください(FILL_INの部分を適切なコードに置き換えると完成します)。ちなみに、テキストに対するテストは壊れやすいです。文量の少ないflashのキーであっても、それは同じです。筆者の場合、flashが空でないかをテストするだけの場合が多いです。 test/integration/users_signup_test.rb require 'test_helper' class UsersSignupTest < ActionDispatch::IntegrationTest # 省略 test "valid signup information" do get signup_path assert_difference "User.count", 1 do post users_path, params: { user: { name: "Example User", email: "user@example.com", password: "password", password_confirmation: "password" } } end follow_redirect! assert_template 'users/show'   # flashに対するテスト assert_not flash.empty? end end 7.4.4 - 2 本文中でも指摘しましたが、flash用のHTML(リスト 7.29)は読みにくいです。より読みやすくしたリスト 7.33のコードに変更してみましょう。変更が終わったらテストスイートを実行し、正常に動作することを確認してください。なお、このコードでは、Railsのcontent_tagというヘルパーを使っています。 app/views/layouts/application.html.erb <!DOCTYPE html> <!-省略-> <div class="container"> <% flash.each do |message_type, message| %> <div class="alert alert-<%= message_type %>"><%= message %></div> <!-以下に変更-> <%= content_tag(:div, message, class: "alert alert-#{message_type}") %> <!-ここまで-> <% end %>     <%= yield %> <%= render 'layouts/footer' %> <%= debug(params) if Rails.env.development? %> </div> <!-省略-> 7.4.4 - 3 リスト 7.26のリダイレクトの行をコメントアウトすると、テストが失敗することを確認してみましょう。 動作確認済み 7.4.4 - 4 リスト 7.26で、@user.saveの部分をfalseに置き換えたとしましょう(バグを埋め込んでしまったと仮定してください)。このとき、assert_differenceのテストではどのようにしてこのバグを検知するでしょうか? テストコードを追って考えてみてください。 ターミナル $ rails test "User.count" didn't change by 1. Expected: 1 Actual: 0 test/integration/users_signup_test.rb:27:in `block in <class:UsersSignupTest>' 21/21: [=============================================] 100% Time: 00:00:01, Time: 00:00:01 Finished in 1.85657s 21 tests, 43 assertions, 2 failures, 0 errors, 0 skips User.countが1から変化していないというエラーが発生してテストが失敗する
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

EC2でDocker+Rails+pumaでアップしたときにWebpacker can't find applicationを解決した

ローカルではきちんと動いていたのに、EC2に上げたら Webpacker can't find application と出てしまったときにどうやって対処したのかを話していきたいと思います。 結論 ローカルできちんと動いていたのは、Dockerを乗せる前にきちんとWebpackerやyarnなどのパッケージが入っていたからだと思います。 しかし、EC2はローカル環境とは全く違うので、そういった事は起きません。 なので、Dockerfileの中にnodeやyarnを入れてあげる記述をしてあげれば大丈夫です。 Dockerfile(before) FROM ruby:2.6.5 # 必要なパッケージのインストール(基本的に必要になってくるものだと思うので削らないこと) RUN apt-get update -qq && \ apt-get install -y build-essential \ libpq-dev \ yarn \ nodejs # 作業ディレクトリの作成、設定 RUN mkdir /app_name ##作業ディレクトリ名をAPP_ROOTに割り当てて、以下$APP_ROOTで参照 ENV APP_ROOT /app_name WORKDIR $APP_ROOT # ホスト側(ローカル)のGemfileを追加する(ローカルのGemfileは【3】で作成) ADD ./Gemfile $APP_ROOT/Gemfile ADD ./Gemfile.lock $APP_ROOT/Gemfile.lock # Gemfileのbundle install RUN bundle install ADD . $APP_ROOT Dockerfile(After) FROM ruby:2.6.5 # 必要なパッケージのインストール(基本的に必要になってくるものだと思うので削らないこと) RUN apt-get update -qq && \ apt-get install -y build-essential \ libpq-dev # yarnパッケージ管理ツールをインストール RUN apt-get update && apt-get install -y curl apt-transport-https wget && \ curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add - && \ echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list && \ apt-get update && apt-get install -y yarn # Node.jsをインストール RUN curl -sL https://deb.nodesource.com/setup_7.x | bash - && \ apt-get install nodejs # 作業ディレクトリの作成、設定 RUN mkdir /app_name ##作業ディレクトリ名をAPP_ROOTに割り当てて、以下$APP_ROOTで参照 ENV APP_ROOT /app_name WORKDIR $APP_ROOT # ホスト側(ローカル)のGemfileを追加する(ローカルのGemfileは【3】で作成) ADD ./Gemfile $APP_ROOT/Gemfile ADD ./Gemfile.lock $APP_ROOT/Gemfile.lock # Gemfileのbundle install RUN bundle install ADD . $APP_ROOT 以下のように、きちんとパッケージ管理ツールをDocker上でインストールするということがわかると思う。 これをしたあとに docker-compose build をしてあげれば、完成しました。 もし皆さんの約煮立てれば幸いです。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[Rails]simple_calenderの導入と実装

はじめに 簡単なカレンダー機能を実装したのでこちらでアウトプットします。 なお、コントローラやモデル、入力フォームといった部分は割愛しております。 成果物イメージ 実装 今回は、Simplecalendarというgemを導入して実装していきます 早速はじめていきましょう まずはgemを導入します。 gem 'simple_calendar', '~> 2.0' ※bundle installを忘れずに!!! 実は、極論これで完成といっても過言ではないです(笑) ビューには以下を記載します。 index.html.erb <%= month_calendar events: @events do |date, events| %> <%= date.day %> <% events.each do |event| %> <div class="title"> <%= event.title%> </div> <% end %> <% end %> 一行目のmonth_calendarの部分は月間カレンダーであることを示します。 ここを、週間カレンダーにしたい場合はweek_calendarとしてやればOKです。 なお、これらの詳しいビューについては以下のコマンドを叩くと生成できます。 rails g simple_calendar:views 個人的には、Googleの検証モードを使用してみてあげるのもわかりやすいかなと思います。 あとは、bootstrapの導入と個人的にCSS等で調整してあげれば成果物のような物が完成します。 個人的に苦しんだ部分を共有(CSS) 以上のようにカレンダー機能自体を実装することは簡単なのですが、デザインのところでかなり苦戦してしまいました。というのも、予定を入力した場合に、各日付のセル幅が、予定の内容の長さによって変わってしまい、カレンダーのデザインが崩れてしまいました。固定幅にするだけ!と鷹を括っていましたが、なぜかうまくいかず、、、 いろいろ調べてみたところ、以下のようにすると解決できました!! calendar.scss .table {  #省略 table-layout: fixed; } table-layoutでtableの列幅を指定します。fixedとするとことで、各列を均等の幅にしてくれます。 おわりに ざっくりとした導入の流れを記載いたしました。おそらく、触りながらの方が理解が早いかと思いますので、まずは実際にやってみることからお勧めします!
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

rails 6 でsemantic ui を使う

一. gemfileに追記 gem 'semantic-ui-sass' 二. bundle install bundle install 三. app/assets/stylesheet/application.scssに追記 @import "semantic-ui"; これでとりあえずは使える プルダウンなどはまた改めて
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

草野球の出欠確認Webアプリを作ろう! part.3

これから作っていく簡単なWebアプリの作成メモ(自分の備忘)です。 自分用なのであまり凝りすぎないように書いていきたい。 <<前回の記事 今回やったこと スケジュールコントローラーほかの生成 前回作成したScheduleモデルに対応するコントローラーやビューを作成していく。 あまりまとまった作業時間をとれていないので、ひとまず見た目や機能は気にしないで動くものを作っていこう。 (でも思いつきや寄り道は大事にしたいジレンマ、、、) $ bin/rails g controller Schedules index show new create edit update delete 生成されたルーティングを以下のように書き直す(個人の好みの問題)。 config/routes.rb Rails.application.routes.draw do # ルート root "users#index" # Users resources :users # Schedules resources :schedules end Users#indexのビューを作った時とほぼ同じものをコピペで作成した。 (以前views/users/index.html.erbを作った際にはif文の条件を@users.empty?としていたが、何か新しいアクションを追加したときにNoMethodErrorでシステムエラーを起こしたくないので@schedules.blank?として@schedulesがnilになってしまうことに備えた。) (本当は業務アプリでは上記のような「想定外を想定してゆるく作る」のはNGだと思うが、今回は遊びの面が強いのでなるべく作りの甘さが出ても動いてくれるようにしていきたい) views/schedules/index.html.erb <h1>チームの予定一覧</h1> <% if @schedules.blank? %> <div><%= "表示できる予定がありません。" %></div> <% else %> <div class="table_card"> <table align="center"> <thead> <tr> <th>件名</th> <th>予定日</th> </tr> </thead> <tbody> <% @schedules.each do |lst| %> <tr> <td><%= lst.title %></td> <td><%= lst.date_of %></td> </tr> <% end %> </tbody> </table> </div> <% end %> コントローラーも以下のように追記した。 controllers/schedules_controllers.rb def index @schedules = Schedule.all end ぎりぎり動く程度の実装はできたので、動作を確認する。 以下は動作確認のためのroot変更。 config/routes.rb # ルート # root "users#index" root "schedules#index" 上記によって、Railsサーバーに最初に接続したときのページがschedules/index.html.erbになる。 Rails6のデフォルトで、development環境ではプロファイラが表示される。 画面ハードコピーを取得する際に邪魔だったので、以下の記事を参考にAlt+pで非表示にした。 rails viewのプロファイラを非表示 他にも以下の記事のように、Railsサーバー起動時にデフォルトで表示されないようにできるらしい。 rack-mini-profilerの計測結果がWebページに表示しないようにする ふだんメインで使っているのはRails5.2.5なのでrack-mini-profilerを意識することがなかったが、かなり便利そうなので常時非表示にするのは惜しいと思いました。 そのため、rack-mini-profilerのREADMEを参考に、以下のようにして表示位置を右下にしてみた。 config/environments/development.rb require "active_support/core_ext/integer/time" Rails.application.configure do (中略) # rack-mini-profilerを右下に置く Rack::MiniProfiler.config.position = 'bottom-right' end 気に入ったので、しばらくこれでいってみようと思います。 (development.rbに記述した内容が反映されるのは、Railsサーバーの再起動時という点に注意) 今日も短いけどここまで。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

アプリの一括削除

初めに アプリケーションを作成している際に、DBに何かのエラーが出たが解決できず、一度全て削除し、再作成を試みました。 1.アプリケーションフォルダ内でDBの削除 $ rails db:drop 2.一つ上のフォルダに移動し、アプリの削除 $ cd .. $ rm -rf [削除したいアプリ名] 以上です。      
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む