例外処理
例外、例外処理
例外とは、事前に想定される、期待と違う挙動。想定されるエラー。(コーディングしてて出くわすエラーとは少し違う)
Exceptionクラスを承継したNoMethodErrorとかSyntaxError。
activerecord-import (Gem)
importメソッドが使えるようになる。
配列 -> import -> 一気にレコード作成
データベースにアクセスする回数を減らせる。
(db/seeds.rb) users = [] 10000.times do |i| # usersに10000件新規ユーザーの情報を格納する users << User.new(name: "dummy-#{i+1}", ticket_count: 0) end # importメソッドの引数に配列を渡して、まとめてレコードを作成する User.import users
reils db:seed
db/seeds.rbに基づいてレコードを作成
Rakeレイクタスク
タスクを実行するためのツール。タスク = コマンド?
(ターミナル)
# タスクファイル作成
% rails g task タスクファイル名
(lib/tasks/タスクファイル名.rake) namespace :ここにグループ名を記述する do desc "ここに処理の説明を記述する" task タスク名: :environment do ここに実際のタスクを記述する end end
# 実行コマンド
rails namespaceの名前:taskの名前
environmentエンバイロメントメソッド
タスクの処理をアプリケーション(Rails)環境に依存させる。
Rails上のUserモデルとかを扱えるようになる。
incrementインクリメントメソッド
User.find_each do |user| # tichket_countカラムの値を10増やす user.increment!(:ticket_count, 10) end
beginビギン
例外処理を想定している箇所を囲う
rescueレスキュー
例外が起きたら実行される
繰り返し処理(each,time,while)の中に begin
,rescue
を書くとループが途中で止まらない。
User.find_each do |user| begin user.increment!(:ticket_count, 10) rescue => e #発生した例外を変数eに格納 # エラーをログに記録 Rails.logger.debug e.message end end
例外を発生させる !
save
, create
, destroy
=> true/false
save!
, create!
, destroy!
=> falseじゃなく例外
raiseレイズ
自分で例外を発生させて「不具合の原因となる箇所で例外を明示して、処理を止めたいとき」
raise 発生させたい例外クラス, 'エラーメッセージ'
例外クラス・・・NoMethodError, RuntimeError, SyntaxError, NameErrorなど
トランザクション transaction: 処理
個別に処理ではなく、一気に処理。 100か0か。
「途中まで処理ができて、例外以降の処理ができない」みたいな状態を避けれる。(商品の注文と支払いとか、セットじゃないと困るもの)
レスポンシブwebデザイン
テストコード #2
FactoryBot × 中間テーブル
(spec/factories/room_users.rb) # アソシエーションのみ定義 FactoryBot.define do factory :room_user do association :user association :room end end
(messages_spec.rb) # userとroomを自動で追加 @room_user = FactoryBot.create(:room_user) => <#RoomUser:0x0000000110b662f8 id: 2, room_id: 2, user_id: 4, created_at: Sat, 02 Sep 2023 09:10:04.633423000 JST +09:00, updated_at: Sat, 02 Sep 2023 09:10:04.633423000 JST +09:00>
(コンソール) pry(main)> Room.find(2) => [#<Room:0x0000000110ca1a50 id: 2, name: "New Jersey goblins", created_at: Sat, 02 Sep 2023 09:10:04.631154000 JST +09:00, updated_at: Sat, 02 Sep 2023 09:10:04.631154000 JST +09:00>,
Rails.root.joinレイルズ ルート ジョイン
# トップ階層〜Railsアプリ のパス pry(main)> Rails.root => #<Pathname:/Users/ユーザー名/projects/sample-app> # joinで後ろにパスを結合 pry(main)> Rails.root.join('public/images/test_image.png') => #<Pathname:/Users/ユーザー名/projects/sample-app/public/images/test_image.png>
attach_fileアタッチ ファイルメソッド
input要素[type: file]に、テスト用の画像を添付(アタッチ)できる。
# 引数(input要素のname属性, ファイルのパス) attach_file('message[image]', image_path) # 非表示(display:none;)のinput要素を表示 attach_file('message[image]', image_path, make_visible: true)
create_listクリエイトリスト
# FactoryBotを量産 FactoryBot.create_list(:message, 3, ) # オプションで、カラムの内容を指定できる。 # 外部キーも指定できる。 FactoryBot.create_list(:message, 1, content: 'hoge', room_id: @room_user.room.id)
ドットは3種類
- アソシエーションのドット
- メソッドのドット
- カラムをつなぐドッド
テストコード #1
テスト結果のログ表示
(.rspec) <!-- ログが詳細に表示される --> --format documentation
エラーメッセージを英語に
(spec/rails_helper.rb) I18n.locale = "en"
after アフターメソッド
文字通り、〜の後に動作させたい時
FactoryBot.define do factory :message do content {Faker::Lorem.sentence} # インスタンスがbuildされた後に after(:build) do |message| # 指定したパスのファイルを名前をつけて保存 # ioはinput/outputの略 # ファイルをフルパスにすると、他の環境では使えなくなるので注意 message.image.attach(io: File.open('public/images/test_image.png'), filename: 'test_image.png') end end end
attach
ファイルを紐づける。
外す時はpurge
by chatGPT
messageはアクティブレコードモデルのインスタンス。
imageはそのモデルに関連付けられたActive Storageアタッチメント名。アタッチメントとは、ファイルをモデルに関連付けて管理するための仕組み。
attached?
画像がattachできているか確認。
# 変数に格納 pry(main)> message = FactoryBot.create(:message) pry(main)> message.image.attached? => true
RSpecは外部ライブラリ
ライブラリの種類を学習してからだと、requireの意味がわかって少しおもしろ。
# 共通の設定とかメソッドを読み込むためのrequire require 'rails_helper'
(rails_helper内に、その下部ディレクトリを読み込む設定が書かれている。)
単体テストの基本
基本は、インスタンス生成とエクスペクテーション
rails g rspec:model user
先にFactoryBotのファイルを手作業で作ってるとconflictってなってる。なんかなるほど。
(conflict: 衝突)
(ターミナル) % rails g rspec:model user create spec/models/user_spec.rb invoke factory_bot conflict spec/factories/users.rb # 上書きしますか? Overwrite /Users/shigeshige/projects/chat-app/spec/factories/users.rb? (enter "h" for help) [Ynaqdhm]
([Ynaqdhm] : 返答方法) Y - yes, overwrite #上書する。 n - no, do not overwrite #上書きしない。 a - all, overwrite this and all others #全てを上書きする q - quit, abort #実行の中断をする d - diff, show the differences between the old and the new #ファイルを古いデータ、新しいデータで比較する? h - help, show this help #ヘルプを呼び出す m - merge, run merge tool #マージする
出典: (enter "h" for help) [Ynaqdhm]の対処方法 - Qiita
belongs_to :user の時に注意
外部キー(user_id)のバリデーションは不要!
class Message< ApplicationRecord belongs_to :user # ↑この時点で、':user_idの有無'というバリデーションはデフォルトで設定されている。 validates :user_id presence: true ←不要 # このバリデーションを設定した場合のエラーメッセージは、'User can’t be blank' # 設定しなかった場合は、'User must exist' end
click_on
click_on('hoge') # テキストリンク(a要素とか) or ボタン要素 をクリックしてくれる。 # テキストを検索 or value属性 を検索
英単語
invoke
in(上)とvocare(呼ぶ) -> 法令を発動する
- vocal: vocalis(声を出すこと) -> 声の
- vocation: 語源はvocatus(呼ばれる) -> 転職
- provoke: pro(前)とvocare(呼ぶ) -> 怒らせる
- revoke: re(後ろ)とvocare(呼ぶ) -> 取り消す
- advocate: ad(方向)とvocare(呼ぶ) -> 支持する
- convocation: con(一緒)とvocare(呼ぶ) -> 招集
- evoke: ex(外)とvocare(呼ぶ) -> 感情を引き起こす
参考
Ruby 深掘り #2
クラスの継承
親から子に引き継ぐ。
親クラス(スーパークラス)
共通する部分を記載
子クラス(サブクラス)
個別の情報を記載
class Chichi def initialize(eye_type, height) @eye_type = eye_type @height = height end def attitude puts "目は#{@eye_type}で、背は#{@height}" end end # ChichiからMusukoへ承継 # インスタンス変数とインスタンスメソッドが引き継がれる class Musuko < Chichi end chounan = Musuko.new("一重", "高い") chounan.attitude # => 目は一重で、背は高い
独自メソッドの定義
子クラス(Musuko)内にdef〜end
で定義したものは、その子クラス独自のメソッドとなる
オーバーライド
親クラスに対して、同名の子クラスを定義 => 上書き
上記の例で言えば、Musuko
内にattitude
メソッドを定義する
class Musuko < Chichi def attitude puts "目は#{@eye_type}で、背は#{@height}、長男" end end
Ruby 深掘り #1
caseケース文
条件分岐が多い時に使う。elseif的な。
case - when - else - end
if - elseif - else - end
whileワイル文
繰り返し構文
while 条件式 do # 条件式を満たす間は、ずっと繰り返す end
無限ループ
元はプログラミングの用語。
while true # 常にtrue -> 無限ループ end
大きな負荷がかかるので避けましょう
breakブレーク
繰り返し処理から強制脱出
ブロック
do〜end
のことをRubyではブロックと呼ぶ
|〜|
をブロック変数と呼ぶ。
each
とかtimes
はブロック自体(do〜endの処理
)を引数として受け取って(繰り返して)いる
{〜}
もブロック。do〜end
と同義。1行で収まるなら{ }
推奨。
yieldイールド
(application.html.erb
に各ビューファイルの内容を展開する時にも出てきた。)
ブロックごと渡すような時にも使えるらしい。
def hoge puts "hogehoge" yield # 渡されたブロックがyieldと取って代わる。 end hoge do puts "fugafuga" end # => hogehoge # => fugafuga
ブロック引数
&block
をつけると、ブロックを引数として渡せる。
call
で呼び出し。
# blockを引数として受け取るために &block def hoge(&block) puts "hogehoge" # callに引数"fugafuga"を渡して、ブロック引数を呼び出し。 block.call("fugafuga") end # hogeというメソッドに do~end のブロックを引数として渡す。 # textという変数に、fugafugaが代入されて呼び出される。 hoge do |text| puts text end # => hogehoge # => fugafuga