Ruby モデルを作ろう：User と Post を使ったクラス設計ハンズオン

## はじめに
このハンズオンでは、Ruby を使って **User** と **Post** という2つのクラスを題材に、オブジェクト指向の基本設計〜機能拡張まで段階的に学びます。

前提：Ruby が実行できる環境を準備してください。

## 問題文 (ステップが4つ)
**【ステップ 1】 User クラスの作成**
**【ステップ 2】 Post クラスの作成**
**【ステップ 3】 User が複数の Post を持てるように**
**【ステップ 4】 応用**

#### [その他] 拡張アイデア (今回はしない)
5. Post にカテゴリ・タグを持たせて分類出来るようにする
6. User に自動採番される ID (通し番) を付与する
7. Post に "いいね" 機能を追加 (カウントして increment)
8. Post を CSV に書き出し/読み込みできるようにする
9. User のデータを JSON で出力できるようにする
10. Post を作成日付のフィルターで検索できるようにする


### ハンズオン
#### 【ステップ 1】 User クラスの作成

**【問題】 次の仕様を満たす User クラスを作成してください。**
- ユーザーの名前とメールアドレスを持つ
- ユーザーの名前を取得できる（name）
- ユーザーの情報を表示する info メソッドがある

##### 🔧 使用例（この動作になるように作る）:
```ruby
user = User.new("Alice", "alice@example.com")
puts user.name         #=> Alice
puts user.info         #=> 名前: Alice, メール: alice@example.com
```

<details>
<summary>答えを見る</summary>

```ruby
class User
  attr_reader :name

  def initialize(name, email)
    @name = name
    @email = email
  end

  def info
    "名前: #{@name}, メール: #{@email}"
  end
end

# 動作確認
user = User.new("Alice", "alice@example.com")
puts user.name         #=> "Alice"
puts user.info         #=> "名前: Alice, メール: alice@example.com"
```
</details> 


#### 【ステップ 2】 Post クラスの作成

**【問題】 次の仕様を満たす Post クラスを作成してください**
- 投稿のタイトルと本文を持つ
- 投稿の内容を表示する summary メソッドがある

#### 🔧 使用例（この動作になるように作ってね）:
```ruby
post = Post.new("初投稿", "これは最初の投稿です。")
puts post.summary
#=> タイトル: 初投稿
#   本文: これは最初の投稿です。
```

<details>
<summary>答えを見る</summary>

```ruby
class Post
  def initialize(title, body)
    @title = title
    @body = body
  end

  def summary
    "タイトル: #{@title}\n本文: #{@body}"
  end
end

post = Post.new("初投稿", "これは最初の投稿です。")
puts post.summary
```
</details> 

#### 【ステップ 3】 User に Post を持たせる
**【問題】 User クラスに、複数の投稿（Post）を持たせられるように拡張してください**
- add_post(post) で投稿を追加できる
- list_posts ですべての投稿のタイトルを表示できる



#### 🔧 使用例（この動作になるように作ってね）:
```ruby
user = User.new("Bob", "bob@example.com")
post1 = Post.new("日記1", "今日は晴れ")
post2 = Post.new("日記2", "今日は雨")

user.add_post(post1)
user.add_post(post2)
user.list_posts
#=> ユーザーBobの投稿一覧:
#   - 日記1
#   - 日記2
```


<details>
<summary>答えを見る</summary>

```ruby
class User
  attr_reader :name, :posts

  def initialize(name, email)
    @name = name
    @email = email
    @posts = []
  end

  def info
    "名前: #{@name}, メール: #{@email}"
  end

  def add_post(post)
    @posts << post
  end

  def list_posts
    puts "ユーザー#{@name}の投稿一覧:"
    @posts.each do |post|
      puts "- #{post.title}"
    end
  end
end

class Post
  attr_reader :title

  def initialize(title, body)
    @title = title
    @body = body
  end

  def summary
    "タイトル: #{@title}\n本文: #{@body}"
  end
end

user = User.new("Bob", "bob@example.com")
post1 = Post.new("日記1", "今日は晴れ")
post2 = Post.new("日記2", "今日は雨")

user.add_post(post1)
user.add_post(post2)
user.list_posts
#=> ユーザーBobの投稿一覧:
#   - 日記1
#   - 日記2
```
</details> 

#### 【ステップ 4】 応用
**以下の機能を追加してください (検索と投稿数の取得はUserクラスに定義)**
- 投稿に created_at を追加して、投稿順(降順)に並べて表示
- 投稿をキーワードで検索できる機能 (search_posts)
- User クラスで投稿数を取得（post_count）

#### 🔧 使用例（この動作になるように作ってね）:
```ruby
user = User.new("Bob", "bob@example.com")
post1 = Post.new("日記1", "今日は晴れ")
post2 = Post.new("日記2", "今日は雨")
post3 = Post.new("日記3", "今日は曇り")

user.add_post(post1)
user.add_post(post2)
user.add_post(post3)

user.list_posts
# ユーザーBobの投稿一覧:
# - 日記3
# - 日記2
# - 日記1
p user.search_posts("曇り") # [#<Post:0x0000000100608e60 @title="日記3", @body="今日は曇り", @created_at=2025-03-28 20:08:18.78414 +0900>]
p user.post_count # 3
```

<details>
<summary>答えを見る</summary>

```ruby
class User
  attr_reader :name, :posts

  def initialize(name, email)
    @name = name
    @email = email
    @posts = []
  end

  def info
    "名前: #{@name}, メール: #{@email}"
  end

  def add_post(post)
    @posts << post
  end

  def list_posts
    puts "ユーザー#{@name}の投稿一覧:"
    @posts.sort_by{ |post| post.created_at }.reverse.each do |post|
      puts "- #{post.title}"
    end
  end

  def search_posts(keyword)
    @posts.select { |post| post.title.include?(keyword) || post.body.include?(keyword) }
  end

  def post_count
    @posts.length
  end
end

class Post
  attr_reader :title, :body, :created_at

  def initialize(title, body)
    @title = title
    @body = body
    @created_at = Time.now
  end

  def summary
    "タイトル: #{@title}\n本文: #{@body}"
  end
end

user = User.new("Bob", "bob@example.com")
post1 = Post.new("日記1", "今日は晴れ")
post2 = Post.new("日記2", "今日は雨")
post3 = Post.new("日記3", "今日は曇り")

user.add_post(post1)
user.add_post(post2)
user.add_post(post3)

user.list_posts
p user.search_posts("曇り")
p user.post_count
```
</details> 

### 終わりに
普段フレームワークを使って開発しているけれど、「オブジェクト指向を本当に理解できているか不安…」という人におすすめの学習方法です。

AIに「Rubyでオブジェクト指向を学びたいから、UserとPostの関係性でステップごとに問題を作って。ハンズオン形式でやりたい」とお願いすれば、すぐに問題を生成してくれます。

「ステップを5つ用意して」や「いいね機能や投稿の編集・削除のステップを追加して」、「クラス継承のステップもほしい」といった細かい指示を出すと、より実践的で自分に合った問題が作れるのでオススメです。

学習のアイデア出しの段階からAIに相談してみるのもアリですね！

また、株式会社シンシアでは、実務未経験のエンジニアの方や学生エンジニアインターンを採用し一緒に働いています。
※ シンシアにおける働き方の様子はこちら

https://www.wantedly.com/companies/xincere-inc/stories

弊社には年間100人程度の実務未経験の方に応募いただき、技術面接を実施しております。
この記事が少しでも学びになったという方は、ぜひ wantedly のストーリーもご覧いただけるととても嬉しいです！