20220110のRailsに関する記事は10件です。

Railsで複数レコードを更新する書き方メモ

はじめに Railsで複数レコードを作成、更新する際にActiveRecord::Base.transactionをどのように用いるかを調べた際のメモです。 主に以下を参考にさせていただきました。 https://qiita.com/aba0312/items/8b29cafe6b505b6a7a4f https://www.youtube.com/watch?v=jFBvEQhApKQ 例 例えば、ユーザーのバルクインサートを行う際に全てのインサートが成功しなければロールバックするという想定をします。 User.rb class User < ApplicationRecord def self.bulk_create(users) all_valid = true transaction(join_table: false, requires_new: true) do users.each do |user| # 何らかの処理 all_valid &= user.save end unless all_valid raise ActiveRecord::Rollback end end all_valid end end transactionの引数である、join_tableやrequires_newはこちらを参考にしました。 https://qiita.com/jnchito/items/930575c18679a5dbe1a0 この書き方をすることによって、システムエラー(プログラムのバグにより起こるエラー)が起きればその時点でロールバックがされますし、業務エラー(ユーザーの操作によるエラー)が起きればRollbacを明示的にするようにしています。 users_controller.rb class UsersController < ApplicationContoller def create if User.bulk_create(@users) redirect_to :index else # エラー通知 render :new end end end おわりに おかしい部分があるかもしれません。ご指摘あればよろしくお願い致します。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Rails】form_withとは?

form_withとは? form_withは、htmlのformタグを生成するためのメソッド。 どうなるの? 「生成する」というのは少し難しい表現ですが、「置き換わる」と考えても問題ありません。 つまり、form_withのところに、<form action=~というhtmlのタグが置き換わります。 へー!すごいね! このようにhtmlを生成するメソッドをビューヘルパーと呼んでいます。 ちなみに... ・link_toとは:<a href=~というaタグに置き換わる。ビューヘルパーの一つです。 ・f.number_fieldとは:inputタグに置き換わる。ビューヘルパーの一つです。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

gem acts_as_list の使い方

acts_as_listとは indexページなどで一覧表示しているデータの並び替えを簡単の実装できるgenのことです。このgemを利用することで各データごとに ”↑”、”↓” などのリンクを表示させクリックすることでそれぞれの並びを一つ上、一つ下と変更することが簡単になります。 acts_as_list使い方 ・Gemfileに以下を追加し、bundle install gem 'acts_as_list' ・”position”カラムの追加 acts_as_listで並び替えをする際の基準となるカラムは、”id”ではなく”position”というカラムです。これはもちろん元々モデルにあるものではないため、もしモデルを作成済みであれば新くmigrationファイルを作り、カラムを追加する必要があります。 ・migrationファイルの作成 Taskモデルにカラムを追加したい場合以下のmigrationファイルを作成します。 class AddColumnPositionToTasks < ActiveRecord::Migration[5.2] def change add_column :tasks, :position, :integer end end こちらのファイルを作成した後 rails db:migrate 。 (もし既存のデータがある場合、positionカラムにデータを入れておかなくてはいけません。自分の場合はrailsコンソールで各データのidを初期のpositionの値としました。) ・modelファイルにacts_as_listを利用するためのコードを追加する カラムを用意しただけではgemの機能を使えるようにはなりません。並び替えの機能をモデルに追加するために、modelファイル内に”acts_as_list”というコードを追加してください。これで並び替えの機能を利用できるようになります。 class Task < ApplicationRecord acts_as_list #この一行を追加 end ・viewページに並び替えのリンクを追加する 一覧表示されているデータに並び順を変更するアクションへのリンクを書きます。 <h1>データ一覧</h1> <table> <% @tasks.each do |task| %> <tr> <td><%= task.title %></td> <td><%= task.body %></td> <td><%= link_to "↑", move_higher_task_path(task) %></td><!--並び順をひとつ上へ --> <td><%= link_to "↓", move_lower_task_path(task) %></td> <!--並び順をひとつ下へ --> </tr> <% end %> </table> ・ルーティングの追加 viewに追加したリンクを並び替えのアクションに紐付けるためのルーティングを記述します。 resources :tasks do member do get :move_higher get :move_lower end end ・actionの追加 最後に、並び変えの機能を利用できるようになったのでcontroller内で実際の並び替えをするコードを書いていきます。 def index @tasks = Task.all.order(:position) #Task.allだけだとIDの順番でデータが表示されてしまうため"position"カラムを基準に並べ替えをする必要がある end def move_higher Task.find(params[:id]).move_higher #viewで選択したtaskを一つ上の並び順に変更する redirect_to tasks_path end def move_lower Task.find(params[:id]).move_lower #viewで選択したtaskを一つ下の並び順に変更する redirect_to tasks_path end これだけでデータを一覧表示する際の並び順を簡単に変更することができます。 タスク管理など優先順位の入れ替えなどをしたいときに便利なgem “acts_as_list”の使い方でした。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Rails memberとcollectionの違い

結論 memberを用いることでidを用いて特定のリソースに対してアクションを実行することができ、collectionを用いることで全てのリソースに対してアクションを実行することができる。 公式API member https://api.rubyonrails.org/classes/ActionDispatch/Routing/Mapper/Resources.html#method-i-member collection https://api.rubyonrails.org/classes/ActionDispatch/Routing/Mapper/Resources.html#method-i-collection member routes.rb resources :users do member do get :hoge end end memberを使うとルーティングは以下のようになります。 idを指定することができるので特定のUserに対してhogeアクションを行いたい場合に用いることができます。 collection routes.rb resources :users do collection do get :piyo end end collectionを用いるとルーティングは以下のようになります。 memberを用いた場合とは異なり、idを指定しないので全てのUserに対してpiyoアクションを行いたい場合に用いることができます。 おわりに 特定のリソースに対してアクションを実行するか、全てのリソースに対してアクションを実行するかによってmemberとcollectionを使い分けることが必要です。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Rails】ajax化とは

ajax化とは Asynchronous JavaScript + XML の略で、非同期通信と呼ばれる通信方法のこと。 Webブラウザ上で非同期通信を行い、ページ全体の再読み込み無しにページを更新する。 同期通信、非同期通信とは? ◆同期通信 クライアントとサーバー間の通信においては、通常、同期通信と呼ばれる方法が用いられ、一瞬画面が白くなった後、画面が切り替わるような通信は、全てこの同期通信となる。 ページが一瞬真っ白になってから表示されるまでの間は、ユーザーは他の操作を何もする事が出来ない。また、同期通信はページ全体を1から作成して表示させているので、どうしても表示までの時間がかかる。 ◆非同期通信 一方、非同期通信では、クライアントからのリクエスト送信後、サーバーの処理中にも、ページ遷移無しに他の作業を行うことができる。 Railsにおけるajax化の方法 非同期通信の方法は2種類あり、 ①remote:true形式 ②ajax関数を使った形式 の2パターンが存在するが、今回はremote:true形式を記載。 例として、掲示板のお気に入り(いいね)ボタンを押した時に、お気に入りの登録、解除を行うという仕組みをajax化していく。 1.コントローラーの設定 redirect先の指定をコメントアウト。 bookmarks_controller.rb class BookmarksController < ApplicationController def create @board = Board.find(params[:board_id]) current_user.bookmark(@board) # redirect_back fallback_location: root_path,success: t('user_sessions.boards.bookmarks.create.success') end def destroy @board = current_user.bookmarks.find(params[:id]).board current_user.unbookmark(@board) # redirect_back fallback_location: root_path,success: t('user_sessions.boards.bookmarks.destroy.success') end end 2.ブックマークボタンをajax化 ブックマークボタンのコードを記載している app/views/boards/_bookmark.html.erb app/views/boards/_unbookmark.html.erb この2つのコード内の<%= link_to ~ %>にremote: trueを追加。 remote: trueを指定することによって、AjaxでHTTPリクエストを送信するように設定される。 更に、html.erbファイルではなくjs.erbファイルをレンダリングしてくれる。 3.ブックマークボタンの切り替え処理を追加 指定したid属性を持つ部分を置き換える。それぞれブックマーク登録・解除に置き換えるよう記述。 $(置換対象).replaceWith(置換後の要素) replaceWithは要素を置換するメソッド。 app/views/bookmarks/create.js.erb $("#js-bookmark-button-for-board-<%= @board.id %>").replaceWith("<%= j(render('bookmarks/unbookmark', board: @board)) %>"); app/views/bookmarks/destroy.js.erb $("#js-bookmark-button-for-board-<%= @board.id %>").replaceWith("<%= j(render('bookmarks/bookmark', board: @board)) %>"); 参考記事 ⭐️ブックマークボタンのajax化 【Rails】remote:true形式でAjax通信を行う(お気に入り登録機能のajax化) 【IT用語】 Ajaxとは?初心者向けに豊富な画像で仕組みを解説
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

インフラ素人が3週間で、Webサービスのインフラを0から構築して起きた変化

目次 1. インフラ設計 2. ネットワーク構築 3. サーバ・DB構築 4. Lambdaによる自動化 5. Amazon SES・SNS 6. 開発環境構築(docker) 7. jenkins・phpmyadminなど開発ツール設定 8. VPN接続 9. 起きた変化 10. おまけ はじめに インフラ素人同然レベルだった私が実務において、Webアプリケーションのインフラを0から構築することになりました。 期間は約3週間、インフラ設計から行い、構築したインフラ上でWebサービスが稼働できる状態まで持っていくことがゴールになります。  約3週間の間、AWSやミドルウェア周りの技術に触れ、今まで考えてもみなかった知識の習得や、多くのつまづきを通して貴重な経験をすることができました。 チームメンバーと分担しながら進めたので、あくまで自分のやったことベースにはなりますが、3週間どんなことをやったのか、特につまづいたことを中心に書いていきたいと思います。 ※基本的なインフラ構成はほぼ全てAWSのリソースを使用しました。 【使用技術】 ・ AWS(EC2, RDS, VPC, Route53, Lambda, IAM, SES, SNS, ACM, CloudWatch, etc.) ・ docker ・ Nginx(Webサーバ) ・ Puma(アプリケーションサーバ) ・ Ruby on Rails 開始前の筆者のレベルを3行で! ・自社開発エンジニア歴5ヶ月の駆け出しエンジニア ・AWS Cloud Practitionerの資格は持っているが実務でのインフラ(AWS)経験は無し ・ミドルウェア周りの知識はほぼゼロ(Webサーバとアプリケーションサーバってどう違うの?レベル) 1. インフラ設計 まずやったこととして、Webサービスを稼働させる上でどのようなインフラ環境が必要か理解し、可視化することです。 今回、実装するのは、Web開発では基本となる開発環境(development)、ステージング環境(staging)、本番環境(production)からなる構成です。 なんとなくの理解だったので、各環境の役割について、改めて理解するのに良い記事があったので共有します。 事前学習 とはいっても、 VPCってなんぞや? サブネットの切り方ってどうするの? NATゲートウェイとは? ALBとロードバランサーなにが違うの? など、私にとってネットワーク設計やサーバ構築が初めての経験だったので、知識の習得のため最初の数日はとにかくインプット量を意識して手を動かしながら学習しました。 VPC構築、サブネットの設定、EC2構築など実際にAWSマネジメントコンソール上でポチポチやりながら、「こことここが繋がるのか〜」「こうすれば良いのね」といった感じで、体系的にAWSのリソースを理解しながら、知識を蓄えていったところが大きいです。 一部、以下AWSCloudTechのサービスを使ったりなんかもしました。 実装するインフラ構成を図に落とし込む 理解が少し曖昧なところがありながらもなんとか、今回実装するインフラ構成を図に落とし込みました。 ここまででおおよそ3日です。 Webサーバはアクセスを考慮して、現時点では冗長構成にせず単一のインスタンスのみで運用を行い、batchサーバの役割も持たせます。 本番環境では、バウンスメール等はSES,SNSを使用し、通知を行いレートの管理をします。 他ネットワークからのアクセスも可能にするため、AWSClientVPNを使用したVPN接続も実装する予定です。 Excelにインフラ設計情報の詳細をドキュメント化 インフラ設計情報として、開発する上で必要になってくる細かな設定に関しては、都度Excelに記載し、後ほど忘れないためにドキュメント化し管理しました。 ・RDSの詳細設定 ・各インスタンスの詳細設定 ・pemキー情報、IAM情報、各種ログイン情報  ・ssh接続コマンドチートシート などなど 2. ネットワーク構築  ここから実際に手を動かしていきます。上記インフラ構成を実現するためにまずは、サーバを設置する箱となるネットワークの構築(VPC)から始めました。 ざっくり手順は以下のとおり実現しました。 1.VPC設定 2.VPC内にサブネット構築 3.インターネットゲートウェイの設置 4.NATゲートウェイの設置 5.VPC間のピアリング接続の設定 6.サブネットのルートテーブルの設定 具体的な設定についてここでは詳細省きますが、これでおおよそ必要なるネットワーク構成は出来あがります。 1つ注意点として、 VPCやサブネットを作成する際のIPv4CIDRブロックは、以下のプライベートIPアドレスの範囲内で作成する必要があります。 プライベートアドレスは以下のように範囲が定められており、この範囲外のIPアドレスはグローバルアドレスとなってしまうからです。 クラス 範囲 ネットワーク数 クラスA 10.0.0.0 ~ 10.255.255.255 (10.0.0.0/8) 1 クラスB 172.16.0.0 ~ 172.31.255.255 (172.16.0.0/12) 16 クラスC 192.168.0.0 ~ 192.168.255.255 (192.168.0.0/16) 256 パブリックサブネットとプラベートサブネット 自分も勉強していく中で、パブリックサブネットとプライベートサブネットってどう違うのと疑問に思っていました。 サブネット作成のコンソール画面でもパブリック/プライベートの選択などなかったはずです。 【結論】 サブネットのルートテーブルの記述内容で変わる パブリックサブネット すべてのIPアドレス宛のターゲットがインターネットゲートウェイに向いているもの。 送信先 ターゲット 0.0.0.0/0 インターネットゲートウェイ  プライベートサブネット すべてのIPアドレス宛のターゲットがNATゲートウェイに向いているもの。 プライベートサブネットがインターネットと通信するためには、NATゲートウェイのルートテーブルに0.0.0.0/0がインターネットゲートウェイに向かうように設定する必要があります。 送信先 ターゲット 0.0.0.0/0 NATゲートウェイ  3. サーバ・DB構築  サブネット内に必要となるEC2インスタンス、またはRDSを作成していきます。 (EC2,RDSの詳細な作成設定については記述を省略します) パブリックサブネットに配置するインスタンスには、インターネットに接続するため、ElasticIPを関連づける必要があります。 パブリックサブネットに配置したインスタンスは通常、パブリックIPv4アドレスが割り当てられます。 しかし、これだとインスタンスの起動停止のたびに毎回IPアドレスが変わってしまいます。 それでは大変なので、EIPを取得し、インスタンスと関連づけることでEIPを固定のパブリックIPアドレスとして使用することができます。 EC2インスタンス作成とNginxインストール 必要となるEC2インスタンスを作成します。 アプリケーションを動かすインスタンスには、RailsアプリケーションサーバであるPumaと通信するためのWebサーバ(Nginx)を事前にインストールします。 アプリケーションデプロイ後には、NginxとPumaを通信させる必要があります。 EIPの上限はデフォルトだと5個な話 インスタンスにEIPを割り当てるときに、画像のようなエラーがでてきました。 これはEIPの数が制限に達したという警告です。 EIPは、サポートプランにも寄りますが、Developerプランではデフォルトでは5個までしか使用できません。(デフォルトVPC内に2つ使用されているので、実質3個) 5個以上使用する場合には、Service Quatasのダッシュボードから申請を行う必要があります。 https://ap-northeast-1.console.aws.amazon.com/servicequotas なお、一気に20個とか申請すると、「申請する理由を詳しく教えてください」などとAWS側から怒られてしまうので、まずは5個ぐらいから始めると良いと思います。(※申請は全て英語です) 私は、デフォルトVPCに関連づいているEIP2個を外したのと、追加申請5個で足りました。 RDSのフェイルオーバー設定 RDSを作成していきます。 RDSの詳細設定に関しては、各自RDS使用用途によって異なるかと思うので、詳細は省きます。 障害時にはRDSを他AZで起動させるフェイルオーバーをさせる必要があります。 RDSのダッシュボードからサブネットグループの作成を行い、フェイルオーバーす先となるAZをグルーピングします。 フェイルオーバーの確認については、以下記事を参考にテストしてみました。 EC2-RDS間の疎通確認 アプリケーションが動く、EC2インスタンスからRDSへ接続ができることを確認します。 RDSのエンジンとしてMySQLを選択していた場合、EC2インスタンス上で以下コマンドでRDS内のMySQLと接続ができます。 RDSに設定しているセキュリグループのインバウンドルールに接続元EC2からのMySQL通信(3306番ポート)の許可を忘れずに! 接続元ec2 $ mysql -u マスターユーザー名 -pパスワード -h エンドポイント マスターユーザー名,パスワードは、それぞれRDS作成時に決定したものです。エンドポイントはRDS作成後に確認できます。 ALBの使用 一台のEC2ならロードバランサーは使用しなくても良いのでは思ったのですが、単なる負荷分散以外の機能もAWSのロードバランサーは提供してくれるので、そちらのメリットを加味してALBを使用します。 またALBには、Amazon Certificate Manager(ACM)からSSL証明書を取得し、HTTPSでの通信を設定します 4. Lambdaによる自動化 Lambda,EventBridge, CloudWatch, AWSChatBot, SNS このあたりのサービスを使用して開発する上で管理しやすくなる自動化を行いました。 Lambda✖︎EventBridgeによるEC2インスタンス起動・停止の自動化 開発ツール系のインスタンスや使用頻度の高いインスタンスについは起動・停止を自動化すると便利です。 ↓記事を参考に、実装しました。 環境ごとのEC2・RDSの停止忘れ防止 staging環境、production環境(運用開始まで)に属するインスタンス、RDSについては毎日↑のLambdaの停止スクリプトのみを実行し、停止忘れ防止策をこうじました。 AWS ChatbotによるSlack通知 Lambdaの実行結果は、CloudWatchLogsに蓄積されます。 インスタンスの停止スクリプトなどはエラー通知を即座に把握したいため、実務のコミュニケーションツールとして使用しているSlackに通知するように設定しました。 すごく便利!! 5. Amazon SES,SNS  本番環境や開発環境において、AWSからメールを送信するにはAmazon SimpleEmailService(SES)を使用します。 ここでもざっくりと手順を説明すると以下になります。 1.メール送信権限付きIAMユーザー作成後、アクセスキーを取得 2.Railsアプリコード内の ~アプリ名/config/environments/development.rb, staging.rb, production.rb配下にアクセスキーを記載 3.SESでドメイン、メールアドレスの認証 4.認証したドメイン・アドレスからのメール送信の確認 5.SNSでメール通知設定 メール送信権限付きユーザーのアクセスキーを取得 メール送信権限を持つIAMユーザーを作成します。(既存のユーザーでも大丈夫です) アタッチするポリシーは、AmazonSesSendingAccessというデフォルトポリシーがあるのでそれをユーザーにアタッチすれば大丈夫です。 AmazonSesSendingAccess { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": "ses:SendRawEmail", "Resource": "*" } ] } テストメール送信 ドメイン・メールアドレスの認証を行います。 認証からテストメールの送信の仕方までは↓記事が参考になります。 ※ドメインに関しては、Route53のほうで事前に認証済みのドメインでないとSES上で認証されないので注意が必要です。(経験あり?) バウンスメールのテストについては、上記テストメールの送信先をbounce@simulator.amazonses.comに設定してあげると、バウンスレートを上げることなくバウンスメールのテストを行なってくれます。 その他、通常の成功メールや苦情メールも同様で↓に記載のテスト用アドレスを使用するとレートとは無関係にテストができます。 バウンスメール・苦情メール等については、SNSとSESを連携させて通知設定を行います。 これも↓記事が参考になるので、簡単に設定できます。 ここまでだいたい2週間ぐらいでした。 6. 開発環境構築(docker)  ローカルの開発環境と検証用のdevelopment環境はdockerで構築を行いました。 Dockerfile, docker-compose.ymlを作成し、シェルスクリプトとして開発環境構築用のスクリプトを用意しました。 このスクリプトを叩くだけで、dockerでの開発環境ができあがります。 合わせて、初期データとして必要なrakeタスクも実装しました。 ざっと内容を紹介 setup.sh #!/bin/bash # 作業用ディレクトリ作成 if [ ! -d ./workspace ]; then mkdir workspace fi # 作業用dir配下にプロジェクトをclone git clone git@~~ # キャッシュを使用せず、imageをbuild docker-compose build --no-cache # 必要な初期rakeタスクを流す docker-compose run web bundle exec rake rakeタスク # 停止済みのコンテナを削除 docker container prune -f ridgepole導入時にハマったこと 今回、アプリケーションはmigrationファイルでの管理ではなくridgepoleを使用します。 私自身初めてのridgepole導入だったので少し苦戦しました。 後ほどridgepole導入時にハマったことは詳細をQiitaに投稿しようと思っています。 ridgepoleとは↓・・・ 7. jenkins・phpmyadminなど開発ツール設定  開発ツール用のインスタンスにjenkins, phpmyadminをそれぞれインストールします。 それぞれのインスタンスには、EC2FullAccessなどのポリシーを持ったアクセスキーを配置する必要があります。 jenkinsインスタンス # 認証情報を設定 $ aws configure # 4つ聞かれるのでそれぞれ入力 1. アクセスキー 2. パスワード 3. region 4. output形式 # この配下に認証情報(アクセスキー等がある) $ cd ~/.aws $ ls -la => config, credentials jenkinsのジョブが失敗する アクセスキーの設置が終わり、jenkinsのジョブを作成し実行たところ、エラーになりました。。。 jenkisnのコンソール出力を見ると以下のようなエラーメッセージが unable to locate credentials. you can configure credentials by running "aws configure". おいおい、アクセスキーはちゃんと配置したはずだぞ? 設定を確認してもきちんと登録されているはず・・・ # アクセスキー設定情報を確認 aws configure list => aws_access_key_id = ***************** => aws_secret_access_key = ***************** 【結論】 jenkinsのジョブを実行しているのは、ec2の中のjenkinsユーザー だからjenkinsユーザーに認証情報を設定してあげる必要がある(これまでは、ec2ユーザーとrootユーザーに設定していた) # rootユーザーになる $ sudo su # jenkinsユーザーになる $ su - jenkins # 認証情報が確認すると・・・なにも設定されていなかった $ aws configure list => aws_access_key_id => aws_secret_access_key # 再度認証情報を設定 $ aws configure 無事、ジョブが成功した! 余談ですが、画面上で作成したjenkinsのジョブはサーバ内jenkinsユーザーの以下に格納されているので、確認できます。 jenkinsインスタンス # rootユーザーになる sudo su # jenkinstユーザーになる su - jenkins cd workspace ls -la => 作成したjenkinsジョブ一覧が表示 8. VPN接続  別のネットワークから、この環境へのアクセスを可能にするためAWSClientVPNを使用し、VPN接続を試みます。 パブリックサブネット内のNATゲートウェイにアタッチしたEIPを固定IPアドレスとして、インターネットに接続できることをゴールとします。 ↓記事を参考にするとできるかと思います。 が、私がハマったことで一つ注意点! ClientVPVEndpointと関連づけるサブネットはプライベートサブネットでないといけない これに気づかず、数時間ハマりました。。。 また、VPN接続するときに作成されるENIは、接続のたびに新しいものが作成されます。 ENIに割り当てられるパブリックIPアドレスは接続のたびに毎回変わりますが、それをNATゲートウェイのEIPで固定化するというイメージです。 9. 起きた変化 以上作業を約3週間で行いました。 インフラにほとんど触ったことの無かった素人が3週間のインフラ構築を通して、どのような変化があったのか、技術的な側面と価値観・考え方の側面から感じたことを書いていきたいと思います。 技術面 【AWS】 ・AWSを使用して、迷わず基本的なアーキテクチャの設計ができるようになった ・AWS上のサービスをドキュメントを読むだけで使いこなせるようになった ・AWSリソースの管理能力が向上した 【docker】 ・dockerを使用して、開発環境の構築ができるようになった ・Dockerfile, docker-compose.ymlなど記述内容を理解し、自分の実装したいように改修できるようになった 【その他】 ・Webサーバやアプリケーションサーバのどのレイヤーに対してエラーが発生しているのか感覚的にわかるようになった ・ログを見る習慣/ログからエラーの原因を特定する力がついた ・Linuxサーバ内のディレクトリ構造や必要ファイルなどが把握し、行いたい修正を加えられるようになった ・Webの3層構造を体系的に理解することができた ざっとこんな感じになります。 特に自分として変化を感じたことは、基本的なアーキテクチャ設計をする際のAWSリソースに対して「わからない・これどうやるんだ」という感情がなくなったことです。 今までは、事前知識としてなかったのはもちろんですがどこかAWSを気軽に触れないものだと思っていました。 ですが、毎日AWSを触りながら理解していくことで、AWSに対するハードルが低くなっていくのを強く感じました。 今では、初めて使用するAWS上のサービスでも「まずは触ってみる」ということを大切にし、ドキュメントや参考記事を読めばだいたいのことはなんとかなるようになったと思います。 わずか3週間ですが、自分のエンジニアとしての知識・技術が3週間前と比較し格段に上がったのを感じました! 価値観・考え方 インフラ構築を経験してみることで、インフラの楽しさを感じたのと同時に、改めて、AWSの素晴らしさに感動しました。 マネジメントコンソールをいじるだけでサーバ・ネットワークを作れたり、あらゆるサービスを連携することでできることの無限さを感じました。 インフラというのはどこか、モヤに隠れた分かりづらいものという意識があった中、自分で0から設計し図を書き、それを実際に構築するという経験のおかげで構造的にインフラを捉えられるようになりました。 AWSを理解するにはまず図を書いてみる とよく聞きますが、これは本当にそうだと思います。 図を書きながら、「これってどうやって通信する」「この部分にはどういう制御が必要なんじゃないか」と頭の中で考え、それを実際に手を動かしてみることで必要な処理や構成が感覚的に理解できるようになってきます。 この経験をきっかけとして、これからもインフラに関する知識・技術を勉強し、今後はSAA,さらにはその上のSAPの取得を目指していきたいと思います。 そして、実務としてこのような素晴らしい挑戦の機会をいただけたことに感謝し、これからも成長できるように頑張っていきたいと思います。 10. おまけ 約3週間インフラ構築をする上で、ミドルウェアの操作についてはコマンドラインが主となるので、自然とコマンドを使う機会が多くなりました。 そこで備忘録がてら、よく使用したコマンドを残していきたいと思います。 よく使ったコマンドたち ■ コマンド # ファイル削除 rm -rf ディレクトリ # 検索 grep -r 正規表現 # プロセス確認 ps aux | grep XXX # 環境変数確認 env ■ systemctl # start, stop, restart, statusなど # Nginxの起動状態確認 systemctl nginx status # MySQLの起動状態確認 systemctl mysql status ■ crontab # サーバの初期設定をするcrontabの内容確認 crontab -l ■ Git # 接続先のremoteリポジトリを確認 git remote -v # remoteリポジトリを設定 git remote set-url origin git@~~~ ■ ssh ssh -i ~/.ssh/キー.pem ec2-user@IPアドレス
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

インフラ素人が3週間でWebサービスのインフラを0から構築するためにやったこと

目次 1. インフラ設計 2. ネットワーク構築 3. サーバ・DB構築 4. Lambdaによる自動化 5. Amazon SES・SNS 6. 開発環境構築(docker) 7. jenkins・phpmyadminなど開発ツール設定 8. VPN接続 9. 起きた変化 10. おまけ はじめに インフラ素人同然レベルだった私が実務において、Webアプリケーションのインフラを0から構築することになりました。 期間は約3週間、インフラ設計から行い、構築したインフラ上でWebサービスが稼働できる状態まで持っていくことがゴールになります。  約3週間の間、AWSやミドルウェア周りの技術に触れ、今まで考えてもみなかった知識の習得や、多くのつまづきを通して貴重な経験をすることができました。 チームメンバーと分担しながら進めたので、あくまで自分のやったことベースにはなりますが、3週間どんなことをやったのか、特につまづいたことを中心に書いていきたいと思います。 ※基本的なインフラ構成はほぼ全てAWSのリソースを使用しました。 【使用技術】 ・ AWS(EC2, RDS, VPC, Route53, Lambda, IAM, SES, SNS, ACM, CloudWatch, etc.) ・ docker ・ Nginx(Webサーバ) ・ Puma(アプリケーションサーバ) ・ Ruby on Rails 開始前の筆者のレベルを3行で! ・自社開発エンジニア歴5ヶ月の駆け出しエンジニア ・AWS Cloud Practitionerの資格は持っているが実務でのインフラ(AWS)経験は無し ・ミドルウェア周りの知識はほぼゼロ(Webサーバとアプリケーションサーバってどう違うの?レベル) 1. インフラ設計 まずやったこととして、Webサービスを稼働させる上でどのようなインフラ環境が必要か理解し、可視化することです。 今回、実装するのは、Web開発では基本となる開発環境(development)、ステージング環境(staging)、本番環境(production)からなる構成です。 なんとなくの理解だったので、各環境の役割について、改めて理解するのに良い記事があったので共有します。 事前学習 とはいっても、 VPCってなんぞや? サブネットの切り方ってどうするの? NATゲートウェイとは? ALBとロードバランサーなにが違うの? など、私にとってネットワーク設計やサーバ構築が初めての経験だったので、知識の習得のため最初の数日はとにかくインプット量を意識して手を動かしながら学習しました。 VPC構築、サブネットの設定、EC2構築など実際にAWSマネジメントコンソール上でポチポチやりながら、「こことここが繋がるのか〜」「こうすれば良いのね」といった感じで、体系的にAWSのリソースを理解しながら、知識を蓄えていったところが大きいです。 一部、以下AWSCloudTechのサービスを使ったりなんかもしました。 実装するインフラ構成を図に落とし込む 理解が少し曖昧なところがありながらもなんとか、今回実装するインフラ構成を図に落とし込みました。 ここまででおおよそ3日です。 Webサーバはアクセスを考慮して、現時点では冗長構成にせず単一のインスタンスのみで運用を行い、batchサーバの役割も持たせます。 本番環境では、バウンスメール等はSES,SNSを使用し、通知を行いレートの管理をします。 他ネットワークからのアクセスも可能にするため、AWSClientVPNを使用したVPN接続も実装する予定です。 Excelにインフラ設計情報の詳細をドキュメント化 インフラ設計情報として、開発する上で必要になってくる細かな設定に関しては、都度Excelに記載し、後ほど忘れないためにドキュメント化し管理しました。 ・RDSの詳細設定 ・各インスタンスの詳細設定 ・pemキー情報、IAM情報、各種ログイン情報  ・ssh接続コマンドチートシート などなど 2. ネットワーク構築  ここから実際に手を動かしていきます。上記インフラ構成を実現するためにまずは、サーバを設置する箱となるネットワークの構築(VPC)から始めました。 ざっくり手順は以下のとおり実現しました。 1.VPC設定 2.VPC内にサブネット構築 3.インターネットゲートウェイの設置 4.NATゲートウェイの設置 5.VPC間のピアリング接続の設定 6.サブネットのルートテーブルの設定 具体的な設定についてここでは詳細省きますが、これでおおよそ必要なるネットワーク構成は出来あがります。 1つ注意点として、 VPCやサブネットを作成する際のIPv4CIDRブロックは、以下のプライベートIPアドレスの範囲内で作成する必要があります。 プライベートアドレスは以下のように範囲が定められており、この範囲外のIPアドレスはグローバルアドレスとなってしまうからです。 クラス 範囲 ネットワーク数 クラスA 10.0.0.0 ~ 10.255.255.255 (10.0.0.0/8) 1 クラスB 172.16.0.0 ~ 172.31.255.255 (172.16.0.0/12) 16 クラスC 192.168.0.0 ~ 192.168.255.255 (192.168.0.0/16) 256 パブリックサブネットとプラベートサブネット 自分も勉強していく中で、パブリックサブネットとプライベートサブネットってどう違うのと疑問に思っていました。 サブネット作成のコンソール画面でもパブリック/プライベートの選択などなかったはずです。 【結論】 サブネットのルートテーブルの記述内容で変わる パブリックサブネット すべてのIPアドレス宛のターゲットがインターネットゲートウェイに向いているもの。 送信先 ターゲット 0.0.0.0/0 インターネットゲートウェイ  プライベートサブネット すべてのIPアドレス宛のターゲットがNATゲートウェイに向いているもの。 プライベートサブネットがインターネットと通信するためには、NATゲートウェイのルートテーブルに0.0.0.0/0がインターネットゲートウェイに向かうように設定する必要があります。 送信先 ターゲット 0.0.0.0/0 NATゲートウェイ  3. サーバ・DB構築  サブネット内に必要となるEC2インスタンス、またはRDSを作成していきます。 (EC2,RDSの詳細な作成設定については記述を省略します) パブリックサブネットに配置するインスタンスには、インターネットに接続するため、ElasticIPを関連づける必要があります。 パブリックサブネットに配置したインスタンスは通常、パブリックIPv4アドレスが割り当てられます。 しかし、これだとインスタンスの起動停止のたびに毎回IPアドレスが変わってしまいます。 それでは大変なので、EIPを取得し、インスタンスと関連づけることでEIPを固定のパブリックIPアドレスとして使用することができます。 EC2インスタンス作成とNginxインストール 必要となるEC2インスタンスを作成します。 アプリケーションを動かすインスタンスには、RailsアプリケーションサーバであるPumaと通信するためのWebサーバ(Nginx)を事前にインストールします。 アプリケーションデプロイ後には、NginxとPumaを通信させる必要があります。 EIPの上限はデフォルトだと5個な話 インスタンスにEIPを割り当てるときに、画像のようなエラーがでてきました。 これはEIPの数が制限に達したという警告です。 EIPは、サポートプランにも寄りますが、Developerプランではデフォルトでは5個までしか使用できません。(デフォルトVPC内に2つ使用されているので、実質3個) 5個以上使用する場合には、Service Quatasのダッシュボードから申請を行う必要があります。 https://ap-northeast-1.console.aws.amazon.com/servicequotas なお、一気に20個とか申請すると、「申請する理由を詳しく教えてください」などとAWS側から怒られてしまうので、まずは5個ぐらいから始めると良いと思います。(※申請は全て英語です) 私は、デフォルトVPCに関連づいているEIP2個を外したのと、追加申請5個で足りました。 RDSのフェイルオーバー設定 RDSを作成していきます。 RDSの詳細設定に関しては、各自RDS使用用途によって異なるかと思うので、詳細は省きます。 障害時にはRDSを他AZで起動させるフェイルオーバーをさせる必要があります。 RDSのダッシュボードからサブネットグループの作成を行い、フェイルオーバーす先となるAZをグルーピングします。 フェイルオーバーの確認については、以下記事を参考にテストしてみました。 EC2-RDS間の疎通確認 アプリケーションが動く、EC2インスタンスからRDSへ接続ができることを確認します。 RDSのエンジンとしてMySQLを選択していた場合、EC2インスタンス上で以下コマンドでRDS内のMySQLと接続ができます。 RDSに設定しているセキュリグループのインバウンドルールに接続元EC2からのMySQL通信(3306番ポート)の許可を忘れずに! 接続元ec2 $ mysql -u マスターユーザー名 -pパスワード -h エンドポイント マスターユーザー名,パスワードは、それぞれRDS作成時に決定したものです。エンドポイントはRDS作成後に確認できます。 ALBの使用 一台のEC2ならロードバランサーは使用しなくても良いのでは思ったのですが、単なる負荷分散以外の機能もAWSのロードバランサーは提供してくれるので、そちらのメリットを加味してALBを使用します。 またALBには、Amazon Certificate Manager(ACM)からSSL証明書を取得し、HTTPSでの通信を設定します 4. Lambdaによる自動化 Lambda,EventBridge, CloudWatch, AWSChatBot, SNS このあたりのサービスを使用して開発する上で管理しやすくなる自動化を行いました。 Lambda✖︎EventBridgeによるEC2インスタンス起動・停止の自動化 開発ツール系のインスタンスや使用頻度の高いインスタンスについは起動・停止を自動化すると便利です。 ↓記事を参考に、実装しました。 環境ごとのEC2・RDSの停止忘れ防止 staging環境、production環境(運用開始まで)に属するインスタンス、RDSについては毎日↑のLambdaの停止スクリプトのみを実行し、停止忘れ防止策をこうじました。 AWS ChatbotによるSlack通知 Lambdaの実行結果は、CloudWatchLogsに蓄積されます。 インスタンスの停止スクリプトなどはエラー通知を即座に把握したいため、実務のコミュニケーションツールとして使用しているSlackに通知するように設定しました。 すごく便利!! 5. Amazon SES,SNS  本番環境や開発環境において、AWSからメールを送信するにはAmazon SimpleEmailService(SES)を使用します。 ここでもざっくりと手順を説明すると以下になります。 1.メール送信権限付きIAMユーザー作成後、アクセスキーを取得 2.Railsアプリコード内の ~アプリ名/config/environments/development.rb, staging.rb, production.rb配下にアクセスキーを記載 3.SESでドメイン、メールアドレスの認証 4.認証したドメイン・アドレスからのメール送信の確認 5.SNSでメール通知設定 メール送信権限付きユーザーのアクセスキーを取得 メール送信権限を持つIAMユーザーを作成します。(既存のユーザーでも大丈夫です) アタッチするポリシーは、AmazonSesSendingAccessというデフォルトポリシーがあるのでそれをユーザーにアタッチすれば大丈夫です。 AmazonSesSendingAccess { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": "ses:SendRawEmail", "Resource": "*" } ] } テストメール送信 ドメイン・メールアドレスの認証を行います。 認証からテストメールの送信の仕方までは↓記事が参考になります。 ※ドメインに関しては、Route53のほうで事前に認証済みのドメインでないとSES上で認証されないので注意が必要です。(経験あり?) バウンスメールのテストについては、上記テストメールの送信先をbounce@simulator.amazonses.comに設定してあげると、バウンスレートを上げることなくバウンスメールのテストを行なってくれます。 その他、通常の成功メールや苦情メールも同様で↓に記載のテスト用アドレスを使用するとレートとは無関係にテストができます。 バウンスメール・苦情メール等については、SNSとSESを連携させて通知設定を行います。 これも↓記事が参考になるので、簡単に設定できます。 ここまでだいたい2週間ぐらいでした。 6. 開発環境構築(docker)  ローカルの開発環境と検証用のdevelopment環境はdockerで構築を行いました。 Dockerfile, docker-compose.ymlを作成し、シェルスクリプトとして開発環境構築用のスクリプトを用意しました。 このスクリプトを叩くだけで、dockerでの開発環境ができあがります。 合わせて、初期データとして必要なrakeタスクも実装しました。 ざっと内容を紹介 setup.sh #!/bin/bash # 作業用ディレクトリ作成 if [ ! -d ./workspace ]; then mkdir workspace fi # 作業用dir配下にプロジェクトをclone git clone git@~~ # キャッシュを使用せず、imageをbuild docker-compose build --no-cache # 必要な初期rakeタスクを流す docker-compose run web bundle exec rake rakeタスク # 停止済みのコンテナを削除 docker container prune -f ridgepole導入時にハマったこと 今回、アプリケーションはmigrationファイルでの管理ではなくridgepoleを使用します。 私自身初めてのridgepole導入だったので少し苦戦しました。 後ほどridgepole導入時にハマったことは詳細をQiitaに投稿しようと思っています。 ridgepoleとは↓・・・ 7. jenkins・phpmyadminなど開発ツール設定  開発ツール用のインスタンスにjenkins, phpmyadminをそれぞれインストールします。 それぞれのインスタンスには、EC2FullAccessなどのポリシーを持ったアクセスキーを配置する必要があります。 jenkinsインスタンス # 認証情報を設定 $ aws configure # 4つ聞かれるのでそれぞれ入力 1. アクセスキー 2. パスワード 3. region 4. output形式 # この配下に認証情報(アクセスキー等がある) $ cd ~/.aws $ ls -la => config, credentials jenkinsのジョブが失敗する アクセスキーの設置が終わり、jenkinsのジョブを作成し実行たところ、エラーになりました。。。 jenkisnのコンソール出力を見ると以下のようなエラーメッセージが unable to locate credentials. you can configure credentials by running "aws configure". おいおい、アクセスキーはちゃんと配置したはずだぞ? 設定を確認してもきちんと登録されているはず・・・ # アクセスキー設定情報を確認 aws configure list => aws_access_key_id = ***************** => aws_secret_access_key = ***************** 【結論】 jenkinsのジョブを実行しているのは、ec2の中のjenkinsユーザー だからjenkinsユーザーに認証情報を設定してあげる必要がある(これまでは、ec2ユーザーとrootユーザーに設定していた) # rootユーザーになる $ sudo su # jenkinsユーザーになる $ su - jenkins # 認証情報が確認すると・・・なにも設定されていなかった $ aws configure list => aws_access_key_id => aws_secret_access_key # 再度認証情報を設定 $ aws configure 無事、ジョブが成功した! 余談ですが、画面上で作成したjenkinsのジョブはサーバ内jenkinsユーザーの以下に格納されているので、確認できます。 jenkinsインスタンス # rootユーザーになる sudo su # jenkinstユーザーになる su - jenkins cd workspace ls -la => 作成したjenkinsジョブ一覧が表示 8. VPN接続  別のネットワークから、この環境へのアクセスを可能にするためAWSClientVPNを使用し、VPN接続を試みます。 パブリックサブネット内のNATゲートウェイにアタッチしたEIPを固定IPアドレスとして、インターネットに接続できることをゴールとします。 ↓記事を参考にするとできるかと思います。 が、私がハマったことで一つ注意点! ClientVPVEndpointと関連づけるサブネットはプライベートサブネットでないといけない これに気づかず、数時間ハマりました。。。 また、VPN接続するときに作成されるENIは、接続のたびに新しいものが作成されます。 ENIに割り当てられるパブリックIPアドレスは接続のたびに毎回変わりますが、それをNATゲートウェイのEIPで固定化するというイメージです。 9. 起きた変化 以上作業を約3週間で行いました。 インフラにほとんど触ったことの無かった素人が3週間のインフラ構築を通して、どのような変化があったのか、技術的な側面と価値観・考え方の側面から感じたことを書いていきたいと思います。 技術面 【AWS】 ・AWSを使用して、迷わず基本的なアーキテクチャの設計ができるようになった ・AWS上のサービスをドキュメントを読むだけで使いこなせるようになった ・AWSリソースの管理能力が向上した 【docker】 ・dockerを使用して、開発環境の構築ができるようになった ・Dockerfile, docker-compose.ymlなど記述内容を理解し、自分の実装したいように改修できるようになった 【その他】 ・Webサーバやアプリケーションサーバのどのレイヤーに対してエラーが発生しているのか感覚的にわかるようになった ・ログを見る習慣/ログからエラーの原因を特定する力がついた ・Linuxサーバ内のディレクトリ構造や必要ファイルなどが把握でき、行いたい修正を加えられるようになった ・Webの3層構造を体系的に理解することができた ざっとこんな感じになります。 特に自分として変化を感じたことは、基本的なアーキテクチャ設計をする際のAWSリソースに対して「わからない・これどうやるんだ」という感情がなくなったことです。 今までは、事前知識としてなかったのはもちろんですがどこかAWSを気軽に触れないものだと思っていました。 ですが、毎日AWSを触りながら理解していくことで、AWSに対するハードルが低くなっていくのを強く感じました。 今では、初めて使用するAWS上のサービスでも「まずは触ってみる」ということを大切にし、ドキュメントや参考記事を読めばだいたいのことはなんとかなるようになったと思います。 わずか3週間ですが、自分のエンジニアとしての知識・技術が3週間前と比較し格段に上がったのを感じました! 価値観・考え方 インフラ構築を経験してみることで、インフラの楽しさを感じたのと同時に、改めて、AWSの素晴らしさに感動しました。 マネジメントコンソールをいじるだけでサーバ・ネットワークを作れたり、あらゆるサービスを連携することでできることの無限さを感じました。 インフラというのはどこか、モヤに隠れた分かりづらいものという意識があった中、自分で0から設計し図を書き、それを実際に構築するという経験のおかげで構造的にインフラを捉えられるようになりました。 AWSを理解するにはまず図を書いてみる とよく聞きますが、これは本当にそうだと思います。 図を書きながら、「これってどうやって通信してるの?」「この部分にはどういう制御が必要なんじゃないか」と頭の中で考え、それを実際に手を動かしてみることで必要な処理や構成が感覚的に理解できるようになってきます。 この経験をきっかけとして、これからもインフラに関する知識・技術を勉強し、今後はSAA,さらにはその上のSAPの取得を目指していきたいと思います。 そして、実務としてこのような素晴らしい挑戦の機会をいただけたことに感謝し、これからも成長できるように頑張っていきたいと思います。 10. おまけ 約3週間インフラ構築をする上で、ミドルウェアの操作についてはコマンドラインが主となるので、自然とコマンドを使う機会が多くなりました。 そこで備忘録がてら、よく使用したコマンドを残していきたいと思います。 よく使ったコマンドたち ■ コマンド # ファイル削除 rm -rf ディレクトリ # 検索 grep -r 正規表現 # プロセス確認 ps aux | grep XXX # 環境変数確認 env ■ systemctl # start, stop, restart, statusなど # Nginxの起動状態確認 systemctl nginx status # MySQLの起動状態確認 systemctl mysql status ■ crontab # サーバの初期設定をするcrontabの内容確認 crontab -l ■ Git # 接続先のremoteリポジトリを確認 git remote -v # remoteリポジトリを設定 git remote set-url origin git@~~~ ■ ssh ssh -i ~/.ssh/キー.pem ec2-user@IPアドレス
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【devise】暗号化前後のパスワードが一致しているか判定するメソッド

実現したいこと Railsでdevise gemを使っている環境にて、暗号化前のパスワードが暗号化後のパスワードと一致しているか確認したい。 例えば、以下のようなケースです。 「このパスワードで設定したはずだがログインできず、パスワードがちゃんと設定されてるか確認してほしい」という問い合わせに対して調査する場合 有効期限を持たせた複数のパスワードを、過去履歴を含めてDBに保持しており、古いパスワードが入力された場合に「それは古いパスワードです」とアラートを出したい場合 deviseでは、パスワードは暗号化されDBに保存されているため、DBのレコードを参照するだけだと、元のパスワードがどんなものだったかわかりません。 解決方法 「入力されたパスワードを自力で暗号化したものでDBを検索する」という方法もありますが、そこまでしなくても一発でわかるvalid_password?メソッドがdeviseで用意されています。 レシーバにはActiveRecordインスタンス(パスワードが保存されたレコード)、引数に暗号化前のパスワードを指定します。 基本例 # ユーザが入力した"hogehoge"というパスワードが、id=1234のユーザのパスワードと一致するか確認したい場合 User.find(1234).valid_password?("hogehoge") # => 戻り値はboolean # paramsで渡ってきたpassword(暗号化前)が、id=1234のユーザに設定されたパスワードと一致するか確認したい場合 User.find(1234).valid_password?(params[:password]) 応用例 ちょっと発展させた例です。 例えば、有効期限を持たせた複数のパスワードを、過去履歴を含めてUserPasswordモデルに保持しており、 古いパスワードが入力された場合に「それは古いパスワードです」とアラートを出したい場合 def old_password?(input_password) old_passwords = UserPassword.find(1234).where.not(expired_at: nil) old_passwords.any? {|old_pw| old_pw.valid_password?(input_password) } end redirect_to new_session_path, alert: "入力されたパスワードは有効期限が切れています" if old_password?(params[:password]) 参考サイト devise gemでは以下で定義されているようです。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Mailgunのダッシュボードが開かない時(Railsチュートリアル学習)

はじめに プログラミング初学者の@kat_logと申します。 Mailgunのダッシュボードが開かない(真っ白なページ)になる時の対処法の共有です。 背景 Railsチュートリアル学習の中で(11章)HerokuにMailgunというアドオンを入れるのですが、 heroku addons:open mailgunコマンド後にクロームで開こうとしてもうまくいきませんでした。 (真っ白です…) 結論 グーグルクロームではなく他のブラウザ(Edge)などで開くとうまくいきます! おわりに お読みいただきありがとうございました、しょぼい記事ですみません? どなたかの参考になれば嬉しいです。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

deviceを使わないrequest specの基本的なテスト(Userモデルver.)

まずは超基本テスト WebブラウザからWebサーバーへHTTPリクエストを送り、Webサーバーから正常なHTTPレスポンスが返ってくるとき、そのHTTPレスポンスのHTTPステータスコードは200を返します。 spec/requests/user_spec.rb require 'rails_helper' RSpec.describe "Sessions", type: :request do describe "GET users" do let(:test_user) { create(:user) } before do session_params = { user: { email: test_user.email, password: test_user.password } } post "/login", params: session_params #コメント① get posts_path #コメント② end it "つぶやき一覧ページのリクエストが成功していること" do expect(response).to have_http_status(200) end end end コメント① 自分はdeviceというgemを使用していないのでログインを手書きしました。(何やらdeviceを使えばsign_inというヘルパーメソッドを使ってこの部分を表現できるらしい) 自分の場合だと以下のコントローラーのように[:user]の中に[:email]を入れているのでそういう構造になるようにsession_paramsを設定しました。 この設定はこちら↓の記事を参考にさせていただきました。 Rspecでサインインメソッドを共通化して切り出す(devise使わないとき)[system spec][request spec] users_controller.rb def login @user = User.find_by( email: params[:user][:email], password: params[:user][:password] ) ...省略... end コメント② userはresourcesを使ってルーティングしているのでurlの指定が少し独特です。 _pathヘルパーを使ってコントローラ#アクションを指定するのに、以下の記事が大変参考になります。 Railsのルーティングまとめ テストちょっと増やしてみる spec/requests/user_spec.rb require 'rails_helper' RSpec.describe "Sessions", type: :request do describe "GET users" do let(:test_user) { create(:user) } let(:test_post) { create(:post, user: test_user) } ########### 追加 ########### before do session_params = { user: { email: test_user.email, password: test_user.password } } post "/login", params: session_params test_post ########### 追加 ########### get posts_path end it "つぶやき一覧ページのリクエストが成功していること" do expect(response).to have_http_status(200) end it "つぶやきの内容を取得していること" do ########### 追加 ########### expect(response.body).to include test_post.content end end end ログインした後にtest_postを作成してからpost一覧ページへ飛んでいます(get posts_path)。 これでつぶやきの内容がレスポンスでやってきたwebページに含まれているかテストしています。 post一覧ページへ飛ぶ(get posts_path)前にtest_postと一行書いてあるのがポイントです。 今回は遅延評価のletを使用しているので、test_postが参照された時にletの行が実行されます。したがって、ここでtest_postを加えないとtest_postが作成されないままpost一覧ページへ飛んでしまうのでエラーになってしまいます。 参考 その他参考にさせていただいた記事です。ありがとうございました。 Railsチュートリアル(3章〜8章) request specを用いた実装 rspecのrequest specでうまくいかない時の原因調査のちょっとしたハック
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む