📝

Rails consoleの理解度を上げるために、 ChatGPTに問題を出力してもらった【中級編】

2023/07/25に公開

はじめに

前回【初級編】を行なったので、今回は【中級編】に挑戦したいと思います。
中級編では、モデル間の関連性、バリデーション、スコープ、クエリの操作などを取り扱います。
なお、使用するアプリケーションは初級編からのものを引き続き使用します。
初級編はこちら
https://zenn.dev/ippe/articles/abe04f750cf3c1

アプリケーションの概要

  • アプリ名
    BlogApp
  • モデル
    User Post Commentが存在します。
    User1 対 Post多 の関係。
    Post1 対 Comment多 の関係。
  • Userテーブル
    nameカラムとemailカラムを持ちます。
    nameは必須のバリデーション、emailは一意性のバリデーションを設定しています。
  • Postテーブル
    titleカラムとcontentカラムを持ちます。
  • Commentテーブル
    bodyカラムを持ちます。

chatGTPに出題してもらった問題(中級)

  1. 特定のUserが作成したPostの数を取得するコマンドを書いてください。
  2. 特定のUserが作成したPostのうち、タイトルに特定のキーワード("Rails")が含まれるものをすべて取得するコマンドを書いてください。
  3. Userのemailが未設定のものがあるかどうかを確認するコマンドを書いてください。
  4. Userモデルに新しいバリデーションを追加するためのコードを書いてください。このバリデーションでは、名前が必須であること、Eメールが一意であることを確認します。
  5. 上記のバリデーションが正しく機能しているかどうかをテストするためのコマンドを書いてください。新しいユーザーを作成し、バリデーションエラーメッセージを表示してください。
  6. Postのタイトルと内容からなる新しいメソッド info をPostモデルに追加するためのコードを書いてください。このメソッドはタイトルと内容を連結した文字列を返すものとします。
  7. 上記で作成したメソッドを使用して、特定のPostのタイトルと内容を表示するコマンドを書いてください。
  8. スコープを使用して、特定のキーワードを含むPostを取得するためのメソッドを作成してください。スコープ名は with_keyword とし、引数は keyword とします。
  9. 上記で作成したスコープを使用して、特定のキーワード("Rails")を含むPostを取得するコマンドを書いてください。
  10. 特定のUserが作成したPostを作成日の新しい順に取得するコマンドを書いてください。

私の回答

問題1の回答

Q. 特定のUserが作成したPostの数を取得するコマンドを書いてください。
まず、userを作成します。

irb(main):00:0> user = User.create(name: "ippei shimizu", email: "test@example.com")
irb(main):00:0> user
=> #<User id: 1, name: "ippei shimizu", email: "test@example.com", created_at: "2023-07-24 11:49:41", updated_at: "2023-07-24 11:49:41">

次に、userpostを作成します。

irb(main):00:0> post = user.posts.create(title: "ippeiの投稿", content: "今日はお散歩をしました")
irb(main):00:0> post
=> #<Post id: 3, title: "ippeiの投稿", content: "今日はお散歩をしました", user_id: 1, created_at: "2023-07-24 23:25:51", updated_at: "2023-07-24 23:25:51">

もう一つ作成しておきます。

irb(main):00:0> post1 = user.posts.create(title: "Railsの勉強をした", content: "modelを作成します。")
irb(main):00:0> post1
=> #<Post id: 4, title: "Railsの勉強をした", content: "modelを作成します。", user_id: 1, created_at: "2023-07-24 23:35:14", updated_at: "2023-07-24 23:35:14">

これで、user_id: 1を持つPostが2つ作成できました。
最後に、userが作成したpostの数を取得するコマンドを実行します。

irb(main):00:0> user.posts.count

問題2の回答

Q. 特定のUserが作成したPostのうち、タイトルに特定のキーワード("Rails")が含まれるものをすべて取得するコマンドを書いてください。

irb(main):00:0> user.posts.where('title LIKE ?', "%Rails%")

問題3の回答

Q. Userのemailが未設定のものがあるかどうかを確認するコマンドを書いてください。
まず、emailが未設定のuserを作成。

irb(main):00:0> user1 = User.create(name: "nivea sun", email: "")
irb(main):00:0> user1
=> #<User id: 3, name: "nivea sun", email: "", created_at: "2023-07-24 23:49:37", updated_at: "2023-07-24 23:49:37">

whereemailが未設定(nilまたは空)の場合を探す。

irb(main):00:0> User.where(email: [nil,""])
 User Load (0.5ms)  SELECT  "users".* FROM "users" WHERE ("users"."email" = ? OR "users"."email" IS NULL) LIMIT ?  [["email", ""], ["LIMIT", 11]]
=> #<ActiveRecord::Relation [#<User id: 3, name: "nivea sun", email: "", created_at: "2023-07-24 23:49:37", updated_at: "2023-07-24 23:49:37">]>

問題4の回答

Q. Userモデルに新しいバリデーションを追加するためのコードを書いてください。このバリデーションでは、名前が必須であること、Eメールが一意であることを確認します。

user.rb
class User < ApplicationRecord
  has_many :posts, dependent: :destroy

  validates :name, presence: true
  validates :email, uniqueness: true
end

問題5の回答

Q. 上記のバリデーションが正しく機能しているかどうかをテストするためのコマンドを書いてください。新しいユーザーを作成し、バリデーションエラーメッセージを表示してください。
まず、nameカラムが空のuserUser.newで作成します。

irb(main):00:0> user5 = User.new(name: "", email: "user5@example.com")
=> #<User id: nil, name: "", email: "user5@example.com", created_at: nil, updated_at: nil>

valid?メソッドでバリデーションを実行します。

irb(main):00:0> user5.valid?
  User Exists (0.2ms)  SELECT  1 AS one FROM "users" WHERE "users"."email" = ? LIMIT ?  [["email", "user5@example.com"], ["LIMIT", 1]]
=> false

バリデーションのエラーメッセージを確認します。

irb(main):00:0> user5.errors.messages
=> {:name=>["can't be blank"]}

問題6の回答

Q. Postのタイトルと内容からなる新しいメソッド info をPostモデルに追加するためのコードを書いてください。このメソッドはタイトルと内容を連結した文字列を返すものとします。
post.rbinfoメソッドを定義します。

post.rb
class Post < ApplicationRecord
  belongs_to :user
  has_many :comments, dependent: :destroy
  
  def info
    "#{self.title} #{self.content}"
  end
end

問題7の回答

Q. 上記で作成したメソッドを使用して、特定のPostのタイトルと内容を表示するコマンドを書いてください。

irb(main):00:0> post
=> #<Post id: 3, title: "ippeiの投稿", content: "今日はお散歩をしました", user_id: 1, created_at: "2023-07-24 23:25:51", updated_at: "2023-07-24 23:25:51">
irb(main):00:0> post.info
=> "ippeiの投稿 今日はお散歩をしました"

問題8の回答

Q. スコープを使用して、特定のキーワードを含むPostを取得するためのメソッドを作成してください。スコープ名は with_keyword とし、引数は keyword とします。
モデルのscope機能は、モデル側であらかじめ条件式に対して名前をつけ、その名前をメソッドで呼び出すことで、条件式の管理がしやすくなります。

post.rb
class Post < ApplicationRecord
  belongs_to :user
  has_many :comments, dependent: :destroy
  
  scope :with_keyword, -> (keyword){where('title LIKE ? OR content LIKE ?'), "%#{keyword}%", "%#{keyword}%"}
  
  def info
    "#{self.title} #{self.content}"
  end
end

問題9の回答

Q. 上記で作成したスコープを使用して、特定のキーワード("Rails")を含むPostを取得するコマンドを書いてください。

irb(main):00:0> Post.with_keyword("Rails")
  Post Load (0.7ms)  SELECT  "posts".* FROM "posts" WHERE (title LIKE '%Rails%' OR content LIKE '%Rails') LIMIT ?  [["LIMIT", 11]]
=> #<ActiveRecord::Relation [#<Post id: 4, title: "Railsの勉強をした", content: "modelを作成します。", user_id: 1, created_at: "2023-07-24 23:35:14", updated_at: "2023-07-24 23:35:14">, #<Post id: 5, title: "Rails楽しい", content: "controllerを作成します。", user_id: 1, created_at: "2023-07-24 23:37:20", updated_at: "2023-07-24 23:37:20">]>

問題10の回答

Q. 特定のUserが作成したPostを作成日の新しい順に取得するコマンドを書いてください。

irb(main):00:0> user
=> #<User id: 1, name: "ippei shimizu", email: "test@example.com", created_at: "2023-07-24 11:49:41", updated_at: "2023-07-24 11:49:41">
irb(main):00:0> user.posts.order(created_at: "DESC")
  Post Load (0.5ms)  SELECT  "posts".* FROM "posts" WHERE "posts"."user_id" = ? ORDER BY "posts"."created_at" DESC LIMIT ?  [["user_id", 1], ["LIMIT", 11]]
=> #<ActiveRecord::AssociationRelation [#<Post id: 5, title: "Rails楽しい", content: "controllerを作成します。", user_id: 1, created_at: "2023-07-24 23:37:20", updated_at: "2023-07-24 23:37:20">, #<Post id: 4, title: "Railsの勉強をした", content: "modelを作成します。", user_id: 1, created_at: "2023-07-24 23:35:14", updated_at: "2023-07-24 23:35:14">, #<Post id: 3, title: "ippeiの投稿", content: "今日はお散歩をしました", user_id: 1, created_at: "2023-07-24 23:25:51", updated_at: "2023-07-24 23:25:51">]>

ChatGPTに確認してもらう

素晴らしい!全ての回答が適切です。以下に各問題に対する詳細な解説を記載します。

問題1
user.posts.countで、特定のユーザーが作成したポストの数を取得することができます。ここでは、UserとPostの間に定義されたhas_many関連付けを利用しています。この関連付けにより、特定のUserオブジェクトから関連するPostオブジェクトにアクセスすることができます。

問題2
user.posts.where('title LIKE ?', "%Rails%")により、特定のユーザーが作成したポストのうち、タイトルに特定のキーワード("Rails")が含まれるものをすべて取得できます。ここでも、UserとPostの間のhas_many関連付けを利用しています。

問題3
User.where(email: [nil,""])で、Userのemailが未設定のものがあるかどうかを確認できます。ここではwhereメソッドを使っています。このメソッドは、指定した条件に一致するレコードを全て取得します。

問題4
バリデーションはモデル層でデータの整合性を担保するための機能です。ここでは、validatesメソッドを使用して、名前が必須であること(presence: true)、Eメールが一意であること(uniqueness: true)を指定しています。

問題5
バリデーションのチェックはvalid?メソッドで行います。ここでは、名前が空の新しいユーザー(user5)を作成し、user5.valid?を実行してバリデーションをチェックしています。結果がfalseとなり、名前が空ではならないというバリデーションが働いていることがわかります。

問題6
ここでは、インスタンスメソッドinfoを定義し、Postのタイトルと内容を連結した文字列を返すようにしています。selfは、現在のオブジェクト(この場合はPostオブジェクト)を指します。

問題7
問題6で作成したinfoメソッドを使用して、特定のPostのタイトルと内容を表示するためには、Postオブジェクト(この場合はpost)に対してinfoメソッドを呼び出します。これにより、Postのタイトルと内容が連結した文字列が表示されます。

問題8
スコープは、頻繁に使用するクエリをモデル内に定義して名前を付け、その名前をメソッドとして呼び出すことができるようにするRailsの機能です。ここでは、タイトルまたは内容に特定のキーワードが含まれるPostを取得するクエリをwith_keywordという名前で定義しています。

問題9
問題8で作成したスコープwith_keywordを使用して、特定のキーワード("Rails")を含むPostを取得します。スコープを使用すると、コードが短くて読みやすくなり、再利用性も向上します。

問題10
特定のUserが作成したPostを作成日の新しい順に取得するためには、orderメソッドを使用します。このメソッドは、指定したカラムに基づいてレコードを並べ替えます。この場合、created_at: "DESC"を指定しているので、作成日時の新しい順にレコードが並び替えられます。

最後に

valid?メソッドを使用して、バリデーションが正しく設定されているかの確認や、メソッドを定義して、コンソールでメソッドを実行して確認するなど、実際のアプリケーション開発でも使えることを学べました。また、chatGPTは回答の正誤判定だけでなく、解説も詳しく行なってくれるので、理解度を深めることができまし。

Discussion