20211014のRailsに関する記事は6件です。

ルーティングのネストについて!

①.結論! ネストは、ある記述の中に別の記述をして、親子関係を示す方法です! 「入れ子構造」とも呼ばれます! ルーティングにおけるネストとは、あるコントローラーのルーティングの中に、別のコントローラーのルーティングを記述することです! ルーティングをネストさせる一番の理由は、アソシエーション先のレコードのidをparamsに追加してコントローラーに送るためです! 例を見ながら解説していきます! ②.記述について! 下記が記述の形になります! routes.rb Rails.application.routes.draw do resources :親となるコントローラー do resources :子となるコントローラー end end ルーティングでネストを利用すると、アクションを実行するためのパスで、親子関係を表現できます! 例えば、eats_controller.rbのルーティングの中にcomments_controller.rbのルーティングを記述します! ネストを利用したときに設定されるルーティングの例を見てみます! 【例】ネストを利用した場合 Prefix Verb URI Pattern Controller#Action eat_comments POST /eats/:eat_id/comments(.:format) comments#create パスの:eat_idという部分に記述された値は、パラメーターとして送られます! もし、ネストを利用しなかった場合は、:eat_idのような、パスにパラメーターを含められる部分がありません! 【例】ネストを利用しなかった場合 Prefix Verb URI Pattern Controller#Action comments POST /comments(.:format) comments#create 以上からわかるように、ルーティングにネストを利用しなければ、モデルと結びついている別モデルのid情報が送れなくなります! ネストを利用すれば、id情報を含めることができます! 最終的な書き方の例は以下の通りです! routes.rb Rails.application.routes.draw do resources :eats do resources :comments, only: :create end end ③.まとめ ネストとは、入れ子構造とも呼ばれ、ある記述の中に別の記述をする方法のこと! と言う事ですね! なかなか難しいですが、1つ1つ概念を分解して理解することが大切だと思います! 何か説明で間違っていたらご指導お願い致します(_ _)
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

rspecで ActionView::Template::Error:に遭遇した!

メール送信機能を追加した後に、いつも通りプルリクだして自動テストの結果を待ってた rspec関連は今回いじってなかったのでエラーの通知がslackに飛んできてびっくりし^^; エラー内容 2) PostProduct valid if post_id is different Failure/Error: <p><%= link_to 'クリックして登録を完了する', controller: 'users/confirmations', action: 'create', confirmation_token: @token %></p> ActionView::Template::Error: Missing host to link to! Please provide the :host parameter, set default_url_options[:host], or set :only_path to true exampleは16作っているのですが、出たエラー全てこれでした。 エラーになっているのは、確認メールの中身なので本当に原因がわからなかった missing hostって書いてあるくらいだからhostがないのでホストを設定するかonly_pathを設定するかしてくださいみたいな感じかな 解決 hostは設定していたと思っていたのですが、設定していたのはdevelopment環境だけ!! rspecを実行するtest環境では設定しなかったことに気づき、 config.action_mailer.default_url_options これをtest.rbに設定しましたところ。。。。。 全てのexampleがパスしました!
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Rails】EC2サーバーのエラーログを確認する方法

先日unicornの自動デプロイでエラーが起き、解決に時間がかかってしまったため、エラーログで素早く原因究明するための手順を備忘録としてアウトプットしていきます。 前提条件(本番環境) ・仮想OS:AWS(EC2) ・WEBサーバ:Nginx ・アプリケーションサーバ:unicorn ・データベース:MariaDB エラーログを確認する際の注意点 ※unicornでエラーが起きた場合の、エラーログの確認場所はすでに自身で設定しているはずです。  そのため人によってディレクトリ名が異なる場合があります。以下を確認しましょう。 config/unicorn.rb (省略) #エラーのログを記録するファイルを指定 stderr_path "#{app_path}/log/unicorn.stderr.log" (省略) エラーログを確認する手順 ※個人情報保護の観点から、一部コードを改変しています。 ※ここでは分かりやすいようにlsコマンドを使って、適宜ディレクトリの中身を確認しています。 ユーザー名@PC名 ~ % cd .ssh/ ユーザー名@PC名 .ssh % ssh -i ダウンロードした鍵の名前.pem ec2-user@作成したEC2インスタンスに紐付けたElastic IP    例)% ssh -i test.pem ec2-user@1.234.5.678 Last login: Wed Oct 13 02:31:20 2021 from 12.345.678.901.cyberhome.jp __| __|_ ) _| ( / Amazon Linux 2 AMI ___|\___|___| https://aws.amazon.com/amazon-linux-2/ 8 package(s) needed for security, out of 24 available Run "sudo yum update" to apply all updates. [ec2-user@ip-123-45-67-890 ~]$ cd /var/www/アプリ名 [ec2-user@ip-123-45-67-890 アプリ名]$ cd current [ec2-user@ip-123-45-67-890 current]$ ls Capfile Gemfile.lock REVISION app babel.config.js config db log package.json public test.dio storage tmp yarn.lock Gemfile README.md Rakefile assets_manifest_backup bin config.ru lib node_modules postcss.config.js spec test_move.dio test vendor [ec2-user@ip-123-45-67-890 current]$ cd log [ec2-user@ip-123-45-67-890 log]$ ls production.log unicorn.stderr.log unicorn.stdout.log [ec2-user@ip-123-45-67-890 log]$ less unicorn.stderr.log まずEC2サーバーへログインしたのち、EC2サーバのlogディレクトリまで移動します。 lsコマンドでlogディレクトリの中身を見てみると、3種類のlogがあることが分かります。 このうち次の2つに注目します。 production.log ブラウザにWe’re sorry, but 〜と表示された時に確認するlogです。 サーバーログを記録する場所で、いわば「EC2内での出来事を記録している場所」です。 Ruby on Railsを例にすると、開発環境でrails sを使ってアプリケーションを実行したとき、様々なログが表示されるのと同じ役割を持っています。 unicorn.stderr.log ターミナルにmaster failed to start, check stderr log for detailsと表示された時に確認するlogです。 今回はこちらのlogの中身を確認してきます。 ファイルの中身を確認する方法 lessコマンドを使います less unicorn.stderr.log エラーログを効率よく確認する方法 lessコマンドでlogファイルを開くと、大量のlogが並んでいると思いますが、これを全て確認する必要はありません。 エラーログを確認する上で大切なのはエラーが起きた直後のlog、つまり最新のlog周りを見ていきます。 最新のログを確認する2つの方法 ①lessコマンドでログファイルを開いた後、Shift + gでログファイルの一番下へ移動する。 ②lessコマンドを実行する代わりに、tail -f ファイル名コマンドで最新のログを10行分だけ表示する。 ①は全体を残しつつ最新ログから遡ることができ、②は最新ログだけを見ることができます。 どちらもメリットがあるため、状況に応じて使い分けていきましょう。 ※ログファイルからは:wqで抜けられます。 エラーログの見つけ方 ここまできたら、あとはエラー原因が書かれているログを探して対処するだけです。 あくまで個人的な見解ですが、エラーログの特徴として次のことが挙げられます。 ・他のログに比べてやや長文(少し飛び出している) ・「○○Error」や「○○ didn't」のようにErrorや否定文が含まれている エラーが起きたら確認すること 自動デプロイ未設定の場合 ・ローカル→GiuHubへのpushのし忘れはないか(mergeまで確認) ・GitHubからEC2への反映(git pull origin master)のし忘れはないか ・EC2サーバー側でエラーログの内容を確認し、原因を見つける ・データベースは正しく起動しているか ・EC2サーバー側の環境変数は正しく設定できているか ・EC2インスタンスの再起動を行ってみる 自動デプロイ設定済の場合 上記に加えて、 ・unicornのプロセスをkillし忘れていないか(masterとworker両方をkill) ※これを行わなければ、自動デプロイでunicornを再起動できません。 ・ローカルのターミナルかつアプリケーションのディレクトリで自動デプロイコマンドを実行しているか(自動デプロイコマンド→bundle exec cap production deploy) ※手動デプロイで使用していたunicornの再起動コマンドRAILS_SERVE_STATIC_FILES=1 unicorn_rails -c config/unicorn.rb -E production -Dは使うと「ArgumentError」になります。これは自動デプロイを設定したことで、unicornの再起動コマンドが変更されたため、手動デプロイコマンドが使えなくなっているためです。 以上、EC2サーバーのエラーログを確認する方法でした。 ご指摘などあれば、ご教授いただけると幸いです。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【RSpec】重複するテストコードを共通化しよう

重複するテストコードはshared_contextやshared_examplesで共通化できる rails_helperの設定 下記の記述のコメントアウトを外す spec/rails_helper.rb ... Dir[Rails.root.join('spec', 'support', '**', '*.rb')].sort.each { |f| require f } ... ↑を忘れると下記のエラーで怒られる ArgumentError: Could not find shared context "hogehoge" shared_contextで重複するコードをまとめる spec下にディレクトリを作成して共通化したい処理を記述 spec/support/contexts/login_setup.rb RSpec.shared_context 'login setup' do before do Rails.application.env_config["devise.mapping"] = Devise.mappings[:user] Rails.application.env_config["omniauth.auth"] = OmniAuth.config.mock_auth[:google_oauth2] sign_in user end end include_context 'login setup'に置き換えるだけ spec/requests/XXXXX_spec.rb RSpec.describe "/XXXXX", type: :request do describe 'GET /XXXXX' do ... include_context 'login setup' ... end end shared_examplesで重複するコードをまとめる shared_contextのときと同じようにファイルを作成する spec/support/contexts/login_user.rb RSpec.shared_examples 'login user' do it 'ログインしているユーザーを取得すること' do expect(response).to have_http_status(200) ... end end spec/requests/XXXXX_spec.rb RSpec.describe "/XXXXX", type: :request do describe 'GET /XXXXX' do context '@user' do it_behaves_like 'login user' end end end include_examplesとit_behaves_likeの違い shared_examplesを使うときはinclude_examplesよりit_behaves_likeを使うほうがよい include_examplesは定義の上書きが起きてしまうらしい 詳しくは↓ 参考
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

RailsとTiDBの統合について

この記事は dev.toで発表されたものです。 このチュートリアルは、RailsとTiDBの統合に関する、おそらくWebで初めてのチュートリアルです。TiDBは、水平的なスケーラビリティ、高可用性、MySQLとの互換性を特徴とする、オープンソースの分散SQLデータベースです。 初心者にとって、ActiveRecordのような複雑なORMをTiDBに統合するのは難しい可能性があります。Web上にはこのトピックを扱っている記事がほとんどないことから、私はRailsユーザーによるTiDB導入を支援するために、このチュートリアルを執筆しました。 TiDB開発環境をローカルで構築する Railsとの統合に先立って、TiDBクラスタをローカルマシンにデプロイする必要があります。TiDBでは、TiDBエコシステム用のパッケージマネージャーであるTiUPによって、デプロイを円滑に進められるようになっています。 TiUPのインストール TiUPのインストールは、Darwin、Linuxのどちらのオペレーティングシステムからも簡単に行うことができます。次のコマンドを実行するだけです。 $ curl --proto '=https' --tlsv1.2 -sSf https://tiup-mirrors.pingcap.com/install.sh | sh これによって$HOME/.tiup/binがPATH環境変数に追加され、TiUPを直接使用できるようになります。 ローカルクラスタの確立 一般的にTiDBクラスタは複数のノードを必要とするため、デプロイが複雑で時間がかかる場合があります。そのためTiUPは、TiDBのテスト環境をローカルですばやく構築できる、TiUPコンポーネントのplaygroundを用意しています。 このコマンドは次のようにシンプルなものです。 $ tiup playground 次のように出力されます。 $ tiup playground Starting component ``playground``: /Users/hooopo/.tiup/components/playground/v1.4.1/tiup-playground Use the latest stable version: v5.0.0 Specify version manually: tiup playground <version> The stable version: tiup playground v4.0.0 The nightly version: tiup playground nightly Playground Bootstrapping... Start pd instance Start tikv instance Start tidb instance Waiting for tidb instances ready 127.0.0.1:4000 ... Done Start tiflash instance Waiting for tiflash instances ready 127.0.0.1:3930 ... Done CLUSTER START SUCCESSFULLY, Enjoy it ^-^ To connect TiDB: mysql --host 127.0.0.1 --port 4000 -u root -p (no password) To view the dashboard: http://127.0.0.1:2379/dashboard To view the Prometheus: http://127.0.0.1:9090 To view the Grafana: http://127.0.0.1:3000 これでローカルクラスタが確立されました。 TiDB Dashboardへのアクセス TiDBには、クラスタを監視するためのWeb UI、TiDB Dashboardが用意されています。これはすでにPDコンポーネントに組み込まれており、http://127.0.0.1:2379/dashboard から直接アクセスできます。 TiUPの詳細については、公式ドキュメントをご覧ください。 RailsをTiDB用に設定する TiDBクラスタを確立したところで、次にこれをRailsと統合します。 Railsプロジェクトの作成 TiDBはMySQLとの互換性があるため、MySQL用に設定されたRailsアプリを作成できます。 $ rails new myapp --database=mysql database.ymlの設定 database.ymlでは次の2つの重要な設定があります。 portを4000に設定します。ローカルのTiDBクラスタは、4000をデフォルトのポートとして使用します。 データベース接続変数tidb_enable_noop_functionsをONに設定します。Railsは、TiDBではデフォルトで無効になっているget_lock関数を使用する必要があります。 default: &default adapter: mysql2 encoding: utf8mb4 pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %> port: 4000 username: root password: host: 127.0.0.1 variables: tidb_enable_noop_functions: ON URIメソッドを使用してデータベース接続を設定する場合も、設定方法は同様です。 default: &default adapter: mysql2 encoding: utf8mb4 pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %> url: <%= ENV.fetch("DB_URL") || "mysql2://root:pass@localhost:4000/myapp" %> variables: tidb_enable_noop_functions: ON プライマリキー、自動インクリメント、一意インデックスの設定 usersというテーブルを作成します。 class CreateUsers < ActiveRecord::Migration[6.1] def change create_table :users do |t| t.string :email t.string :password t.string :username t.timestamps end end end 一意インデックスを追加します。 class AddUniqueIndexForEmail < ActiveRecord::Migration[6.1] def change add_index :users, :email, unique: true end end TiDBはMySQLとの互換性があるため、使用方法はスタンドアロンのMySQLデータベースとほとんど同じです。プライマリキー、自動インクリメント、一意インデックスなどの機能について互換性がない他の分散データベースと比較して、追加の処理が不要なTiDBは導入が非常に容易です。 ここまでで、次のようなデータテーブルが生成されます。 mysql> show create table users; + -------+------------------------------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------+ | Table | Create Table | +-------+------------------------------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------+ | users | CREATE TABLE `users` ( `id` bigint(20) NOT NULL AUTO_INCREMENT, `email` varchar(255) DEFAULT NULL, `password` varchar(255) DEFAULT NULL, `username` varchar(255) DEFAULT NULL, `created_at` datetime(6) NOT NULL, `updated_at` datetime(6) NOT NULL, PRIMARY KEY (`id`) /*T![clustered_index] CLUSTERED */, UNIQUE KEY `index_users_on_email` (`email`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin AUTO_INCREMENT=30001 | +-------+------------------------------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------+ 1 row in set (0.01 sec) セーブポイントへのパッチの追加 TiDBとActiveRecordを結合するうえで1つだけ障害になるのが、現時点ではTiDBではセーブポイントがサポートされていないことです。そこで、これを解決する簡単なパッチを作成しました。 # https://github.com/rails/rails/blob/6-1-stable/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb#L313 require 'active_record/connection_adapters/abstract/database_statements.rb' module DisableSavepoint def transaction(requires_new: nil, isolation: nil, joinable: true) if requires_new requires_new = nil Rails.logger.warn "savepoint statement was used, but your db not support, ignored savepoint." Rails.logger.warn caller super(requires_new: requires_new, isolation: isolation, joinable: joinable) else super(requires_new: requires_new, isolation: isolation, joinable: joinable) end end end ActiveRecord::ConnectionAdapters::DatabaseStatements.send(:prepend, DisableSavepoint) Railsでセーブポイントを使用するのは、トランザクションがtrueをパラメータrequires_newに渡す場合に限られます。その場合は、このパッチによってrequires_newの値がnilに変更され、移行のためのログが出力されます。 私の経験では、Railsプロジェクトでセーブポイントが頻繁に使用されることはほとんどないため、移行が必要になった場合でも大きな問題はありません。マイグレーションを行う場合はセーブポイントを使用しますが、並行して実行する移行がなければ、セーブポイントを削除しても予期しない結果になることはありません。 参考資料 What's New in TiDB 5.0 tidb_enable_noop_functions TiDB's Compatibility with MySQL Source code for rails-tidb Demo
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[Ruby]any?を||の代わりに使わない

Rubyの配列(Array)にはany?という便利メソッドがあります。 すべての要素が偽である場合に false を返します。真である要素があれば、ただちに true を返します。 ブロックを伴う場合は、各要素に対してブロックを評価し、すべての結果が偽である場合に false を返します。ブロックが真を返した時点で、ただちに true を返します。 上記はドキュメントから転記しました。 any?を使うことで、配列内に特定の条件を満たした要素が1つ以上あること(または存在しないこと)を確認することができます。 また、真の要素が見つかったら以降の判定は行われないと記載されているため計算効率も良いです。 簡単に動作確認をしてみます。 配列[5, 3, 4]の中に3以下の数値があるかをチェックしています。 何が判定されたか可視化できるように判定ごとにp _1で判定した要素を出力するようにしています。 irb(main):005:0> ary = [5, 3, 4] irb(main):012:1> ary.any? do irb(main):013:1* p _1 irb(main):014:1* _1 <= 3 irb(main):015:0> end 5 3 => true 2つ目の要素3がtrueとなるため、以降の要素4は判定されていないことがわかります。 また、配列内の要素の真偽を判定するだけであれば、ブロックやパタメーターなしで使うことができます。 irb(main):028:0> [nil, 'a'].any? => true any? を || の代わりに使わない ここからがこの記事の本題です。 ブロックやパラメーターなしのany?を応用すると、複数項目のor条件の代わりに使えることがわかります。 例えばifの条件であったり、?メソッドの戻り値などでany?を使えます。 if hoge? || fuga? || piyo? # hoge?, fuga?, piyo?のいずれかがtrueの場合に実行される end # any?を使って下記のように書くこともできる if [hoge?, fuga?, piyo?].any? end # hoge?, fuga?, piyo?のいずれかがtrueか? def any_truthy? hoge? || fuga? || piyo? end # any?を使って下記のように書くこともできる def any_truthy? [hoge?, fuga?, piyo?].any? end 当初、私はどちらの書き方も好みの問題だけで、どちらでも良いと考えていました。 ただ、このパターンの場合は明確に||の方が良いということができます。 実際にhoge?, fuga?, piyp?メソッドを使って処理を確認してみます。 今回はfuga?だけがtrueを返却するようにしています。また、呼び出されたことがわかるようにプリントするようにしています。 def hoge? p 'hoge' false end def fuga? p 'fuga' true end def piyo? p 'piyo' false end ここで下記のように判定した場合、どうなるでしょうか? [hoge?, fuga?, piyo?].any? 前から処理していくと、fuga?がtrueを返却するのでpiyo?は確認しなくてもany?はtrueが確定しているのですがpiyo?も実行されてしまいます。 irb(main):015:0> [hoge?, fuga?, piyo?].any? "hoge" "fuga" "piyo" => true 一方、||を使うとpiyo?の判定は行われません。 irb(main):015:0> hoge? || fuga? || piyo? "hoge" "fuga" => true 上記の通り、any?を使った場合は3つのメソッドが全て呼び出されますが、||の場合はhoge?やfuga?がtrueになった場合に後続メソッドが呼び出されないので効率が良いです。 any?も真の要素が見つかれば処理が中断するのではなかったっけ??という疑問が起きると思いますが、[hoge?, fuga?, piyo?].any?の処理を分解すると下記のように動作しています。 最初に配列[hoge?, fuga?, piyo?]を生成 この時点でhoge? / fuga? / piyo?は判定されて、[false, true, false]という配列が生成されています。 [false, true, false]を先頭から順に判定 2つ目がtrueのため判定は終了します。最後のfalseの判定は行われません。 判定の前に配列の生成を行ってしまうため、配列内の要素はすべて実行されてしまうんですね。 上記のように||の代わりにany?を使う場合は、好みの問題だけでなくパフォーマンスにも影響があるので||を使うようにしましょう。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む