SuzuBlog

webのお勉強はじめたばかりの初心者。備忘録

Rails基礎 Active Recordの基本操作(メモ)

実行結果・実行されているSQLを確認するための自分用メモです。 作成~登録~更新~削除

新規オブジェクトの作成

#新規オブジェクトを作成
>> user = User.new(name: "Michael Hartl", email: "michael@example.com")
   (0.1ms)  begin transaction
=> #<User id: nil, name: "Michael Hartl", email: "michael@example.com", created_at: nil, updated_at: nil>

created_atupdated_atは登録日時、更新日時。このカラムとidは勝手に作ってくれる。 newしただけだと、created_atupdated_atnilであることが確認できる。

有効性のチェック 

#有効性のチェック(DBの存在チェックは行えない)
>> user.valid?
=> true

エラーがなければtrue、エラーが発生したらfalseが返却される。 登録前のチェック等に。 実行結果が逆になる.invalid?も存在する。  

オブジェクトの保存

#保存
>> user.save
   (0.1ms)  SAVEPOINT active_record_1
  User Create (3.9ms)  INSERT INTO "users" ("name", "email", "created_at", "updated_at") VALUES (?, ?, ?, ?)  [["name", "Michael Hartl"], ["email", "michael@example.com"], ["created_at", "2020-11-21 15:11:49.849711"], ["updated_at", "2020-11-21 15:11:49.849711"]]
   (0.1ms)  RELEASE SAVEPOINT active_record_1
=> true

INSERTが発行されていて、DBに保存されていることがわかる。また、先ほどはnilだったcreated_atupdated_atに値が入っていることを確認できる。 またSAVEPOINTが作成されているので、トランザクションが発行されていて、失敗した場合はロールバックしてくれるような感じがする(自分では未検証)  

情報取得

#各情報の参照
>> user
=> #<User id: 1, name: "Michael Hartl", email: "michael@example.com", created_at: "2020-11-21 15:11:49", updated_at: "2020-11-21 15:11:49">

>> user.name
=> "Michael Hartl"

>> user.email
=> "michael@example.com"

>> user.updated_at
=> Sat, 21 Nov 2020 15:11:49 UTC +00:00

上記のINSERTの時にはidは含まれていなかったが、ちゃんと値が入っている。ということは内部で勝手に自動採番してくれているらしい。  

createで生成と削除を同時に行う

#モデルの生成と保存を同時に行う
>> User.create(name: "A Nother", email: "another@example.org")
   (0.1ms)  SAVEPOINT active_record_1
  User Create (0.1ms)  INSERT INTO "users" ("name", "email", "created_at", "updated_at") VALUES (?, ?, ?, ?)  [["name", "A Nother"], ["email", "another@example.org"], ["created_at", "2020-11-21 15:12:58.282793"], ["updated_at", "2020-11-21 15:12:58.282793"]]
   (0.1ms)  RELEASE SAVEPOINT active_record_1
=> #<User id: 2, name: "A Nother", email: "another@example.org", created_at: "2020-11-21 15:12:58", updated_at: "2020-11-21 15:12:58">

>> foo = User.create(name: "Foo", email: "foo@bar.com")
   (0.1ms)  SAVEPOINT active_record_1
  User Create (0.1ms)  INSERT INTO "users" ("name", "email", "created_at", "updated_at") VALUES (?, ?, ?, ?)  [["name", "Foo"], ["email", "foo@bar.com"], ["created_at", "2020-11-21 15:13:06.291513"], ["updated_at", "2020-11-21 15:13:06.291513"]]
   (0.1ms)  RELEASE SAVEPOINT active_record_1
=> #<User id: 3, name: "Foo", email: "foo@bar.com", created_at: "2020-11-21 15:13:06", updated_at: "2020-11-21 15:13:06">

saveのときは戻り値がtrue(真偽値)だったが、createのときは作成されたオブジェクトが返却されてくる違いがあるので、 なんでも便利だからcreateで済まそう!とはいかなさそう。  

削除

#削除
>> foo.destroy
   (0.1ms)  SAVEPOINT active_record_1
  User Destroy (0.2ms)  DELETE FROM "users" WHERE "users"."id" = ?  [["id", 3]]
   (0.1ms)  RELEASE SAVEPOINT active_record_1
=> #<User id: 3, name: "Foo", email: "foo@bar.com", created_at: "2020-11-21 15:13:06", updated_at: "2020-11-21 15:13:06">

>> foo
=> #<User id: 3, name: "Foo", email: "foo@bar.com", created_at: "2020-11-21 15:13:06", updated_at: "2020-11-21 15:13:06">

DELETEが発行され削除されている。しかし、オブジェクト内にはメモリ上の情報が残っている。 実際に削除されたかどうかはこの方法で調べないように。(以下のfindメソッド等を使用しSELECT文を発行して確認するのが良さげ)  

クラス、継承元の調べ方

#クラスと継承元を調べる
>> user.name.class
=> String
>> user.email.class
=> String
>> user.created_at.class
=> ActiveSupport::TimeWithZone
>> user.updated_at.class
=> ActiveSupport::TimeWithZone

 

find

#id:1を検索
>> User.find(1)
  User Load (0.2ms)  SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT ?  [["id", 1], ["LIMIT", 1]]
=> #<User id: 1, name: "Michael Hartl", email: "michael@example.com", created_at: "2020-11-21 15:11:49", updated_at: "2020-11-21 15:11:49">

>> User.find(3)
  User Load (0.1ms)  SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT ?  [["id", 3], ["LIMIT", 1]]
Traceback (most recent call last):
        1: from (irb):18
ActiveRecord::RecordNotFound (Couldn't find User with 'id'=3)

  SELECTが発行されている。findはidで調べる用。

find_by

#特定の属性で検索
>> User.find_by(email: "michael@example.com")
  User Load (0.2ms)  SELECT "users".* FROM "users" WHERE "users"."email" = ? LIMIT ?  [["email", "michael@example.com"], ["LIMIT", 1]]
=> #<User id: 1, name: "Michael Hartl", email: "michael@example.com", created_at: "2020-11-21 15:11:49", updated_at: "2020-11-21 15:11:49">

SELECTが発行され、条件WHEREemailとなっている。任意の属性で検索する場合はfind_byを使用する。  

first

#最初のデータ
>> User.first
  User Load (0.2ms)  SELECT "users".* FROM "users" ORDER BY "users"."id" ASC LIMIT ?  [["LIMIT", 1]]
=> #<User id: 1, name: "Michael Hartl", email: "michael@example.com", created_at: "2020-11-21 15:11:49", updated_at: "2020-11-21 15:11:49">

SELECTが発行され、idでソート(`ORDER BY~ASC``)をかけたあと、最初の1件を取得していることがわかる。  

all

#すべてのデータ
>> User.all
  User Load (0.2ms)  SELECT "users".* FROM "users" LIMIT ?  [["LIMIT", 11]]
=> #<ActiveRecord::Relation [#<User id: 1, name: "Michael Hartl", email: "michael@example.com", created_at: "2020-11-21 15:11:49", updated_at: "2020-11-21 15:11:49">, #<User id: 2, name: "A Nother", email: "another@example.org", created_at: "2020-11-21 15:12:58", updated_at: "2020-11-21 15:12:58">]>

SELECTですべてのデータを取得している。[["LIMIT", 11]]の11はどこから来たのか不明…いつか調べたい。もしかしたら色々登録してて、idの最大値が入っているだけかも。

find_by_name

#名前で検索
>> User.find_by_name("Michael Hartl")
  User Load (0.2ms)  SELECT "users".* FROM "users" WHERE "users"."name" = ? LIMIT ?  [["name", "Michael Hartl"], ["LIMIT", 1]]
=> #<User id: 1, name: "Michael Hartl", email: "michael@example.com", created_at: "2020-11-21 15:11:49", updated_at: "2020-11-21 15:11:49">

WHERE name =で名前検索してくれる。  

length

#要素の長さを取得
>> User.all.length
  User Load (0.2ms)  SELECT "users".* FROM "users"
=> 2

SELECT~FROMだけのシンプルなSQLだった。 COUNTで件数を取得してるのかと思っていたが、どうやら違うらしい。別のところで件数を数えてくれているっぽい。  

更新(save)

#更新
>> user.email = "mhartl@example.net"
=> "mhartl@example.net"

>> user.save
   (0.1ms)  SAVEPOINT active_record_1
  User Update (0.2ms)  UPDATE "users" SET "email" = ?, "updated_at" = ? WHERE "users"."id" = ?  [["email", "mhartl@example.net"], ["updated_at", "2020-11-21 15:27:55.850900"], ["id", 1]]
   (0.1ms)  RELEASE SAVEPOINT active_record_1
=> true

すでにあるIDのオブジェクトをsaveすると、勝手にUPDATEしてくれるっぽい。有能。さらに、名前からして当然ではあるが、UPDATEではcreated_atは更新されない。  

取消

#save前に取消
>> user.email = "foo@bar.com"
=> "foo@bar.com"

>> user.reload.email
  User Load (0.1ms)  SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT ?  [["id", 1], ["LIMIT", 1]]
=> "mhartl@example.net"

DBにまだ保存されていないので、SQLで特に何かしているわけではないっぽい。  

更新(update)

#updateで更新
>> user.update(name: "The Dude", email: "dude@abides.org")
=> true
>> user.name
=> "The Dude"
>> user.email
=> "dude@abides.org"

updateを使用すると成功したかどうかの真偽値が返却される。  

検証を回避しつつ更新

#検証を回避しつつ更新
>> user.update_attribute(:name, "El Duderino")
=> true
>> user.name
=> "El Duderino"

実装の中で検証が失敗するようになることもあるらしい。これから学んでいく。