- 投稿日:2020-11-22T23:45:53+09:00
letter_openerでエラーが出た時の話
表示されていたエラー
Launchy::CommandNotFoundError Exception: Unable to find a browser command. If this is unexpected, Please rerun with environment variable LAUNCHY_DEBUG=true or the '-d' commandline option and file a bug
経緯
vagrantがどうこうっていう記事ばかりで参考になるものが決め打ちでなかなか見当たらなかった為、次回同じ原因でハマった時用の備忘録。
環境
Rails 4.2
Ruby 2.3
EC2に内にソースコードを置いて、SSH接続での開発対応方法
letter_openerだと、リモート開発時(EC2にSSH接続している等)には、上記エラーを吐いてしまう。
リモート開発でメール送信機能の確認をしたいのであれば、letter_opener_webの追加が必要。
導入手順は以下。1 gemfileにletter_opener_webの追加
gemfileで、
gem 'letter_opener_web', group: :developmentを追加する。
2 config/environments/development.rbの設定追加
config.action_mailer.delivery_method = :letter_opener_webを追加する。
※※※既にletter_openerをインストールしているのであれば、
config.action_mailer.delivery_method = :letter_openerという行があるはずなので、
単純に末尾に_web
を足してやればOK。3 config/routes.rbに設定追加
最後に、以下3行をroutes内に追加してやればOK。
if Rails.env.development? mount LetterOpenerWeb::Engine, at: '/letter_opener' endletter_opener_web導入後
localhost:3000/letter_opener/
を別タブでブラウザ上に開いておけば、
メールの送信記録が確認できる。参考記事
https://qiita.com/k-shogo/items/d85905535a64e82a3b2b
http://rubyandrails.hatenablog.com/entry/letter_opener_web
https://www.geek.sc/archives/2227
https://qiita.com/7sgg_m/items/178e0d90fc55c5716474
- 投稿日:2020-11-22T23:45:53+09:00
ActionMailer実行時にletter_openrが原因で落ちてしまった件について
表示されていたエラー
Launchy::CommandNotFoundError Exception: Unable to find a browser command. If this is unexpected, Please rerun with environment variable LAUNCHY_DEBUG=true or the '-d' commandline option and file a bug
経緯と概要
vagrantがどうこうっていう記事ばかりで参考になるものが決め打ちでなかなか見当たらなかった為、次回同じ原因でハマった時用の備忘録。
EC2でリモート開発するなら、letter_openerではだめで、letter_opnener_webを使わないといけない。環境
Rails 4.2
Ruby 2.3
letter_opener 1.4.1
EC2に内にソースコードを置いて、SSH接続での開発対応方法
letter_openerだと、リモート開発時(EC2にSSH接続している等)には、上記エラーを吐いてしまう。
リモート開発でメール送信機能の確認をしたいのであれば、letter_opener_webの追加が必要。
導入手順は以下。1 gemfileにletter_opener_webの追加
gemfileで、
gem 'letter_opener_web', group: :developmentを追加する。
2 config/environments/development.rbの設定追加
config.action_mailer.delivery_method = :letter_opener_webを追加する。
※※※既にletter_openerをインストールしているのであれば、
config.action_mailer.delivery_method = :letter_openerという行があるはずなので、
単純に末尾に_web
を足してやればOK。3 config/routes.rbに設定追加
最後に、以下3行をroutes内に追加してやればOK。
if Rails.env.development? mount LetterOpenerWeb::Engine, at: '/letter_opener' endletter_opener_web導入後
localhost:3000/letter_opener/
を別タブでブラウザ上に開いておけば、
メールの送信記録が確認できる。参考記事
https://qiita.com/k-shogo/items/d85905535a64e82a3b2b
http://rubyandrails.hatenablog.com/entry/letter_opener_web
https://www.geek.sc/archives/2227
https://qiita.com/7sgg_m/items/178e0d90fc55c5716474
- 投稿日:2020-11-22T23:45:53+09:00
ActionMailer実行時にletter_openrが原因で落ちた
表示されていたエラー
Launchy::CommandNotFoundError Exception: Unable to find a browser command. If this is unexpected, Please rerun with environment variable LAUNCHY_DEBUG=true or the '-d' commandline option and file a bug
経緯と概要
vagrantがどうこうという記事ばかりで参考になるものが決め打ちでなかなか見当たらなかった為、次回同じ原因でハマった時用の備忘録。
結論、EC2でリモート開発するなら、letter_openerではだめで、letter_opnener_webを使わないといけない。HogeMailer.hoge(huga).deliverみたいな感じのパターンで落ちてて、上記エラー出てるなら疑うべき。
環境
Rails 4.2
Ruby 2.3
letter_opener 1.4.1
EC2に内にソースコードを置いて、SSH接続での開発対応方法
letter_openerだと、リモート開発時(EC2にSSH接続している等)には、上記エラーを吐いてしまう。
リモート開発でメール送信機能の確認をしたいのであれば、letter_opener_webの追加が必要。
導入手順は以下。1 gemfileにletter_opener_webの追加
gemfileで、
gem 'letter_opener_web', group: :developmentを追加する。
2 config/environments/development.rbの設定追加
config.action_mailer.delivery_method = :letter_opener_webを追加する。
※※※既にletter_openerをインストールしているのであれば、
config.action_mailer.delivery_method = :letter_openerという行があるはずなので、
単純に末尾に_web
を足してやればOK。3 config/routes.rbに設定追加
最後に、以下3行をroutes内に追加してやればOK。
if Rails.env.development? mount LetterOpenerWeb::Engine, at: '/letter_opener' endletter_opener_web導入後
localhost:3000/letter_opener/
を別タブでブラウザ上に開いておけば、
メールの送信記録が確認できる。参考記事
https://qiita.com/k-shogo/items/d85905535a64e82a3b2b
http://rubyandrails.hatenablog.com/entry/letter_opener_web
https://www.geek.sc/archives/2227
https://qiita.com/7sgg_m/items/178e0d90fc55c5716474
- 投稿日:2020-11-22T23:23:16+09:00
最低限のゲストログイン機能を作った
はじめに
ポートフォリオの作成にあたり、採用担当者さんに少しでも見ていただけるように、ゲストログイン機能を実装した。
流れ
- ルーティング記述
- ゲストの情報をモデルに記述
- コントローラーにアクションを記述
- ビューを記述
流れは機能を実装するときとほぼ同じ。
1. ルーティング記述
routes.rbdevise_scope :user do get 'users/guest_sign_in', to: 'users/sessions#new_guest' endURIはわかりやすく、正規のユーザーログインと同じような感じで。
アクションは、deviseのコントローラーに記述するので、sessions
コントローラーを指定。2. ゲストの情報をモデルに記述
user.rbdef self.guest #ゲストユーザー用のアカウント作成 find_or_create_by!(email: 'guest@example.com', nickname: 'ゲスト', class_room_id: 1, first_name: 'ゲスト', last_name: 'ゲスト', attendance_number: 1) do |user| user.password = SecureRandom.urlsafe_base64 #パスワードはランダム生成 end end
find_or_create_by!
の引数には、自分の作成したアプリで新規登録をする際に必要な項目分作る。
SecureRandom.urlsafe_base64
でランダムに文字列を生成。3. コントローラーにアクションを記述
sessions_controller.rbdef new_guest #ゲストログイン用アクション user = User.guest #ゲストユーザーをモデルから呼び出す sign_in user #ゲストユーザーでサインイン redirect_to root_path end
gest
は「2」で作成したゲストアカウントのこと。4. ビューを記述
<%= link_to 'ゲストログイン', users_guest_sign_in_path %>参考記事
簡単ログイン・ゲストログイン機能の実装方法(ポートフォリオ用)
最後に
ユーザー登録前に、2つの情報を登録して、その情報にユーザーを紐づけているのだが、どうすれば、ゲストログインで事前の2つの情報を自動で作成できるのだろうか?必須項目にしない以外の方法を考えたいのだが…
- 投稿日:2020-11-22T23:08:25+09:00
FactoryBotでポリモーフィックなアソシエーションを生成する
はじめに
FactoryBotを書いてて、ポリモーフィック関連を自動生成するにはどうしたらいいんじゃ!
と思って調べたので、忘備録です。やりたいこと
例えばツイッターのようなアプリを作ることを考えて、Postテーブルを作ることにします。Postテーブルには投稿主を表すpostable_idがあるとします。
投稿できるのは、一般のUserの他に別テーブルで管理されてるCompanyも投稿できるようにしたとしましょう。すなわちUserとCompanyはPostとポリモーフィックな関係で結ばれています。User ----| |---- Post Company--|この時、postを生成するのと同時にuserやcompanyをFactoryBotで自動的に生成する方法を説明します。
解決
では 早速コードをみてみましょう。
まずは、デフォルトで用意されてるかもしれませんが、userとcompanyを作成するファクトリを用意します。factories/users.rbFactoryBot.define do factory :user, class: 'User' do name { 'test' } end endfactories/companies.rbFactoryBot.define do factory :company, class: 'Company' do name { 'test' } end end上記は特になんの変哲のないファクトリーです。specに
create(:user)
みたく書けばuserを作成できるでしょう。
続いてPostのファクトリーは以下のようになります。factories/posts.rb# userのpostを生成(postと一緒にuserができる) FactoryBot.define do factory :user_post, class: 'Post' do postable_type { 'User' } #ポリモーフィック関連の名前を指定して、userを生成するfactorを呼ぶ association :postable, factory: :user end # companyのpostを生成(postと一緒にcomapnayができる) factory :company_post, class: 'Post' do postable_type { 'Company' } #ポリモーフィック関連の名前を指定して、userを生成するfactorを呼ぶ association :postable, factory: :company end end肝はassociationでfactoryを指定することです。これによってuserかcompanyを自動で作成してくれます。
もちろんspecではcreate(:user_post)
で問題ありません。
便利なので是非ご活用ください!
- 投稿日:2020-11-22T22:30:49+09:00
Rails初心者がRSpecに入門してみた 2
大分間が空いてしまいましたが、前回からの続きでテストの記述方に触れていきます。
RSpec記述の基本形
'rails_helper' RSpec.describe "テストする対象", type: :Specの種類 do describe "どのような機能" do before do (以下のテストを確認するために必要な用意) (事前準備) end context "どのような状況/条件で" do (具体的な条件) it "どのような結果を期待する" do (具体的な結果/処理) end end end end基本的には上記のような形になると思います。
describeはテストしたい機能、contextはif文のような条件分け、itはそれに対して期待する結果を記述します。before doは必要であればテストをする以前に必要な処理、例えばユーザーをcreateしてログインさせておくといった内容を書いておきます。これをすることで多くのitを扱う際に一つ一つにログイン処理を書く必要がなくなり、記述量を大幅に削減できる訳ですね。また、itに到達するまでにcontextはdescribeは幾つでもネストして使用することも可能です。複雑なテストを書く場合には有効でしょう。
まとめると以下の通りです。
具体的にテストを実行する→before, it テストを分類してまとめる→describe, contextそれでは一例としてmodel_specを書いてみます。
今回テストしたいのはUser modelの登録時のvalidationについてです。
validatesは以下の通りです。model/user.rbvalidates :name, presence: true, #名前は必須 length: {maximum: 30} #30文字以下 validates :email, presence: true, #アドレスも必須 length: {maximum: 255}, #255文字以下 format: {with: VALID_EMAIL_REGEX}, #アドレスのフォーマットであるか uniqueness: { case_sensitive: false } #重複がないか validates :password, presence: true, #パスワードは必須 length: {minimum: 6} #6文字以上まず何を記述していけばいいか考えていきます。
・有効なユーザー情報 ・そこから各項目をnilにした情報(presenceの検証) ・文字数が多すぎる/少なすぎる情報(lengthの検証) ・項目固有の情報(emailのフォーマットや重複の検証)spec/models/user_spec.rbrequire "rails_helper" RSpec.describe User, type: :model do let!(:user) { create(:user) } #全てのvalidationを通る情報をFactoryBotで作成 context "submit valid values" do #事前用意したuserが通るか確認 it "should be valid user" do expect(user).to be_valid end end describe "User validation" do #ここからvalidation describe "Name" do context "name is valid" do #nameが有効な場合 it "be valid" do user.name = "foobar" expect(user).to be_valid end end context "name is nil" do #nameがない場合 it "be invalid" do user.name = nil expect(user).to be_invalid end end context "name is too long" do #nameが長すぎる場合 it "be invalid" do user.name = "a" * 31 expect(user).to be_invalid end end end end describe "Email" do context "email format is valid " do #emailのフォーマットが正しい場合 it "be valid" do user.email = "foobar@valid.com" expect(user).to be_valid user.email = "test@user.com" expect(user).to be_valid user.email = "user@example.com" expect(user).to be_valid end end context "email format is invalid" do #emailのフォーマットが正しくない場合 it "be invalid" do user.email = "foobar@invalid" expect(user).to be_invalid user.email = "__test@user.bar+org" expect(user).to be_invalid user.email = "foobar@example.com.." expect(user).to be_invalid end end context "email is nil" do #emailがない場合 it "be invalid" do user.email = nil expect(user).to be_invalid end end context "email is too long" do #emailが長すぎる場合 it "be invalid" do user.email = "a" * 256 + "@example.com" expect(user).to be_invalid end end context "email is already exists" do #emailが既存のものと重複している場合 it "be invalid" do second_user = user.dup second_user.email = user.email.upcase user.save! expect(second_user).to be_invalid end end end describe "Password validation" do context "submit valid values" do #passwordが有効である場合 it "be valid" do user.password = "password" expect(user).to be_valid end end context "password is nil" do #passwordがない場合 it "be invalid" do user.password = nil expect(user).to be_invalid end end context "password is too short" do #passwordが短すぎる場合 it "be invalid" do user.password = "test" expect(user).to be_invalid end end context "doesn't match with confimation" do #passwordと確認が合わない場合 it "be invalid" do user.password = "testuser" user.password_confirmation = "foobar" expect(user).to be_invalid end end endspec/factories/user.rbFactoryBot.define do factory :user, class: User do name { "TestUser" } email { "testuser@example.com" } password { "password" } password_confirmation { "password" } end end最初はminitestより書きにくいかもしれませんが、慣れるとより自然言語に近い形でテストが確認できます。
こう記述した方がより簡潔であるとか、自分だったらこのようにネストして記述するといったアドバイスがあればぜひよろしくお願いします。ありがとうございました。
- 投稿日:2020-11-22T20:58:11+09:00
TECH CAMP (エンジニア転職)7週目の学習内容の振り返り
みなさんおつかれさまです。今週やっとテックキャンプの最終課題が終わったので、明日から自分のポートフォリオの作成に入ろうと思います。ではでは、振り返りをやっていこうかと思います。
11/16~11/22までの学習進捗
・商品詳細表示機能の導入
・商品情報編集機能の導入
・商品削除機能の導入
・商品購入機能の導入正直いって詳細表示、編集、削除機能に関しては、そんなに難しくなかったですが、購入機能は結構な工数が必要になり、時間は結構かかりました。いつもならそれぞれの項目でどんなことをやったのかを書いているのですが、フリマアプリの商品情報に関する機能はそこまで難しくない上、文章として残しておけるほどの情報量を思い出せないので割愛しておきます(笑)。
・購入機能の導入
まず始めに、大まかに手順が必要だったのかを箇条書きで書くと、
・テーブルの作成(購入履歴と配送先の情報をDBに記録)
・フォームオブジェクトパターンの実装
・決済機能の導入
・テストコードの実装
・購入機能実装によるビューファイルの編集
という感じですね最初にやるテーブル作成では、2つのテーブル(購入履歴と配送先)が必要で、それらについての実装をしなければいけませんでした。これに関しては、先週に書いたER図やread.meの記述を参照しながらやったのでそこまでの時間はかからなかったですね。ただ次にやるフォームオブジェクトパターンの実装、自分の中ではこれが一番難しかったですね。
フォームオブジェクトパターンとは一つのフォームから複数テーブルへ情報に送信・保存を行うための手法で、一つのフォームから一つのテーブルに情報を保存する場合とは異なる記述をしなければいけません。やはり最大の違いは、MVCのやりとりの流れが違う点です。通常、一つのフォームから一つのテーブルに情報を保存する場合、コントローラーにストロングパラメーターを設定するモデルやDBに通す前に制限をかけるとおもうのですが、フォームオブジェクトパターンでは、取得する情報を新しく作成したモデル内に列挙し、どの情報をどのテーブルに割り振るのか振り分けを(モデル内で)行うという流れでデータベースに情報が送信・保存されます。その考え方があまり理解できなくて実装に時間をかけてしまいました。
決済機能の導入では、Pay.jpというカード決済代行サービス利用し、セキュリティ面に配慮しながら実装を進めなければいけませんでした。カード情報をそのまま送信しては第三者の介入でカード情報が抜き取られる可能性があるため、トークン化というものを行い、情報が漏洩しても悪用できない仕様にします。概念はわかるのですが、javascriptをいじる必要があるので面倒でした(苦手意識)。
テストコードの実装は今までの内容とやるべきことは変わらないものだったので時間はかかりましたが、難しくはありませんでした。
最後のビューファイルの編集は、商品の購入記録の有無で売り切れと表示したり、購入ボタンをなくしたりするものです。データの有無を判定するメソッド(nil?メソッド)を知らなかったのでこれも時間をかけてしまう作業でした。
土日のうちにカリキュラム外でやったこともいろいろあるのですが、それは一段落がついてから記事にしていこうと思います。来週は自作ポートフォリオについて進捗報告をしていこうと思います。
それでは!
- 投稿日:2020-11-22T18:42:10+09:00
[Rails]respond_toについて勉強してみた!![初心者]
respond_toメソッドとは?
URLにアクセスする際に、リクエストされるフォーマット(HTMLやJSONなど)ごとに、処理を分けることができるメソッドです。
リクエストのフォーマットは、URLの最後に拡張子(htmlやjsonやjs等)をつけることで、指定することが出来るものです。普段、インターネットを利用する時に、わざわざ拡張子まで意識して利用している人は少ないと思いますが、特にフォーマットの指定がなかった場合は、デフォルトのHTML形式で送信されます。
近年に入り、Web APIでJSON形式のデータを扱うことも増えたので、このメソッドを目にする機会も多くなりました。
つまり、通常はHTML形式で結果を取得できているのですが、明示的に他のフォーマットを指定された場合に備えて、この
respond_toメソッド
を使用しましょう、ということです。使い方
まずは基本構文から確認しましょう。
respond_to do |format| format.形式 {行いたい処理} end↑のように記述します。
具体的な使用例
books_controller.rbclass BooksController < ApplicationController def index @books = Book.all respond_to do |format| format.html {redirect_to root_path} format.json {render json: @books} format.js {render 'shared/index.js.erb'} end end endまた、
format.html
に処理の指定を記載しない場合もあります。books_controller.rbclass BooksController < ApplicationController def index @books = Book.all respond_to do |format| format.html #何も書かないパターン format.json {render json: @books} format.js {render 'shared/index.js.erb'} end end endこのように、
format.html
に具体的な指定を書かない場合は、デフォルトのテンプレートが指定されたフォーマットで表示されます。format.anyとは?
通常は、上記のような記述をするパターンがほとんどです。
まれに、それ以外のフォーマットを指定されるパターンもあり、
format_any
を使用することもあります。おわりに
メソッドの意味自体は、比較的簡単だと思うのですが、使いどころが難しいですね。
アプリを開発するときは、あらゆる可能性を考え抜いた上で、ユーザーに快適に使ってもらえるように、試行錯誤しないといけないということでしょうか。
- 投稿日:2020-11-22T16:35:01+09:00
Railsアプリのデプロイで「応答時間が長すぎます。」のserver errorに出くわした話
概要
Railsアプリを本番環境(AWS/EC2)にデプロイしようとIPアドレスでサーバーへ接続した際、「このサイトにアクセスできません。●●(IP),応答時間が長すぎます」とのエラーで長時間ハマったため、備忘録 兼 同じ境遇の方の参考になればと思い投稿しました。
実行環境
・Rails v5.1.7
・Ruby v2.7.0
・DB mysql
・AWS, EC2(本番環境)
・unicorn
・nginx結論 : config.force_ssl = true を有効にしていたことが原因
config/production.rbconfig.force_ssl = trueを
config/production.rbconfig.force_ssl = falseに変更することで改善出来ました。
config.force_ssl って何?
ずばり、IPアドレスへのアクセスを全てhttps形式として通信させる設定です。
つまり上記画像のように、意図せずとも自動でhttpsになるということ。
こちらのコードが書かれているconfig/production.rbはrailsアプリを本番環境上の設定を決めるファイル内にあります。 config.force_ssl = true のコードは通常コメントアウトされているのですが、開発中に外したことが原因となっていました。
今回私が立てたAWSのEC2サーバーは、通信形式をhttp形式のポート範囲でのみ設定しており、延々と許可していないhttps形式でアクセス処理をしていたことで、「応答時間が長すぎます」とのエラーが発生しました。環境によってはこのようなエラーも発生しなかった訳ですね...
余談ですが、解決までに悪戦苦闘し、自分なりに大切だなと思ったポイントを書かせて頂きます。
初心者の戯言だと思って鼻くそをほじりながらご覧になってください。笑サーバー通信エラー解決のポイント
①問題が起きているサーバー通信がどこなのかを特定する
②問題が起きているサーバーのログを読む
③ログを読んでもわからない場合は怪しいところをコピペしてひたすらググる!笑もう少しだけ掘り下げて書いていきます。
①について
クライアントがリンクをクリックしてアクセスしてからアプリケーションが表示されるまで、どのような通信が走っているのかを調べ以下の構造になっていることを学習しました。・EC2サーバー(ローカル環境の場合ここはスルー)
⬇︎
・webサーバー(今回の場合Nginx)
⬇︎
・アプリケーションサーバー(今回の場合Unicorn)そして、上記の順番に習い、1つずつ正しくアクセス出来ているか確認しました。
結果として、私の場合はEC2➡︎Nginxへの通信が原因でした。その確認方法については次の項で。
また、AWSへのデプロイに伴い、こちらの記事を参考にさせて頂きました。画像や細かいポイント付きでとてもわかりやすかったので、実行環境がマッチしていて上手くデプロイ出来ない方は是非参考にしてください!https://qiita.com/Yuki_Nagaoka/items/5be084c6efe1f797fd94
②について
・EC2サーバー
VPC,EC2等作成して公開鍵でログイン出来ていれば問題ないかなと思います。・webサーバー(私の場合ここが原因でした)
Nginx、デプロイするアプリ、Unicorn全てインストールし、ファイル設定を何度確認してもサーバーエラーでしたが、Nginxログが解決の糸口となりました!・nginx.access.log
・nginx.error.log
・Unicorn.lognginxやunicornでは、リアルタイムでアクセス履歴を記録してくれる上記ファイルが自動作成されています。そのファイルの中身を確認しましょう。ログファイルの場所は環境毎に違うかもしれません。私の場合、参考記事の作業で生成した /etc/nginx/conf.d/●●.confファイルの中で設定した場所に生成されていました)
cat /var/www/rails/アプリ名/log/nginx.access.log上記コマンドでnginx.access.logを表示し、IPアドレスにアクセスして再度logを確認。
すると、何度アクセスしてもアクセス履歴が更新されていないことに気付きました。
ここで初めて、webサーバー(Nginx)に上手く接続出来ていないこと(EC2➡︎webサーバーの通信が上手くいっていないこと)がわかり、ポイント③のようにググって記事を漁り、なんとか自力で解決に至りました!
ログを確認することの大切さをここでやっと理解しました。
今回は活用する必要がありませんでしたが、Nginxにアクセス出来ていると確認出来た場合は・同様の方法で、同ディレクトリのnginx.error.logの中身を確認。
tail -f /var/www/rails/アプリ名/log/nginx.error.log※tail -f :ファイルの最後に追加される文字をリアルタイムに表示するコマンド
(エラーが特定しづらい場合はcatコマンドで全て表示させて確認してください)エラーが起きている場合、Nginxのサーバー内での問題の可能性が高い
(Webサーバー➡︎アプリケーションサーバーの通信が上手くいっていない)・エラーがない場合は、
同ディレクトリのunicorn.logを確認。unicornの中で問題が起きていないか確認しましょう。
(アプリケーションサーバー内(アプリ内で)で問題が起きている)あとは③の通り、ログで見つけた怪しい部分をひたすら読む、ググるの繰り返しです笑
最後に
拙い記事にも関わらずここまで読んで頂きありがとうございます!
この記事が少しでも誰かのエラー解決の手助けになれば幸いです。
また、コードや考え方など間違っている可能性も十分にあります。その場合すぐに修正致しますので、気軽にコメントでご指摘頂ければと思います!
- 投稿日:2020-11-22T16:17:05+09:00
Rspecレスポンス確認方法
背景
テスト作成時、わざわざ手作業でアプリ動作させてログ上で正しいレスポンスを確認したり、
テストの途中binding.pryでブレークポイントを仕掛けて確認したりしていた...ここに書くこと
- テストを走らせたときにDB処理やrollback等のログを一緒に表示してくれる方法
- コンソール上でリクエストを送信してアプリ上で行われる処理を確認する方法
1. テスト実行時ログを標準出力(STDOUT)する方法
rails_helper.rbRails.logger = Logger.new(STDOUT) #railsのログ出力 ActiveRecord::Base.logger = Logger.new(STDOUT) #SQLのログ出力 RSpec.configure do |config| ・・・
2. コンソール上でリクエスト送信してレスポンスを確認する方法
appメソッドでappオブジェクトにアクセス
# サインインページを訪れて、トークンを発行する(CSRF対策) pry(main)> app.get 'http://localhost:3000/sign_in' # ワンタイムトークンの確認 pry(main)> token = app.session[:_csrf_token] => "????????" # 毎回POSTリクエスト行うときは authencity_token が必要になる pry(main)> app.post 'http://localhost:3000/sign_in', params: {authencity_token: token, user: "hogehoge"}参考
https://qiita.com/Esfahan/items/456df708d364987734ef
https://railsguides.jp/command_line.html#app%E3%82%AA%E3%83%96%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88%E3%81%A8helper%E3%82%AA%E3%83%96%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88
- 投稿日:2020-11-22T15:49:23+09:00
AWSのEC2インスタンスにカラム名の変更が反映されているのに変更前のカラム名がunknown attributeだというエラーが出る
起きたこと
データベースのカラムを変更するため、マイグレーションファイルを書き換えました。
その後、自動デプロイツールであるCapstranoでデプロイを更新しました。
動作を確認したところ、カラムを変更したフォームに入力する画面に遷移しようとした時に、unknown attributeというエラーが出ました。結論
teratailで質問をしたところ「アプリケーションサーバーの再起動はできているのか」とアドバイスいただきまして、Unicornのプロセスを確認したところ起動していませんでした。
Uniconが起動していなかった原因はわかりませんが、起動したところエラーがなくなり変更したカラムにも値が保存されるようになりました。下の図のようにアプリケーションサーバーが起動していなかったため、ビューなどは表示できたが、処理を行ったりDBへアクセスができずエラーになったと考えました。
teratailでの質問:https://teratail.com/questions/304282
質問前に行ったこと3つ
1. DBのカラム名確認
EC2内のDBであるMariaDBの中身を確認しました。
[ec2-user@ip-..... ~]$ mysql -u root -pでデータベースにアクセスした後は
USE アプリ名_productionでデータベースを指定し、
DESCRIBE テーブル名で確認するとカラムがみられます。
これでチェックしたところ、変更されていました。2.データベースとWebサーバーのリスタート
[ec2-user@ip-・・・・ ~]$ sudo systemctl restart mariadb [ec2-user@ip-・・・・ ~]$ sudo systemctl restart nginxこれでも変わりませんでした。
3. データベースをリセット
投稿していた中身は消えてしまいますが、以下の記事を参考に、EC2インスタンスのcurrentディレクトリに移動した後、以下の4つを実行してリセットしました。
$ RAILS_ENV=production DISABLE_DATABASE_ENVIRONMENT_CHECK=1 bundle exec rake db:drop $ rake db:create RAILS_ENV=production $ rake db:migrate RAILS_ENV=production $ rake db:seed RAILS_ENV=production参考:https://qiita.com/iczo32/items/84719b5aff8a6b9e37bd
以上
- 投稿日:2020-11-22T15:10:30+09:00
Rails 子レコードの作成・更新時に親レコードのupdated_atも更新する
こんにちは。
初めて記事を投稿してみます。Railsで子レコードを作成・更新時、親レコードのupdated_atも更新したい時
ActiveRecordの関連付けで、touchオプションを使えば簡単にできること知ったので
備忘のためにまとめてみます。touchオプション
Railsガイドより
:touchオプションをtrueに設定すると、そのオブジェクトがsaveまたはdestroyされたときに、関連付けられたオブジェクトのupdated_atタイムスタンプやupdated_onタイムスタンプが常に現在の時刻に設定されます。
class Shop < ApplicationRecord has_many :reviews end class Review < ApplicationRecord belongs_to :shop, touch: true end review = Review.last review.update( title: "いいお店") => # review.shop.updated_atも更新する利用シーン
キャッシュの無効化
このためにtouchオプションを使うのが一番多いようです。
Russian Doll Cachingという、ネストされたフラグメントキャッシュの内側のキャッシュ(review)が更新されると、外側のキャッシュ(shop)も更新してくれる機能で、子のmodelにtouchオプションをつければ有効になります。
キャッシュを自動で更新してくれるので便利ですね。検知処理の高速化
例えばこんな機能を追加しようとして
- お店(shop)の評点を集計する
- 評点は全レビュー(review)の平均点を使用する
これをバッチ処理で開発する場合
- 差分更新だけにしたい
- 更新対象は、前回バッチ実行時から今まででreview.updated_atが更新されたかで検知したい
touchオプションを付けておくと、review作成・更新時にshopのupdated_atも自動更新してくれるので、バッチ処理ではshopのupdated_atを参照するだけで集計対象を検知できるようになります。
(もしreviewのupdated_atを参照しようとすると、shopとReviewは1:Nなので参照するレコードが多くなり処理が遅くなります)touchしたくない場合
touchオプションを付けたものの、なんらかの理由(子レコードを大量作成や、全て更新)でtouchしたくない場合、
ActiveRecord.no_touching
で一時的に無効にできます。shop = Shop.last ActiveRecord::Base.transaction do ActiveRecord::Base.no_touching do shop.reviews.find_each do |review| # shopのupdated_atは更新されない review.update!(some_attributes) end end end参考URL
https://railsguides.jp/association_basics.html#belongs-to%E3%81%AE%E3%82%AA%E3%83%97%E3%82%B7%E3%83%A7%E3%83%B3-touch
https://postd.cc/the-complete-guide-to-rails-caching/
https://techracho.bpsinc.jp/hachi8833/2018_04_18/55475
- 投稿日:2020-11-22T15:03:58+09:00
【Rails6】Railsの既存アプリをDockerizeする【Docker】
はじめに
Hello,Qiita!
今回は既存のRailsアプリをDockerに乗せてみようと思います!
コンテナの中に環境を移すというシンプルなものですが、
webpackやyarnのインストールで少し引っ掛かったので、記事にしてみました!
docker-composeでRailsとMySQLの2つのコンテナをオーケストレーションしてみましょう
それではいきましょう!!前提条件
- OS: MacOS
- Ruby: 2.7.1
- Rails: 6.0.3
- データベース: MySQL
- Docker: 19.03.13
Dockerfileの記述
以下のように記述します。
DockerfileFROM ruby:2.7.1 ENV BUNDLER_VERSION="2.1.4" \ APT_KEY_DONT_WARN_ON_DANGEROUS_USAGE=DontWarn \ TZ=Asia/Tokyo RUN apt-get update && apt-get install -y \ build-essential \ libpq-dev \ nodejs \ mariadb-client \ sudo \ vim && \ 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 WORKDIR /app COPY Gemfile Gemfile.lock /app/ COPY . /app RUN bundle install -j4 && \ yarn upgrade && \ rails webpacker:install && \ yarn install --check-files COPY entrypoint.sh /usr/bin/ RUN chmod +x /usr/bin/entrypoint.sh ENTRYPOINT ["entrypoint.sh"] EXPOSE 3000 CMD ["rails", "server", "-b", "0.0.0.0"]何をやっているのか
FROM
Docker Hub にある(今回はRubyのバージョン2.7.1の)公式イメージを取ってくる。
ENV
環境変数の定義をする。
APT_KEY_DONT_WARN_ON_DANGEROUS_USAGE=DontWarn
↑これを書くとWarningメッセージを非表示にできるRUN
Dockerコンテナ上でコマンドを実行する。
apt-get
このコマンドは、Debian系ディストリビューション(DebianやUbuntu)のパッケージ管理システムであるAPT(Advanced Package Tool)ライブラリを利用してパッケージを操作・管理する、という意味。今回はRubyのイメージを取ってきたが、Debianイメージの上にrubyがインストールされてある。DebianはLinuxカーネルを利用しているためLinuxコマンドが使える。WORKDIR
ワークディレクトリの設定をする。
同じDockerfile内に複数回指定可能で、ENVで登録したパスを利用してもよい。COPY
新しいファイルをフォルダコピーする(圧縮されているファイルは展開されない)。
ENTRYPOINT
記述されたコマンドの実行をする。
EXPOSE
特定のポートを解放する。
CMD
実行するコンテナのデフォルト値を設定する。
同じDockerfile内で使用できるのは一回のみで、ENTRYPOINTに対して引数を設定することも可能である。
Dockerfileには、少なくとも一回はENTRYPOINTかCMDを記載すべき。docker-compose.ymlの記述
以下のように記述します。
docker-compose.ymlversion: '3' services: app: build: . command: bash -c "rm -f tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'" volumes: - .:/myapp - ./vendor/bundle:/myapp/vendor/bundle:delegated ports: - "19802:3000" # "任意のポート:3000" とする depends_on: - db tty: true stdin_open: true db: image: mysql:5.7 environment: MYSQL_ROOT_PASSWORD: "password" ports: - "19801:3306" # こちらも、"任意のポート:3306"とする volumes: - ./tmp/db:/var/lib/mysql何をやっているのか
version
使用するdocker-composeのバージョンを定義する。
services
アプリケーションを動かすための各要素(service)を定義する。(今回は
app
とdb
)build
composeファイルを実行し、ビルドされるときのパスを指定する。
command
デフォルトコマンドをオーバーライドする。
volumes
マウントする設定ファイルのパスを指定する。
ports
Dockerイメージを立ち上げる際のポート番号を指定する。
depends_on
service同士の依存関係を指定する。
environment
環境変数を指定する。
tty: true
コンテナが起動し続けるよう設定する。
stdin_open: true
コンテナ内の標準入出力の許可を設定する。
entrypoint.shの記述
以下のように記述します。
entrypoint.sh#!/bin/bash set -e # Railsのserver.pidファイルを取り除く rm -f /app/tmp/pids/server.pid # コンテナのメインプロセスを実行する (DockerfileでCMDと設定されているもの)。 exec "$@"database.ymlの記述
以下のように記述します。
database.ymldefault: &default adapter: mysql2 pool: 5 timeout: 5000 # 任意 development: <<: *default database: myapp_development username: root password: password host: db port: 3306GemfileとGemfile.lockの確認
今回は既存アプリをDockerにのせるので、GemfileとGemfile.lockが存在していることを確認するだけで良いです。
docker-composeの起動
ターミナルで
docker-compose build
を実行します。ターミナルSuccessfully built ~ Successfully tagged ~と出力されればビルド成功です。
次に、
docker-compose exec app bash
を実行し、appコンテナ内に入ります。その後、
bundle exec rails db:create
bundle exec rails db:migrate
bundle exec rails db:seed
を実行し、無事完了です!終わりに
最後までご覧いただきありがとうございました。
個人的には、コンテナの中に入って作業をするのがめちゃ楽しいです。
なぜかはわかりません。(インセプション的な気持ちになる)
また、不適切な表現などありましたらお知らせいただけると幸いです。それではまた!
- 投稿日:2020-11-22T14:46:47+09:00
lメソッドで時刻の表示が指示通りできない
起きたこと
https://qiita.com/jnchito/items/831654253fb8a958ec25
に従い設定をしました。
しかし、ja.ymlのdefaultをいくらいじってもブラウザに指示通りの表記がされませんでした。ja.ymlja: time: formats: default: "%Y/%m/%d"結論
ja.ymlファイルの中に2つja:の塊を作っていたことが原因でした。
もう一つのja:の塊とは別のことも記述していました。具体的にはエラー時に表示されるカラム名を日本語に変換するためのデータです。ja.yml改善前ja: time: formats: default: "%Y/%m/%d" ja: activerecord: attributes: user: nickname: 名前 grade_id: 段位 email: Email password: パスワード password_confirmation: 確認用パスワードこれを一つにまとめて、
ja.yml改善後ja: time: formats: default: "%Y/%m/%d" activerecord: attributes: user: nickname: 名前 grade_id: 段位 email: Email password: パスワード password_confirmation: 確認用パスワードとすることで年/月/日の表示が無事できました。
インデントの幅がスペース一つずれていても認識されなかったので注意が必要です。以上
- 投稿日:2020-11-22T14:03:17+09:00
【初学者向け】単体テスト・機能テスト・統合テストを書こう【Rails Tutorial】
経緯
先日RailsTutorialを修了し、自分でコードを書き始めた途端にテストを書かなくなってしまいました。
これは非常に良くないと思ったので、勉強した内容について簡単にまとめておきます。この記事で(多分)わかること
- テストを書くことのメリット
- RailsTutorialに登場する単体テスト・機能テスト・統合テストの違い
- それぞれのテストが何を対象としているか、どんなテストを書けばいいのか
テストを書くことのメリット
まずは勉強のモチベーションを上げるために、テスト自動化ができると何が嬉しいのかを調べました。
1. テスト作業の効率化と工数の削減
テストを手動で行っていた工数を大幅に削減し、開発に時間を割けるようになる。
リアルタイムでテストを実行できるため、誤ってコードを改変したときにどこが悪かったのか即座に検知できる。2. テスト作業におけるヒューマンエラーの排除
機械が何度でも正確にテストを繰り返してくれるため、人的ミスを排除することができる。
3. 手動では実現できなかったテスト作業を実現
「数万件の同時アクセス」などの負荷テストや、イレギュラーなテストパターンを容易に実行できる。
ポートフォリオ作成に取り掛かる初学者にとっては、1.が感じやすいメリットだと思います。
「上手くいっていたものを動作しないコードに書き換えてしまう」ことが頻発してしまいそうなので、それをリアルタイムで検知してくれるのは非常に頼もしく、安心してリファクタリングできそうです。
先にまとめ
テストの種類 テスト対象 テスト方法 テストを記載するファイル 単体テスト モデル モデルに記載された機能に対して、テストデータを投入して結果を確認する test/models 機能テスト コントローラ コントローラに対してHTTPリクエストを発行し、コントローラの振る舞いを確認する test/controllers 統合テスト モデル・コントローラ・ビュー 想定されるユーザの操作フローを模倣して、モデル・コントローラ・ビューの一連の振る舞いを確認する test/integration 以下でそれぞれのテストについて記載していきます。
単体テスト
単体テストはモデル(/app/models/xxx.rb)単位に記述します。
モデルに記載したバリデーションチェック等の機能一つに対して、対応するテストを一つ記述するイメージです。例)
models/user.rbclass User < ApplicationRecord validates :name, presence: true, length: { maximum: 50 } endtest/models/user_test.rbdef setup @user = User.new(name: "Example User", email: "user@example.com", password: "foobar", password_confirmation: "foobar") end #user.nameのバリデーションに関するテスト test "name should be present" do @user.name = " " assert_not @user.valid? end test "name should not be too long" do @user.name = "a" * 51 assert_not @user.valid? end上記の例ではuserモデルのnameというカラムに以下のバリデーションチェックを設けています。
1. 名前が空白でないこと
2. 50字以内であることそれに対して以下のテスト実行しています。
1. 名前が空白の@userを作成し@userが無効になること
2. 名前が51文字の@userを作成し@userが無効になること上記は非常に単純な例ですが、複雑な機能でもやっていることは一緒のような気がします。
モデルに一つ機能を追加するたびに一つテストも追加するようなイメージですかね。機能テスト
機能テストはコントローラ(/app/controllers/xxx_controller.rb)単位に記述します。
「def new」「def create」などのアクション一つ一つに対して記述するイメージです。コントローラにHTTPリクエスト(GET,POST,PATCH,DELETE)を送り、
それに対するコントローラの振る舞いが想定通りであるかどうかを確認します。例)
controllers/users_controller.rbdef create @user = User.new(user_params) #ユーザの保存に成功した場合は、①flashにメッセージを格納し②ログインした後③ユーザ詳細画面にリダイレクトする if @user.save flash[:success] = "Welcome to App!" login @user redirect_to @user #ユーザの保存に失敗した場合は、再びユーザ登録画面にリダイレクトする else render 'new' end endtest/controllers/users_controller_test.rb#有効なユーザ情報を登録した場合のcreateアクションの振る舞いをテストする test "should get create with valid user" do #ユーザ登録画面にアクセスし、正常応答を得る get new_user_path assert_response :success #有効なユーザ登録のPOSTリクエストを送り、ユーザの数が1増えることを確認する assert_difference 'User.count', +1 do post users_path, params: { user: { name: "Example User", email: "user@example.com", password: "foobar", password_comfirmation: "foobar"} } end #flashにメッセージが格納されている(ユーザ登録成功のメッセージ)ことを確認する assert_not flash.empty? #ユーザ登録後ログインできていることを確認する assert is_logged_in? end #無効なユーザ情報を登録した場合のcreateアクションの振る舞いをテストする test "should get create with invalid user" do #ユーザ登録画面にアクセスし、正常応答を得る get new_user_path assert_response :success #無効なユーザ登録のPOSTリクエストを送り、ユーザの数が増減しないことを確認する assert_no_difference 'User.count' do post users_path, params: { user: { name: " ", email: " ", password: " ", password_comfirmation: " "} } end #flashにメッセージが格納されている(ユーザ登録失敗のメッセージ)ことを確認する assert flash.empty? #ユーザ登録後ログインできていないことを確認する assert_not is_logged_in? #ユーザ登録画面にリダイレクトされていることを確認する assert_template 'users/new' end上記の例では、userコントローラのcreateアクションの想定される振る舞いは以下の2通りです。
1. 登録時のユーザ情報が有効である場合、ユーザを登録しユーザ詳細画面に遷移する
2. 登録時のユーザ情報が無効である場合、再度ユーザ情報入力画面に遷移するそれに対して以下のテストを実行しています。
1. 有効なユーザ情報のPOSTリクエストを送信し、ユーザ詳細画面に遷移すること
2. 無効なユーザ情報のPOSTリクエストを送信し、ユーザ登録画面に戻されること「アクション一つにつきテスト一つ」というわけではなく、
「リクエストに対して想定される振る舞いの数のテストが必要」という点がポイントかなと思いました。統合テスト(UIテスト)
統合テストはユーザーの実際の操作を想定し、操作のフローに伴うアプリの挙動を確認します。
テストを書くにあたってアプリケーションでユーザがどのような操作をできるのかを洗い出す必要がありそうです。例)
test/integration/site_layout_test.rbrequire 'test_helper' class SiteLayoutTest < ActionDispatch::IntegrationTest test "layout links" do #ホーム画面に遷移する get root_path #遷移先のURLが想定されたものであることを確認する assert_template 'static_pages/home' #遷移先画面で表示されているリンクの数が想定された通りであることを確認する assert_select "a[href=?]", root_path, count: 2 assert_select "a[href=?]", help_path assert_select "a[href=?]", about_path assert_select "a[href=?]", contact_path end end上記の例では、「ユーザがホーム画面に遷移する」という操作を想定ししています。
- ルートパスにgetリクエストを送り、ホーム画面に遷移することを確認する
- 遷移したホーム画面にて、画面上に表示しているリンクが想定通りであることを確認する
前述までの単体テスト・機能テストでは死んでいるリンクなどを検知できません。
統合テストを書くことでビューのバグも検知できるため、自分でブラウザを開いて一個一個クリックする必要がなくなりそうです。本当にあっている?
ここまで記載しましたが、自分で怪しいと思っている点が2点あります。
機能テストの例で出したものは本当に機能テストになっているか?
機能テストの例としたcreateコントローラのテストは「ユーザのログイン」操作を模倣した統合テストとも捉えられます。
統合テストを書こうとしても上述した機能テストの繰り返しのようになってしまう気がしました。
①userコントローラにgetリクエストを送り、アクセスできることのテスト
②userコントローラに有効なpostリクエストを送り、ユーザ登録できることのテスト
③userコントローラに無効なpostリクエストを送り、ユーザ登録できないことのテスト
とリクエスト一発に対して何が帰ってくるかを細かく区切った一つ一つが機能テストになるでしょうか?「テストを記載するファイル」について別にルールはないのでは?
上記の「test/controllers」に記載しているテストは「test/integration」の中に記載しても動きます。
極端に言えば全てのテストを同じファイルに記載しても、テストは実行可能なのではないでしょうか。
Tutorialで分かりやすいフォルダ構成を決めているだけで、テストを書くファイルは実際には自由?・・・有識者の方、ご指摘いただけると助かります。
最後に
RailsTutorialは
出てきたテストをそのままコピーしていたので、
それぞれのテストの違いを理解しないまま進めてしまっていたので、今回整理できてよかったです。誤っている記述などあれば、コメントにてご教示いただけると助かります。
- 投稿日:2020-11-22T12:19:28+09:00
[Rails]dry_validationでドライなバリデーションを構築
dry-validationて?
railsでのバリデーションをdryにやってくれるgemです。
備忘録として残しておきます。
https://dry-rb.org/gems/dry-validation/1.5/schemas/導入
Gemfilegem 'dry-validation' gem 'dry-struct'設定
class ApplicationContract < Dry::Validation::Contract config.messages.default_locale = :ja config.messages.backend = :yaml config.messages.load_paths << 'config/errors.yml' endバリデーションエラー時のメッセージ
キーとバリューはyamlに記載します。
config/errors.ymlja: dry_validation: errors: str?: '文字列ではない' int?: '数字ではない' array?: '配列ではない' filled?: '空です' rules: name: hogehoge: 'ホゲホゲ' カラム名: ...バリデーションルール
class HogeContract < ApplicationContract params do required(:name).filled(:string) optional(:email).filled(:string) required(:age).maybe(:integer) end rule(:name) do key.failure(:hogehoge) if ~ end end
required
:パラメータが存在しているかチェック
optional
:パラメータの存在は任意
filled
:型のチェック
maybe
:型のチェック、nilの時は発火しないruleでバリデーション対象のカラムを指定し、その中にバリデーションルールを記述します。
呼び出し
HogeContract.new.call( name: params[:name], email: params[:email], age: params[:age] ).errors.to_hバリデーションルールを記述したクラスを生成し、callで呼び出します。
引数にはparamsで使うものを全て渡すようにします。
終わりです。なんか記事もドライになったな、、、
- 投稿日:2020-11-22T11:01:17+09:00
本番環境のコマンドを開発環境で実行してしまった場合の対処
はじめに
今回は本番環境で行うコマンドを間違って開発環境で実行してしまいエラーが発生してしまったのでそうなってしまった理由や原因を調べていきます。
やってしまったこと
AWSでEC2のサーバーを立ち上げるために以下のコードを誤って開発環境で実行してしまった...
$ bundle install --path vendor/bundle --without test developmentそこから
bundle install
やサーバーを立ち上げようとするとエラーが発生するようになりました。bundle installで
Nokogiri
がインストールできないエラーGem files will remain installed in /home/vagrant/work/SMB/vendor/bundle/ruby/2.5.0/gems/nokogiri-1.10.9 for inspection. Results logged to /home/vagrant/work/SMB/vendor/bundle/ruby/2.5.0/extensions/x86_64-linux/2.5.0/nokogiri-1.10.9/gem_make.out An error occurred while installing nokogiri (1.10.9), and Bundler cannot continue. Make sure that `gem install nokogiri -v '1.10.9' --source 'https://rubygems.org/'` succeeds before bundling.何が行われてしまったのか?
$ bundle install --path vendor/bundle --without test developmentこのコマンドで
bundle install
でオプションを付けている
--path
でインストール先をいつものパスではなくて指定したパスのディレクトリにインストールをしている(vendor/bundle
)
rubyはrbenv
ファイルにインストールをしなければいけないのにvendor/bundle
にインストールをしてしまっている
--without
(意味:除外します/抜きにする)
今回だとtest development
を除外します
development(開発)環境なのにインストールしないのはマズい...
bundle install
に一回でもオプションをつけるとbundle
ファイルがずっと覚えていてくれるのでずっとそのオプションになってしまう原因!
bundle install
にオプションを付けてしまったのが原因解決策
bundleファイルの中身を修正
.bundle/config
ファイルの中が先ほどbundle install
した際のオプションが入っているのでそこを修正。修正前
--- BUNDLE_PATH: "vendor/bundle" BUNDLE_WITHOUT: "test:development:production"修正後
--- BUNDLE_WITHOUT: "production"これでまたうまく動くようになりました!
最後に
エラーが出た時はかなり焦りましたがしっかりしてしまったことを理解することが大事だと思いました。
またコマンド一つ一つが何をしているのか把握していくのが大事だと改めて知る機会になりました。
- 投稿日:2020-11-22T09:40:56+09:00
【エラー】Postgres PG::ConnectionBad: could not connect to server: No such file or directory Is the server running locally and accepting connections on Unix domain socket "/tmp/.s.PGSQL.5432"?【Rails】
brew install imagemagick
した後にサーバーを立ち上げると下記のエラーが。したこと
とりあえずhttps://qiita.com/great084/items/98c83364f246473249c4 を参照。
しかしエラーは解決せず。postgres -D /usr/local/var/postgres 2020-11-21 23:37:47.476 AEDT [84006] FATAL: database files are incompatible with server 2020-11-21 23:37:47.476 AEDT [84006] DETAIL: The data directory was initialized by PostgreSQL version 12, which is not compatible with this version 13.1.postgresqlのバージョンをあげたらいけるっぽいのであげてみる
brew postgresql-upgrade-database Error: Upgrading postgresql data from 12 to 13 failed! ==> Removing empty postgresql initdb database... ==> Moving postgresql data back from /usr/local/var/postgres.old to /usr/local/v Error: Failure while executing; `/usr/local/opt/postgresql/bin/pg_upgrade -r -b /usr/local/Cellar/postgresql@12/12.5/bin -B /usr/local/opt/postgresql/bin -d /usr/local/var/postgres.old -D /usr/local/var/postgres -j 4` exited with 1.何故かバージョンがあげれないというエラーが。
そこで、以前postgresql関連のエラーが出たときにした事を思い出してbrew doctor
を実行Warning: Git could not be found in your PATH. Homebrew uses Git for several internal functions, and some formulae use Git checkouts instead of stable tarballs. You may want to install Git: brew install git Warning: No developer tools installed. Install the Command Line Tools: xcode-select --install Warning: Your Xcode does not support macOS 10.15. It is either outdated or was modified. Please update your Xcode or delete it if no updates are available. Warning: Xcode alone is not sufficient on Catalina. Install the Command Line Tools: xcode-select --install検知された問題を解消していく。
そして再度postgresqlのバージョンをあげてみるbrew postgresql-upgrade-database ~~(省略)~~ ==> Upgraded postgresql data from 12 to 13! ==> Your postgresql 12 data remains at /usr/local/var/postgres.old無事にバージョンをあげることができ、サーバーもエラーが出ずに立ち上げれました!
- 投稿日:2020-11-22T06:18:33+09:00
Rails で既存カラムにdefault オプションを追加したい
はじめに
Rails で既存カラムのdefault オプションを追加したい場面があったので備忘録です。
環境
- macOS 10.15.6
- Ruby 2.5.7
- Rails 5.2.3
参考URL
https://railsguides.jp/active_record_migrations.html
https://qiita.com/toda-axiaworks/items/dcc24c8e4b23318e37f4
http://tanihiro.hatenablog.com/entry/2014/01/10/182122目標
- 既存カラムにdefault オプションのみ変更したい
- きちんとロールバックできるmigration ファイルを作成したい
ロールバック用のメソッドについて
up/down
メソッドchange
メソッド上記の2つのパターンでmigration ファイルを記述できますが、オプションの変更のみであれば
change
メソッドの方がシンプルでロールバックも可能ということなので今回はchange
メソッドで進めます。
こちらの記事を参考にしました。ありがとうございました。実装
Users テーブルのid カラムに
default: 0
オプションを追加する想定です。
- migration ファイル作成
- migration ファイルにオプションを追加する処理を追加
- migrate して設定を反映させる
# 既存カラムのオプション変更用migratiton ファイル作成 $ rails g migration change_column_default_to_users# migration ファイルでdefault値に0 を追加 class ChangeColumnDefaultToUsers < ActiveRecord::Migration[5.2] def change change_column_default :users, :id, from: nil, to: "0" end end# migration ファイルの各項目の詳細 def change change_column_default :テーブル名複数形, :カラム名, from: 変更前のdefault オプションの状態, to: 変更したいdefault オプション end
default: true/false
,dafault: デフォルト値
などのオプション変更も可能です。# 作成したmigration ファイルでmigrate $ rails db:migrate # migrate の履歴を確認 $ rails db:migrate:status学び
- option を追加するだけだったのに以外にハマってしまった
- migration ファイルはロールバックできるのかを意識して書く事が重要
- オフィシャルのドキュメントはちゃんと読む事
- 投稿日:2020-11-22T06:01:33+09:00
【Rails】でデータを保存・更新後に直前のページに戻りたい!
はじめに
たとえばECサイトの購入ページからユーザー情報を更新した後、トップページに飛ばされたらどうでしょう?
ユーザーはまた購入画面にアクセスし直さなければならず、かなりUXが悪い状態になってしまいます。直接指定すれば良いのでは?
もちろんページ同士が1対1の関係にある場合はこれでOKです。
しかし、ユーザー情報の更新などは他のページからも行えるようにしたいですよね。
ページの関係が多対1の場合、リンク元によって戻るページを変える必要があります。1つ前のページに戻す方法
1つ前に戻る方法はRailsに標準メソッドにあるので簡単です。
redirect_back(fallback_location: root_path)しかし、今回はこれを使うことができません。
実は「2つ前」に戻さないといけない
データの保存・更新では
元のページ
→new
→create
と遷移するので元のページに戻るには2つ前に戻らないといけません。そこで、戻りたいページのURLをセッションに保存し、create後にそのページに遷移する設定にします。
controllerdef new session[:previous_url] = request.referer # ここで前ページセッションを保存 end def create redirect_to session[:previous_url] # create後に遷移させる end
request.referer
で遷移元のURLを取得することができるので、それをセッションに保存し、createメソッド後に保存しておいたセッションを利用してnew直前のページに遷移させています。
これで2つ前のページに戻ることができます。参考
Referer - HTTP | MDN
https://developer.mozilla.org/ja/docs/Web/HTTP/Headers/RefererAction Controller の概要 - Railsガイド
https://railsguides.jp/action_controller_overview.html#request%E3%82%AA%E3%83%96%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88%E3%81%A8response%E3%82%AA%E3%83%96%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88