railsの基礎まとめ

# 前提
書籍アプリみたいなのを前提に書いています
### railsの更新系

**createメソッド**
値の設定、DBへの保存までを一気に行うメソッド

```
irb(main):014:0> Book.create(
irb(main):015:1*  name: "キングダム",
irb(main):016:1*  published_on: Time.parse("20201024").ago(2.months),
irb(main):017:1*  price: 498,
irb(main):018:1*  publisher: Publisher.find(1),
irb(main):019:1* )
```

上記を分解して記述する方法

**newメソッド**
モデルオブジェクトの作成
createメソッドとは違い、保存はされていない
saveメソッドを使い保存を行う

```
irb(main):001:0> book = Book.new
=> #<Book id: nil, name: nil, published_on: nil, price: nil, created_at: nil, updated_at: nil, publisher_id: nil>
irb(main):002:0> book.name = "キングダム"
=> "キングダム"
irb(main):003:0> book.published_on = Time.parse("20201024").ago(2.months)
=> 2020-08-24 00:00:00 +0900
irb(main):004:0> book.price = 498
=> 498
irb(main):005:0> book.publisher = Publisher.find(1)
=> "飛信隊"
irb(main):006:0> book.save
=> true
```

既存のデータを更新する際は
findメソッドなどでレコードを取得
→更新して再度saveメソッドを呼び出す

既存のデータを削除する際は
レコードを取得
→destroyメソッドを呼び出す
saveメソッドは不要

### バリデーション

アプリケーションの要件時に、一定のルールでデータのチェックを行いたい場面が必ずある

* 本の名前は必ず入れたい
* 本の名前は20文字までに
* 価格は0円以上で

上記の要件の時↓
~~~md:app/models/book.rb
class Book < ApplicationRecord
  略

  validates :name, presence: true
  validates :namae, length: { maximum: 25 }
  validates :price, numericality: { greater_than_or_equal_to: 0 }
end
~~~

実際に本の名前を30文字でデータを保存しようとする
```
irb(main):004:0> book = Book.new
=> #<Book id: nil, name: nil, published_on: nil, price: nil, created_at: nil, updated_at: nil, publisher_id: nil>
irb(main):005:0> book.name = "a" * 30
=> "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
irb(main):006:0> book.price = 1000
=> 1000
irb(main):007:0> book.publisher = Publisher.find(1)
=> "飛信隊"
rb(main):008:0> book.save
=> false
```

saveメソッドの戻り値がfalseになり、レコードの保存に失敗している

#### 保存せずにバリデーションだけを行いたいとき

saveメソッドの代わりにvalid?メソッドを使用する
```
rb(main):008:0> book.save
↓
rb(main):008:0> book.valid?
```


保存しようとして失敗した際にどのようなエラーが起こったのか、どのフィールドで発生したのか
という情報はインスタンスに記録される

**上記のインスタンスとは何?**
インスタンスとは、クラスを元に作られた具体的な個別データのこと

**ではクラスとは何？**
クラスとは、個別のデータ（値）の生成するための設計図・仕様のこと。

その情報は**errorsメソッド**で取得することができる。

今回の場合は、book.errorsとすることで取得可能
また、book.errors.full_messagesと記述することで、読みやすい形にしてくれる

### バリデーションと「!」付きのメソッド
保存メソッド(save、create、update、、、)に!がついている時の違い
* 「!」を伴わないメソッドはバリデーション失敗時には例外を起こさない
* 「!」を伴うメソッドはバリデーション失敗時には例外(ActiveRecord::RecordInvalid)が起こる

### 独自のバリデーション作成
少し、複雑なバリデーションを行ったり、メッセージをカスタマイズしたい場合
validateブロックを利用する。

下記が例になります
本の名前に"test"という文字列が含まれていたらバリデーションに引っかかるようにしている
また、errorsに何かしらの値が入っていればバリデーション失敗であると判定されるので、
地震でバリデーションの設定をする際は、引っかかった場合にerrorsにエラーメッセージを付与する

~~~md:app/models/book.rb
class Book < ApplicationRecord
 略
  validates :price, numericality: { greater_than_or_equal_to: 0 }
  validate do |book|
    if book.name.include?("test")
      book.errors[:name] << "使用できない文字が含まれています"
    end
  end

end
~~~


### DBの中身を見てみるコマンド

```
rails db
```

出力結果をわかりやすくするためには
```
sqlite> .mode line
```
~~~md:通常の出力ver
sqlite> select * from book_authors;
1|1|3|2022-07-28 05:50:05.854258|2022-07-28 05:50:05.854258
2|2|3|2022-07-28 05:50:15.770756|2022-07-28 05:50:15.770756
3|1|4|2022-07-28 05:50:53.570274|2022-07-28 05:50:53.570274
~~~

~~~md:分かりやすい出力ver
sqlite> select * from book_authors;
        id = 1
   book_id = 1
 author_id = 3
created_at = 2022-07-28 05:50:05.854258
updated_at = 2022-07-28 05:50:05.854258
~~~