- 投稿日:2021-02-20T23:21:24+09:00
Railsで開発中にデータベースのレコードを削除したい時は?
目的
開発中に作成したデータベース内のレコードをすべて削除したい。
例)ユーザーテーブルの「test_user」など適当に作ったユーザーデータ方法
ターミナルで「rails db:reset」コマンドを実行。
これでデータベースの中身が空っぽになる。terashimatakaya@MacBook-Air furima-34501 % rails db:reset Dropped database 'furima_34501_development' Dropped database 'furima_34501_test' Created database 'furima_34501_development' Created database 'furima_34501_test'Railsガイドv6.1 「4.3データベースをリセットする」によるとこのコマンドで行ったことは、「rails db:drop db:setup」と同等とのこと。
注意点としては「rails db:migrate」の意味は含まれていない点。解説
「rails db:drop」コマンド
データベースを削除するコマンド。usersテーブルやらが全て削除される。
「rails db:create」する前の状態に戻ると思えばOK。「rails db:setup」コマンド
データベースの作成、スキーマの読み込み、シードデータを用いてデータベースの初期化を実行。
実際にRailsがやってる処理の流れは、
①既存のdb/schema.rbを読み込む
②①の情報を頼りにデータベースを再作成
③再作成のタイミングでdb/seeds.rbに開発用のサンプルデータがあればそれもこのタイミングで再度流し込む補足
なぜ「db/schema.rb」を参照するのか?
簡単に説明すると、古いマイグレーションファイルたちもイチから順に実行するとエラーが起きやすくなるから。
それよりも常に最新の状態に保たれているだろうschema.rbの情報をもとにしたほうがエラーが起こらず再度データベースを作成できるから、といったかんじだろうか。
詳細は以下のリンクで確認してください。
- 投稿日:2021-02-20T22:59:32+09:00
「omniauth」とDevise「recoverableモジュール」を同時に使う時の挙動分岐
タイトルがいまいち意味不明ですが、下記のやりたいことを実装する上で調べたことが非常に勉強になったので記録しておきます。
前提条件
・認証にdeviseを使用。googleなどの外部サービスのログインも実装している
やりたいこと
①通常のemail、passwordでログインした場合、ユーザー情報を変更する
(edit_user_registration_path)
時にパスワード変更フォームを表示。情報変更の際に現在のパスワードの入力を要求するように設定。②外部サービスログインを使った場合は
(edit_user_registration_path)
でパスワード変更フォーム、現在のパスワード入力欄を非表示。情報変更の際に現在のパスワード入力も不要な設定にする。こういった挙動を実装したい。
実装
①ログイン認証の方式によって、Viewの表示を変更する。
app/views/devise/registrations/edit.html.erb<%if current_user.uid == nil %> <div class="field"> <%= f.label :password %> <br /> <%= f.password_field :password, autocomplete: "new-password" , class: "form-control form-control-comment" %> <% if @minimum_password_length %> <br /> <em><%= @minimum_password_length %> characters minimum</em> <% end %> </div> <p class="comment">(変更したくない場合は空白のままにしてください)</p> <div class="field"> <%= f.label :current_password %> <br /> <%= f.password_field :current_password, autocomplete: "current-password", class: "form-control form-control-comment" %> </div> <p class="comment">(変更するには現在のパスワード入力が必要です)</p> <% end %>通常のメールアドレスとパスワードのログインの場合はプロバイダから返ってくる、
uid
はnilになっている。それをif文でViewの表示を分岐させた。
②ユーザー情報を更新する時にパスワード要否を分岐させる
deviseの初期設定ではユーザー情報を更新する時は現在のパスワード入力を求められる。
app/controllers/users/registrations_controller.rbclass Users::RegistrationsController < Devise::RegistrationsController . . . protected def update_resource(resource, params) if current_user.uid == nil resource.update_with_password(params) else resource.update_without_password(params) end end endどういうことだろう?
rails g
で自作したUsers::RegistrationsController
はDevise::RegistrationsController
を継承している。情報を更新する時の仕組みは
Devise::RegistrationsController
のupdateメソッドを読んでいる。
色々辿っていくと、def update_resource(resource, params) resource.update_with_password(params) endこの
update_with_password
メソッドにつながる。require 'devise/strategies/database_authenticatable' module Devise module Models . . . def update_with_password(params, *options) ... current_password = params.delete(:current_password) if params[:password].blank? params.delete(:password) params.delete(:password_confirmation) if params[:password_confirmation].blank? end result = if valid_password?(current_password) update(params, *options) else assign_attributes(params, *options) valid? errors.add(:current_password, current_password.blank? ? :blank : :invalid) false end . . . end endこのメソッドは現在のパスワードが入力されていない、もしくは間違っている場合は情報を更新しないようになっている。
この
update_with_password
と同じところにupdate_without_password
メソッドもある。
これこそがパスワードなしで情報を変更できるメソッド。仕組みがわかれば
Users::RegistrationsController
でupdate_resource
メソッドを上書きする。
やりたいことはViewと同じであり、現在のユーザーがプロバイダから返ってくるuidを保持しているかnilかで発火させるメソッドを分岐させた。学び
ググれば色んな方が情報発信してくれているが、一次情報を見る癖もつけないといけない
参考
https://github.com/heartcombo/devise/tree/769506e96cd45b36a311eeca293ce0228c58e5f3
- 投稿日:2021-02-20T21:08:58+09:00
Rubyインストールに伴うMSYS2インストール時のエラーについて
環境
- Windows 10
- Ruby 3.0.0
どこで引っかかったか
Rubyをインストールする
RubyInstallerを使ってインストールした
ここは特に問題なし。MSYS2をインストールする
ここで以下のようなエラーで出てうまくインストールできていないような感じ
エラー: mingw32: "David Macek <david.macek.0@gmail.com>" の署名は信頼されていません エラー: mingw64: "David Macek <david.macek.0@gmail.com>" の署名は信頼されていません詳細
C:\Windows\System32>ridk install _____ _ _____ _ _ _ ___ | __ \ | | |_ _| | | | | | |__ \ | |__) | _| |__ _ _ | | _ __ ___| |_ __ _| | | ___ _ __ ) | | _ / | | | '_ \| | | | | | | '_ \/ __| __/ _` | | |/ _ \ '__/ / | | \ \ |_| | |_) | |_| |_| |_| | | \__ \ || (_| | | | __/ | / /_ |_| \_\__,_|_.__/ \__, |_____|_| |_|___/\__\__,_|_|_|\___|_||____| __/ | _ |___/ _|_ _ __ | | o __ _| _ _ | (_) | |^| | | |(_|(_)\^/_> 1 - MSYS2 base installation 2 - MSYS2 system update (optional) 3 - MSYS2 and MINGW development toolchain Which components shall be installed? If unsure press ENTER [1,3] 3 > sh -lc true MSYS2 seems to be properly installed Install MSYS2 and MINGW development toolchain ... > pacman -S --needed --noconfirm auto略ds-git エラー: mingw32: "David Macek <david.macek.0@gmail.com>" の署名は信頼されていません エラー: mingw64: "David Macek <david.macek.0@gmail.com>" の署名は信頼されていません エラー: msys: "David Macek <david.macek.0@gmail.com>" の署名は信頼されていません エラー: データベース 'mingw32' は無効です (無効または破損したデータベース (PGP 鍵)) エラー: データベース 'mingw64' は無効です (無効または破損したデータベース (PGP 鍵)) エラー: データベース 'msys' は無効です (無効または破損したデータベース (PGP 鍵)) Install MSYS2 and MINGW development toolchain failed Installation failed: pacman failed 1 - MSYS2 base installation 2 - MSYS2 system update (optional) 3 - MSYS2 and MINGW development toolchain Which components shall be installed? If unsure press ENTER []どうやって解決したか
- MSYS2を更新
- 再度ridk installを実施
という感じで進めました。
Rubyをインストールしたフォルダ内にあるMSYS2.exeを実行する
C:\Ruby30-x64\msys64\msys2.exe表示されたコマンドラインでMSYS2を更新
以下issueを参考に、↓のコマンドを実行
https://github.com/msys2/MINGW-packages/issues/240pacman-key --init pacman-key --populate msys2 pacman-key --refresh-keysこの後↓を複数回実施する
pacman -Syuu再度ridk installを実施したら、通りました。
やったぜ
- 投稿日:2021-02-20T19:25:26+09:00
【Ruby】rbenvを利用し、Macターミナル上にRuby3.0.0をインストールしました
はじめに
『プロを目指す人のためのRuby入門』を活用しRuby学習を深めるにあたり、
MacOSのターミナル上にRubyの最新版をインストールしました。
本記事はその備忘録です。前提条件
- MacOS(M1チップ搭載モデル)
- Homebrewインストール済み
- rbenvをインストールし、Ruby3.0.0をインストールする予定
インストールまでの流れ
- 現在ターミナル上で使っているRubyのバージョンを確認
- Homebrewが使えるかどうか確認
- rbenvをインストール
- rbenvでインストール可能なRubyのバージョンを確認
- Rubyをインストールする
- ターミナル上でインストールしたRubyを使えるようにする
- ターミナル上で使えるRubyのバージョンを確認する
RubyのバージョンとHomebrewの確認
1.現在ターミナル上で使っているRubyのバージョンを確認
username$ ruby -v =>ruby 2.6.3 #人によって異なります私の場合は2.6のバージョンがデフォルトでインストールされていました。
この項目は人によって異なると思います。2.Homebrewが使えるかどうか確認
username$ brew doctor =>Your system is ready to brew. #これが出力されたらOK!上記以外の結果が出た場合は何らかのエラーが起こっているので、安全に使えないよ〜
という状態です。
エラーが解消できれば上記の結果が出力されるはずです。
ちなみに私の場合は、
Warning! 「コマンドラインツールをアップデートしてね!」
と出力されたため、CLTをアップデートさせたところ上記結果が出力されました。rbenvインストール〜Rubyを使用可能にする
3.rbenvをインストール
username$ brew install rbenv username$ rbenv --version #rbenvのバージョンを確認&インストールできているか確認 =>rbenv 1.1.2 #(2021/2時点)4.rbenvでインストール可能なRubyのバージョンを確認
username$ rbenv install --list =>2.5.8 2.6.6 2.7.2 3.0.0 ...etc #インストールできるRubyのリストが出力されます5.Rubyをインストールする
username$ rbenv install 3.0.0 username$ rbenv versions =>* system (set by /Users/username/.rbenv/version) 3.0.0*system~ の出力結果は、.rbenv/version下で利用できるRubyのバージョンです。
rbenvを利用しRuby3.0.0のインストールはできていますが、
まだMacOS上で利用できるRubyは変更されていません。6.ターミナル上でインストールしたRubyを使えるようにする
7.ターミナル上で使えるRubyのバージョンを確認するusername$ rbenv init =>"$(rbenv init -)" #bash_profileにパスを通す username$ echo 'eval "$(rbenv init -)"' >> ~/.bash_profile #再読み込み username$ source ~/.bash_profile #ターミナル上のRubyバージョンを確認 username$ ruby -v =>ruby 3.0.0これで最新版Rubyをターミナル上で使えるようになりました!
bash_profile が見つからない、とエラーになった場合は、
ホームディレクトリにbash_profileファイルを作成する必要があります。まとめ
今回は下記の流れでターミナル上でRubyを利用できるようにしました。
- 現在ターミナル上で使っているRubyのバージョンを確認
- Homebrewが使えるかどうか確認
- rbenvをインストール
- rbenvでインストール可能なRubyのバージョンを確認
- Rubyをインストールする
- ターミナル上でインストールしたRubyを使えるようにする
- ターミナル上で使えるRubyのバージョンを確認する
他設定にあたり必要な項目などありましたら、随時追記していきます!
参考記事
- 投稿日:2021-02-20T18:22:43+09:00
cannot load such file -- nokogiri/nokogiri (LoadError) を解決する方法
この記事では、
cannot load such file -- nokogiri/nokogiri (LoadError) を解決する方法
について書いていきます。あくまで、僕自身が実際に行った方法ですので、全員がうまくいくとは限りません。
ですが、少しでも参考にしていただけたら幸いです。
解決法
実際のエラー
$ rails s require': cannot load such file -- nokogiri/nokogiri (LoadError)何行もあるエラーの最後にこのような文が記載されていました。
gem install nokogiri
などを行っても変わりませんでした。$ which ruby /usr/bin/ruby
which ruby
でrubyの場所を調べたところ、
/usr/bin/ruby
に存在している事がわかりました。$ [[ -d ~/.rbenv ]] && \ export PATH=${HOME}/.rbenv/bin:${PATH} && \ eval "$(rbenv init -)" $ which ruby /Users/XXXX/.rbenv/shims/rubyこのようにrubyの場所を変更します。
$ bundle install --path vendor/bundle最後に
bundle install
を行うことでエラーが解消されると思います。まとめ
$ [[ -d ~/.rbenv ]] && \ export PATH=${HOME}/.rbenv/bin:${PATH} && \ eval "$(rbenv init -)“ $ bundle install --path vendor/bundleこの2つで僕自身の環境では治せました。
それぞれ環境は違うと思うので、参考程度によろしくお願いいたします。質問や訂正等ございましたら、コメントの方でお願いできればと思います。
最後まで読んでいただきありがとうございました。参考
cannot load such file -- nokogiri/nokogiri (LoadError) のエラーを解決するまで。 - Qiita
注意
この記事は、プログラミング初学者が書いており、内容に誤りがある場合がございます。
あしからずご了承願います。
また、誤りにお気付きの場合にはご指摘いただけると幸いです。
よろしくお願いいたします。
- 投稿日:2021-02-20T17:27:44+09:00
【Rails】アソシエーションで紐づいたレコードを自動保存
概要
中級者は知ってて当然なので、初心者向けです?
アソシエーションで関連付けられたモデルを保存する時に、片方のレコードに外部キーが設定されているせいで、「保存処理を2回に分けなきゃ」と思ったことはないですか?(保存するまでidが確定しないので)
そんなときどうするのというお話です
※ 自分もかつて良くないコードを書いていたので、同じような初心者の参考になってもらえれば幸いです
具体例
例えば本のモデル(Book)と著者のモデル(Author)があると想定します
(book has_many authors
の関係)Bookモデル?
カラム 型 補足 id integer title string Authorモデル
カラム 型 補足 id integer book_id integer 外部キー name string このとき初心者がやりがちなのが以下の書き方
books_controller# createアクション book = Book.new(book_params) if book.save author = Author.new(book_id: book.id, name: author_params[:name]) if author.save # 保存後の処理 else # 失敗時の処理 end else # 失敗時の処理 end # book_params, author_paramsの定義は省略してますこれだと以下のようにデメリットが大きいです
- if文の階層が深くなる
- bookだけ保存されてauthorが保存されない場合が出てしまう
早期リターンやtransactionでこれらを回避することもできますが、わざわざそんな面倒なことをしなくて済む方法があるのです✨(以下)
books_controller# createアクション book = Book.new(book_params) author = book.build_author(author_params) return ['保存成功時の処理'] if book.save # 失敗時の処理この場合
book
の保存が成功した場合はauthor
の保存も保証してくれます(片方だけ保存されることはない)当然外部キーは関連付けられて保存されます
すっきりしていて見やすく、ファットコントローラ対策にもなります?
※ 早期リターンでリファクタもしてますモデルの関係性が、
belongs_to
とhas_many
とで書き方が変わるので注意が必要です(以下参照)
belongs_to
で関連付けられたモデルのbuildbook.build_authorhas_oneでの関連付けもこちらになります
has_many
で関連付けられたモデルのbuildauthor.books.build
1つだけ紐づくモデル
=>build_[モデル名の単数形]
複数紐づくモデル
=>[モデル名の複数形].build
と覚えとけば良さそうです?
(build_複数形
にするとインスタンスが複数buildされるイメージがつくからこのように分けたんですかね?)参考
- 投稿日:2021-02-20T16:27:46+09:00
rspecのテストでFactorybotが代入されなかった!?
WHY
rspecでテストコードの記述中、Factorybotで二つの変数を定義しようとしたところ、片方は代入されるのに、片方はされなかったことが起きたのでアウトプットしていきます。
問題
今回はテストコードを記述し、いざ実行!とするとこのようなエラー文がずらり、、、
対処
最近エラーを解除するのがとても楽しくなってきた自分ですが、とりあえず最初に目が止まったのは
「 Failure/Error: user = FactoryBot.create(:user)」
というエラー、
まぁ調べるまでもなくuserに入っていないという意味でしょう、、しかし、コードをみてみると、before do item = FactoryBot.create(:item) user = FactoryBot.create(:user) @sample = FactoryBot.build(:sample, user_id: user.id, item_id: item.id) end記述は上のitemと同じ、記述は間違っていない、、、となるとFactoryBot内がおかしいのか?とおもいましたが、
UserのFactoryBotは他のspecファイルでも使用しており、そこでは問題なく動作している、、、続いてエラー文の下の方をみてみると
「Failure/Error: _query(sql, @query_options.merge(options))」
という文字が、調べてみるとテストではたまに起きて、変数が代入しきる前にテストが実行されたりすることで起こるのだそう、、、
解決策としてはsleepというものを使う。
なので書いてみたbefore do item = FactoryBot.create(:item) user = FactoryBot.create(:user) @sample = FactoryBot.build(:sample, user_id: user.id, item_id: item.id) sleep(1) endこれでテストは1秒ごとに実行される。
しかしエラーは治らなかった、となればやっぱり代入がされない何かの理由がある!!
ということで次に目が行ったのは
「Validation failed: Email has already been taken」という文字直訳すると「メールはすでに使われている」というもの、
deviseを使っているので一意性があるのでしっかりバリデーションが仕事してくれています!解決
ということでFactorybotをみにいくと、
FactoryBot.define do factory :user do nickname { 'Test' } email { 'test@test' } password { 'test111' } password_confirmation { password } end endこのEmailに注目!
一意性のある値をテストするときはFakerを指定しなければならないのでemailの値を修正します!!email { Faker::Internet.free_email }その後テストはエラーなく無事解決しました!!
なお、「Failure/Error: _query(sql, @query_options.merge(options))」に関してはその後も出たので、
sleepはそのままにしています。
- 投稿日:2021-02-20T14:44:09+09:00
【AWS】デプロイ後にadminユーザーを追加する方法〜seedsファイルの実行〜
なんの話し?
AWSにデプロイした後にadminユーザーを追加する方法がわからなくて悩んだ結果の話しです。
開発環境ではseedsファイルにadmin: true
の記述をしていた。awsにデプロイした後にadminユーザーを追加したい
などで検索するとIAMアカウント関連の結果ばかり出てきてしまい、なかなか欲しい情報にたどり着けない。
そもそもseedsを追加した時のコマンドは開発環境で下記のように実行していた。開発環境のとき
% rails db:seed
そしてHerokuにデプロイした時にも同じことで悩み、実行したコマンドがこちら。
Herokuにデプロイしたとき
# アプリケーションのディレクトリで実行 % heroku run rails db:seedEC2のリポジトリでRailsを起動するときのコマンドを見ていたら、
「rails~
コマンドを使えれば追加できるのではないか?」と考え、実行してみた。AWSにデプロイしたとき
# EC2のリポジトリ内で実行 $ rails db:seed RAILS_ENV=productionこれでadminユーザーが追加された。
- 投稿日:2021-02-20T14:27:30+09:00
Rubyで月の日数を当てるプログラムを作ってみた
はじめに
私は、勉強のアウトプットとしてミニアプリをつくったりします。今回は、少し複雑な条件分岐を用いて閏年を当てるプログラムを書きました。備忘録として残りしたいと思いますので宜しくお願いします。
閏年になる場合を加味する
Googleぐぐるとトップに出てきますが、
①西暦年が4で割り切れる年は閏年
②ただし、西暦年が100で割り切れる年は平年
③ただし、西暦年が400で割り切れる年は閏年
とこの三つの条件分岐があるみたいです!さて早速、プログラミングを組んでいきます。
早速コードを書きます!
2月の日付のみ条件分岐にかけます。
理由としては、2月だけ日付の変動があるからです。def get_days(year, month) month_days = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31] # month_daysに予め配列で1~12月までの日数を入れておきます。 if month == 2 #2月を選んだ場合のみ、条件分岐にかけます。 if year % 4 == 0 #4で割り切れる場合は、さらに条件分岐にかけます。 if year % 100 == 0 && year % 400 != 0 #100で割り切れて、400で割り切れない場合の条件分岐です。 days = 28 else days = 29 end else days = 28 end else days = month_days[month - 1] end return days end puts "年を入力してください:" year = gets.to_i puts "月を入力してください:" month = gets.to_i days = get_days(year, month) puts "#{year}年#{month}月は#{days}日間あります"完成しました!
Javaでも作ってみた
しかし、今のJavaの知識では同じプログラムは作れず。
Googleの記事に上がっていたコードを参考にしました。public class LeapYear1 { public static void main(String[] args) { int year = 2020; boolean check = false; if (year % 4 == 0) { if ((year % 100 ) == 0) { if ((year % 400 ) == 0) { check = true; //閏年 } }else { check = true; //閏年 } } System.out.println(check ? "閏年です。" : "閏年ではありません。"); } }閏年の判定ができるプログラムになりました。
最後に
Rubyだけではなく、Javaでもプログラムが組めるように徐々にやっていきたいなと思います。
ここまで読んでいただきありがとうございました!
- 投稿日:2021-02-20T14:01:06+09:00
【Rails】【nested_form】追加された要素自体のIDを取得する方法
- 投稿日:2021-02-20T13:30:56+09:00
【Rails】ActiveRecord::ConnectionNotEstablished を解消する
1.はじめに
railsでアプリを作成し、サーバーを立ち上げ
rails s
を行い、http://localhost:3000/XX
にアクセスしました。
すると、ActiveRecord::ConnectionNotEstablished
と表示されました。2.使用環境
- mac.os バージョン10.15.6
- Ruby 2.6.6
- Rails 6.0.3.5
- psql (PostgreSQL) 12.6
3.実際のエラー
4.試したこと
4.1 データベースの確認
error.rb# 利用可能な全てのデータベースを一覧表示する hogehoge@hogenoAir sample_app % psql -l psql: error: 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"?4.2 postmaster.pidの削除
hogehoge@hogenoAir sample_app % rm /usr/local/var/postgres/postmaster.pidこちらを試すと、うまくいきました。
補足 /usr/の場所
macの場合、Finderの移動タブから、
フォルダへ移動
を選択し、/usr/
と入力すると表示されます。5.まとめ
今回はリンクの5番に近い状況で、
① パソコンがフリーズ
② 全て保存・終了して再起動
③ 表題のエラーが表示される ...という流れでした。②で全て終了していたはずが、うまく終了されなかったようです。
傷がついてしまったpostmaster.pid
を削除することで、解決できました。6.参考リンク
1:PostgreSQL 9.1.5文書
2.Postgresqlに接続できなくなった時
3.Postgres could not connect to server
4.【Mac】Finderから /usr / local ディレクトリを参照する
5.Mac+HomebrewでPostgreSQLが起動しない場合の対応7.最後に
記事の感想や意見、ご指摘等あれば伝えていただけるとありがたいです。
読んでいただき、ありがとうございました。
- 投稿日:2021-02-20T11:36:07+09:00
|= or equal記法について
- 投稿日:2021-02-20T10:40:51+09:00
【Rails】特定のカラムのオプションだけを変更したい
Rails6.0.0でアプリを作っていて、既に作成済みのテーブルのカラムにオプションの制約をつけ忘れていた。
なので、特定のカラムのオプションだけを追加で設定する方法をまとめる。現状
現状のマイグレーションファイルは以下のように「null:false」オプションを付け忘れているカラムがある。
class CreateItems < ActiveRecord::Migration[6.0] def change create_table :items do |t| t.string :name t.text :explain t.integer :price t.references :user, null: false, foreign_key: true t.integer :category_id, null: false t.integer :item_status_id, null: false t.integer :shipping_fee_id, null: false t.integer :prefecture_id, null: false t.integer :delivery_id, null: false t.timestamps end end end手順
①新しいマイグレーションファイルを作る。
「rails g migration ChangeColumnOfItems」とコマンドを打つ(アッパーキャメル)。
コマンドの意味は「Itemsテーブルのカラムを変更せよ」という感じ。terashimatakaya@MacBook-Air furima-34501 % rails g migration ChangeColumnOfItems Running via Spring preloader in process 8220 invoke active_record create db/migrate/20210220012237_change_column_of_items.rb②マイグレーションファイルを自分で修正する。
「Railsガイドv6.1」のマイグレーションの章を参考に、以下のように記述した。
意味としては、「itemsテーブルのnameカラムにnull:falseのオプションを追加してね」という感じ。class ChangeColumnOfItems < ActiveRecord::Migration[6.0] def change change_column_null :items, :name, false change_column_null :items, :explain, false change_column_null :items, :price, false end end③マイグレーションを実行
「rails db:migrate」を実行。
- 投稿日:2021-02-20T04:37:25+09:00
sqlcommenterをRuby on Railsのデモアプリケーションで動かしてみる
Googleが提供しているオープンソースのツールで、ORMが生成するSQLの調査を容易にしてくれるらしいので使ってみました。
具体的にはログなどに、コメントが含まれるようになり、ORMが生成したSQL文はどのコードで生成されたものかを知ることができるみたいです。今回Rails APIモードのデモアプリケーションが用意されているので、どのようなコメントが出力されるか動かして確認してみます。
google/sqlcommenter | GitHubsqlcommenterが対応する言語、フレームワーク、DBは以下
言語
- Ruby
- Python
- JavaScript
- Node.js
- Java
フレームワーク
- Ruby on Rails
- Flask
- Django
- Express
- Knex.js
- etc...etc
DB
- MySQL
- MariaDB
- PostgreSQL
- SQLite
- Google Cloud SQL
デモRailsアプリケーションで試してみる
google/sqlcommenter | Rails demo
RailsのAPIデモアプリケーションでとりあえずsqlcommenterがどんなものかを体験ができるみたいです。
ただ、sqlcommenter_railsはrubygemsではリリースされていないようなので、上記のREADMEの手順に沿って環境構築すればとりあえずは使うことができます。APIは以下の2つが用意されています。
- Get /posts
- POST /posts
APIを叩くcurl
bashcurl localhost:3000/postsbashcurl -X POST localhost:3000/posts -d 'title=my-post'POST /postsを実行
bashcurl -X POST localhost:3000/posts -d 'title=my-post'INSERT INTO "posts" ("title", "created_at", "updated_at") VALUES (?, ?, ?) /*action='create',application='SqlcommenterRailsDemo',controller='posts',db_driver='ActiveRecord::ConnectionAdapters::SQLite3Adapter', framework='rails_v6.0.3.5',route='/posts', traceparent='00-e71c784d7151a939ef4e8d886a326456-82ad00a116eaa038-01'*/初期設定では以下の情報が出力されるようです。
- action
- application
- controller
- db_driver
- framework
- route
- traceparent
設定を追加することで、出力する情報の変更 / 追加が可能です。
bashmkdir config/initializers touch config/initializers/marginalia.rb vim config/initializers/marginalia.rb # 追加 Marginalia::Comment.components = [ :action, :application, :controller_with_namespace, :hostname, :job, :line] ~ ~ ~Rails serverを再起動して再度curlを実行すると先ほど追加した情報が表示されます
/*action='create',application='SqlcommenterRailsDemo',controller_with_namespace='PostsController', hostname='xxxx',line='/app/controllers/posts_controller.rb:25:in `create\''*/GET /postsを実行
次にpostの一覧を取得してみます。
bashcurl localhost:3000/postsSELECT "posts".* FROM "posts" /*action='index',application='SqlcommenterRailsDemo',controller_with_namespace='PostsController', hostname='xxxx',line='/app/controllers/posts_controller.rb:19:in `index\''*/先程のPOSTと同じくactionや実際にSQL文が生成されたコードの位置を出力してくれました。
posts_controller.rbは以下のようになっています。
app/controllers/posts_controller.rb#... 17 class PostsController < ApplicationController 18 def index 19 render json: Post.all 20 end 21 22 def create 23 title = params[:title].to_s.strip 24 head :bad_request if title.empty? 25 render json: Post.create!(title: title) 26 end 27 end参考
- 投稿日:2021-02-20T04:35:32+09:00
N+1問題の発見方法と解決方法(備忘録)
概要
N+1問題とは必要以上にSQL文が発行されてパフォーマンスが低下する問題です。
N+1問題の解決方法
便利なgem bullet(N+1を検出してくれる)の導入
最後に初学者のただの備忘録です。
環境
- Ruby: 2.6.6
- Rails: 6.0.3.5
実装例
例えば、パラメータのcategory_nameがDBに存在するかどうかによって
@ideasに代入される値が変わる処理があるとします。app/controllers/ideas_controller.rbdef index category = Category.find_by(name: params[:category_name]) if category.present? @ideas = category.ideas render formats: :json else @ideas = Idea.all render formats: :json end endcategoryとideaの関係は
app/models/category.rbhas_many :ideas, dependent: :destroyapp/models/idea.rbbelongs_to :categoryN+1問題が発生してない場合
category.present?がtrueの場合は@ideasにcategory.ideasが代入されて
レンダリングされる。
そのときのログを一応確認(わかりやすいように一部ログをはしょっています)
CategoryとIdeaが1回ずつ読み込まれてます。N+1問題は発生していません。ターミナルCategory Load (0.5ms) SELECT `categories`.* FROM `categories` WHERE `categories`.`name` = 'hoge1' LIMIT 1 ↳ app/controllers/api/v1/ideas_controller.rb:13:in `index' Idea Load (0.4ms) SELECT `ideas`.* FROM `ideas` WHERE `ideas`.`category_id` = 1 ↳ app/views/api/v1/ideas/index.json.jbuilder:2N+1問題が発生している場合
category.present?がfalseの場合、@ideasにIdea.allが代入されてレンダリングされる。
ログを確認するとCategory Loadが何回も...
これがN+1問題です。ターミナルIdea Load (0.5ms) SELECT `ideas`.* FROM `ideas` ↳ app/views/api/v1/ideas/index.json.jbuilder:2 Category Load (0.3ms) ↳ app/models/idea.rb:4:in category_name Category Load (0.3ms) ↳ app/models/idea.rb:4:in category_name CACHE Category Load (0.0ms) ↳ app/models/idea.rb:4:in category_name Category Load (0.3ms) ↳ app/models/idea.rb:4:in category_name Category Load (0.4ms) ↳ app/models/idea.rb:4:in category_name Category Load (0.3ms) ↳ app/models/idea.rb:4:in category_name CACHE Category Load (0.0ms) ↳ app/models/idea.rb:4:in category_name Category Load (0.4ms) ↳ app/models/idea.rb:4:in category_name CACHE Category Load (0.0ms) ↳ app/models/idea.rb:4:in category_name Category Load (0.4ms) ↳ app/models/idea.rb:4:in category_nameN+1問題を解決する方法
結論から言いますとincludes、preload、eager_loadのいずれかを使用すると解決できます。
他の記事ではよくincludesで解決してますが、結局のところincludesは条件によって
preloadしたりeager_loadしたりする。preloadはエラー(例外)を発生させることもあるので
eager_loadを使用するのが無難だと思います。詳しく知りたい方は
下記の記事を読んでみてください。ActiveRecordのjoinsとpreloadとincludesとeager_loadの違い
では、解決していきます。
eager_load (LEFT OUTER JOIN)の場合
app/controllers/ideas_controller.rb# def index # category = Category.find_by(name: params[:category_name]) # if category.present? # @ideas = category.ideas # render formats: :json # else @ideas = Idea.eager_load(:category) # もとはIdea.all # render formats: :json # end # endターミナルCategory Load (0.6ms) SELECT `categories`.* FROM `categories` WHERE `categories`.`name` = 'hoge1ddd' LIMIT 1 ↳ app/controllers/api/v1/ideas_controller.rb:13:in `index' Rendering api/v1/ideas/index.json.jbuilder SQL (0.5ms) SELECT `ideas`.`id` AS t0_r0, `ideas`.`category_id` AS t0_r1, `ideas`.`body` AS t0_r2, `ideas`.`created_at` AS t0_r3, `ideas`.`updated_at` AS t0_r4, `categories`.`id` AS t1_r0, `categories`.`name` AS t1_r1, `categories`.`created_at` AS t1_r2, `categories`.`updated_at` AS t1_r3 FROM `ideas` LEFT OUTER JOIN `categories` ON `categories`.`id` = `ideas`.`category_id` ↳ app/views/api/v1/ideas/index.json.jbuilder:2何回もCategoryがLoadされていたSQL文が発行されなくなりました。
preloadの場合
app/controllers/ideas_controller.rb# def index # category = Category.find_by(name: params[:category_name]) # if category.present? # @ideas = category.ideas # render formats: :json # else @ideas = Idea.preload(:category) # もとはIdea.all # render formats: :json # end # endターミナルCategory Load (0.4ms) SELECT `categories`.* FROM `categories` WHERE `categories`.`name` = 'hoge1ddd' LIMIT 1 ↳ app/controllers/api/v1/ideas_controller.rb:13:in `index' Rendering api/v1/ideas/index.json.jbuilder Idea Load (0.5ms) SELECT `ideas`.* FROM `ideas` ↳ app/views/api/v1/ideas/index.json.jbuilder:2 Category Load (0.4ms) SELECT `categories`.* FROM `categories` WHERE `categories`.`id` IN (1, 2, 3, 4, 5, 6, 7) ↳ app/views/api/v1/ideas/index.json.jbuilder:2includesの場合
app/controllers/ideas_controller.rb# def index # category = Category.find_by(name: params[:category_name]) # if category.present? # @ideas = category.ideas # render formats: :json # else @ideas = Idea.includes(:category) # もとはIdea.all # render formats: :json # end # endターミナルCategory Load (0.3ms) SELECT `categories`.* FROM `categories` WHERE `categories`.`name` = 'hoge1ddd' LIMIT 1 ↳ app/controllers/api/v1/ideas_controller.rb:13:in `index' Rendering api/v1/ideas/index.json.jbuilder Idea Load (0.4ms) SELECT `ideas`.* FROM `ideas` ↳ app/views/api/v1/ideas/index.json.jbuilder:2 Category Load (0.2ms) SELECT `categories`.* FROM `categories` WHERE `categories`.`id` IN (1, 2, 3, 4, 5, 6, 7) ↳ app/views/api/v1/ideas/index.json.jbuilder:2おまけ
Ideaモデルに複数の関連付けがある場合は下記のように書くことができます。
app/controllers/ideas_controller.rb# def index # category = Category.find_by(name: params[:category_name]) # if category.present? # @ideas = category.ideas # render formats: :json # else @ideas = Idea.eager_load(:category, :hoge, :huga) # render formats: :json # end # endgem "bullet"の導入方法
N+1問題を検出してくれるgemです。
通常はターミナルに出ますが、jquery等でカスタムもできます。
今回それは割愛Gemfilegem "bullet"bundleだけでも可能
ターミナル$ bundle installyでconfig/environments/development.rbを自動作成
ターミナル$ bundle exec rails g bullet:install Would you like to enable bullet in test environment? (y/n)N+1問題が発生するとターミナルに下記のようにでます。(一部省略)
IdeasテーブルにCategoriesテーブルをincludesしてねということターミナルuser: shu GET /api/v1/ideas?category_name= USE eager loading detected Idea => [:category] Add to your query: .includes([:category])以上。
間違っている等ありましたらご指摘頂けると幸いです。
最後に
N+1問題の解決方法自体はそんなに難しいコードを書くわけではないですがSQLを読んで
なにが起こっているのかしっかり理解することが大切だと思います。
(解決できたらいいやーでは逆に遠回りになることを身を持って感じております。)
- 投稿日:2021-02-20T01:16:51+09:00
【Rails】 フラッシュメッセージ使い分け
はじめに
お恥ずかしながら、私は最近までフラッシュメッセージってflash[:notice] = ⚪︎⚪︎と書いておけばいいんだろうくらいの認識しかありませんでした。ポートフォリオ作成時にフラッシュメッセージの使い分けの方法があることを知り、少し理解を深めることができたので、自身の備忘録として残しておきたいと思います。
フラッシュメッセージって何?
何かの処理を行った後に画面に表示されるメッセージのことを指します。
例) ● ログイン時
「ログインに成功しました」
● 記事の投稿時
「記事の投稿に成功しました」
見本
フラッシュメッセージの種類
● flash
次のリクエストまで表示させることができる。
= redirect_toの際に使用する。
※render時に使用すると次のリクエスト時までメッセージが画面に表示され続けてしまうので、不適切になります。● flash.now
現在のリクエストまでしか表示できない。
= renderの際に使用する。
● notice
通知を出す時。主に成功した時のメッセージなど。
● alert
警告の通知を出す時。何かの動作に失敗時など。
コントローラー
今回は、投稿した際の保存成功時と失敗時にメッセージが表示されるようにしています。
books_contoroller.rbdef create @book = Book.new(book_params) @book.user_id = current_user.id if @book.save redirect_to books_path, notice: = "投稿に成功しました" else flash.now[:alert] = "投稿に失敗しました" render :new end end # 2行に分けて記述することも可能 # redirect_to books_path # flash[:notice] = "投稿に成功しました"ビュー
viewにもフラッシュメッセージが表示されるように記述を加えます。
※フラッシュメッセージを表示させるタイミングは何度もあるかと思いますので、部分テンプレートに書き出し、呼び出す形にしています。books/index.html.erb<%= render 'layout/flash' %> <% @books.each do |book| %> <%= book.user.name %> <%= book.title %> <%= book.content %> <% end %>layout/_flash.html.erb<% if notice %> <%= notice %> <% elsif alert %> <%= alert %> <% end %>終わり
今回は以上になります。
私自身もプログラミング初心者ですが、同じ様な立場の方に少しでも参考になれば幸いです。
また、もし内容に誤りなどがございましたら、ご指摘いただけますと幸いです。
- 投稿日:2021-02-20T01:00:40+09:00
[Ruby on Rails] CSSが反応してくれない時の対処法
自身の備忘録を書いて行きます。
CSSを書いても全く反応してくれないことがありました。
なんでや?と思い調べて行くと、ちゃんと動いてくれるようになりました。それの解決策を書いて行きます。
解決策
layouts/application.html.erb<%= stylesheet_link_tag 'application', media: 'all'%>上記の記述をすることでCSSを読みこむようになりました。
こちらはCSSの類を全て読みこんでくれる記述らしいです。
その他に
ユーザー管理機能(devise使用の場合)の
ログイン等の配置を動かす場合はconfig/initializers/devise.rbconfig.scoped_views = true上記の記述は元々、247行目でコメントアウトになっている
config.scoped_views = false
こういった記述になっている。それをコメントアウトを外してtrueにすればいいらしい。
実際、両方やってたら問題なく動いているので、
今の所は大丈夫そう。
- 投稿日:2021-02-20T00:32:20+09:00
Rails ERDのススメ
About Rails ERD?
Railsのテーブル情報を自動生成するためのgem
https://github.com/voormedia/rails-erd
ER図をpdfで出力することができる。Getting started ?
for mac
brew intall graphviz
gemfilegem install ‘rails-erd’, group: :development
- 設定でmigrationの度に自動生成することも可能
Pros and cons
?
クライアント・新入メンバーへの説明するのに便利
?
関連にもよるがテーブル数が50超えてくるとごちゃごちゃしてすごく見づらい
内部の開発に関しては、モデル数20以下の場合annotateで十分
ある程度の規模のサービスの場合、LucidChartやdraw.ioで作図するするのがオススメ
- 投稿日:2021-02-20T00:26:27+09:00
Docker,CircleCI,AWS,Railsでポートフォリオを作成
前書き
就職活動用のポートフォリオをDocker,CircleCI,AWS(ECS)を用いてWebアプリケーションを作成しました。
バックエンドにRuby on Railsを用いました。
今回は作成したポートフォリオの機能、参考記事などを紹介したいと思います。概要と作成背景
今回作成したアプリはスイーツのデリバリーに特化したECサイトです。
- ケーキ屋のアルバイト経験からお店の業務改善をしたい
- 手軽にお店のスイーツを食べたい
- 店舗で販売しているようなスイーツを配達するサービスが存在しない(自分調べ)
上記の理由により飲食店にもユーザーにもメリットのあるサービスを作成しようと思いました。
アプリのURL: http://sweetsdeli.com
GitHubのURL: https://github.com/sekine617/sweetsdeli
画面イメージ紹介
トップページ
新着商品、人気商品などを表示
人気商品はユーザーの購入履歴から購入数が多い商品を表示しています。
商品一覧ページ
商品詳細ページ
こちらでは商品をカートに入れる、お気に入り登録、商品のレビュー投稿などができます。
マイページ
マイページではプロフィール編集、お気に入り、購入履歴、投稿したレビューを閲覧できます。
ショッピングカート
こちらではカートに入れた商品の確認、個数の変更、カートから削除などができます。
購入画面
カートに入れた商品から合計金額を確認し、クレジットカードによる決済が可能です。実際に決済する場合はpay.jpのてすとカードを使用してください。
このようにカード情報の入力フォームがモーダルウィンドウで出てきます。
使用言語
- フロントエンド
- jQuery
- HTML
- CSS/Sass
- Bootstrap
- バックエンド
- Ruby on Rails
- Ruby
- PAY.JP(外部API)
- インフラ
- Docker/docker-compose
- CircleCI
- nginx
- mysql
- AWS(ECS, ALB, S3, RDS, Route53, ECR, VPC, IAM)
インフラ構成図
開発環境
機能一覧
- ユーザー関連(devise)
- 登録機能
- プロフィール編集機能
- ログイン・ログアウト機能
- 決済機能(PAY.JP API)
- 人気商品表示機能
- タグ機能
- 商品登録機能
- 画像アップロード機能(AWS S3バケット, carrierwave)
- お気に入り機能(非同期処理, jQuery)
- フラッシュメッセージ表示機能
- レビュー投稿機能
- カート関連
- カート登録機能
- カート編集機能
- 住所自動入力機能(jQuery)
- 商品名検索機能
- カテゴリー検索機能
- ページネーション機能(kaminari)
データベース設計
テーブル説明
テーブル名 説明 users ユーザー情報 orders 注文管理(受け取り日時など) orders_products 注文商品管理 products 商品情報 reviews 商品に対するレビューを管理 likes 商品へのお気に入り情報 address ユーザーの住所 cart_items cartsとproductsの中間テーブル shops ショップ情報 carts カート追加した商品情報一時的に保存 product_tag_relations productsとtagsの中間テーブル tags 商品のカテゴリ情報 ポイントはproductsテーブルのquantity_per_dayで、1日の提供数を指定し注文数が1日の提供数を上回らないようにしました。
また注文時に受け取り日時を指定し、各店舗ごと、日にちごとに管理が可能です。苦労した点
CircleCIでAWSへの自動デプロイ
CircleCIを用いて開発環境のDockerイメージをECRにpushし、ECSのタスク定義を更新してデプロイをしましたが、config.ymlの設定でのエラーに悩まされました。
またAWSの各設定にもかなり悩まされ、インフラの知識がないことで時間が結構かかりました。credentials.ymlでのpay.jpなどのアクセスキー管理でなかなかうまく行かずインデントの重要性がよくわかりました。
参考記事
Railsでのテストを参考にしました。
【Rails】はじめてのRSpec!テストコードを書こう!deviseのログイン機能を参考にしました
【Rails】ログイン機能を実装する
- 投稿日:2021-02-20T00:04:23+09:00
git push -u origin mainでpushされずerrorになる
rails tutorialのversion 6.0の1章でgitの扱い方を学びながら進めていたがgit push -u origin mainをしたら下記のようなエラーに遭遇した
terminal
error: src refspec main does not match any error: failed to push some refs to '自分のgithubアカウント'原因
2020/10月からgithubはレポジトリ名をmasterからmainに変更したためmainでpushしてもレポジトリ名が違うためerrorになるとのこと
次のようにgit branchで調べるとその通りだった
% git branch * masterので次のようにブランチを変えて解決
% git branch -M main % git branch * mainまだまだ初学者なのだと実感させられる
参考になったURL