0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

ポートフォリオ構築の振り返り(第10回:親子関係/リレーションを作る)

Last updated at Posted at 2025-09-12

はじめに

Railsで投稿機能を作っていると、「最初に作った投稿(親投稿)」に対して「その後の経過(子投稿)」を紐づけて記録したいケースが出てきます。
例えば、商品レビューの途中経過を追加したり、使い始めてからの変化を追跡したりするようなイメージです。編集とは違い経過を記録するために作りました。

ここでは、親子関係を持った投稿機能(親:Item、子:ItemPost) を実装する流れをまとめます。

これまでの記事はこちら👇
ポートフォリオ構築の振り返り(第1回:プロジェクト概要と設計)
ポートフォリオ構築の振り返り(第2回:Railsアプリ立ち上げ〜トップページ表示)
ポートフォリオ構築の振り返り(第3回:Deviseでログイン機能を実装)
ポートフォリオ構築の振り返り(第4回:ヘッダーの作成とログイン機能の実装)
ポートフォリオ構築の振り返り(第5回:投稿機能と画像投稿フォームの作成)
ポートフォリオ構築の振り返り(第6回:投稿機能の作成)
ポートフォリオ構築の振り返り(第7回:ユーザーカラム追加)
ポートフォリオ構築の振り返り(第8回:部分テンプレートを使ったマイページ作成)
ポートフォリオ構築の振り返り(第9回:itemのカード表示と共通化)


今回の流れ

  1. モデルの作成(親:Item、子:ItemPost)
  2. コントローラの作成
  3. ビューでの親子関係を考慮した表示・投稿
  4. まとめと用語解説

内容

1. 親子関係の考え方

  • 親投稿(Item):元となる投稿(商品やレビュー対象)
  • 子投稿(ItemPost):親に紐づく追加の経過投稿(途中経過や再レビュー)

これにより、1つの投稿のライフサイクルを継続的に追跡できるようになります。
親に依存して存在するのが子というのが重要なポイントです。


2. モデルの定義

app/models/item.rb(親)

class Item < ApplicationRecord
  has_one_attached :image

  validates :title, presence: true, length: { maximum: 100 }
  validates :body, presence: true, length: { maximum: 500 }
  validates :category, presence: true
  validates :image, presence: true   

  has_many :item_posts, dependent: :destroy
  belongs_to :user
  belongs_to :group, optional: true

  enum category: { cosmetics: 0, daily_necessities: 1, groceries: 2, supplement: 3 }
  enum status: { unopened: 0, start: 1, active: 2, finish: 3, discard: 4, repeat: 5 }

  scope :latest, -> { order(created_at: :desc) }
end

app/models/item_post.rb(子)

class ItemPost < ApplicationRecord
  has_one_attached :image

  belongs_to :user
  belongs_to :item
  accepts_nested_attributes_for :item

  validates :review, presence: true, length: { maximum: 500 }
  validates :image, presence: true 

  enum status: { unopened: 0, start: 1, active: 2, finish: 3, discard: 4, repeat: 5 }
end

✅ ここで重要なのは以下です:

  • Item has_many :item_posts … 親に複数の子が紐づく
  • ItemPost belongs_to :item … 子は必ず親に紐づく

3. コントローラの実装

app/controllers/public/items_controller.rb(一部)

class Public::ItemsController < ApplicationController
  def show
    @item = Item.find(params[:id])
    @item_post = ItemPost.new
  end
end

app/controllers/public/item_posts_controller.rb(一部)

class Public::ItemPostsController < ApplicationController
  def new
    @item = Item.find(params[:item_id])
    @item_post = ItemPost.new(item_id: @item.id)
  end

  def create
    @item = Item.find(params[:item_id])
    @item_post = current_user.item_posts.new(item_post_params)
    @item_post.item = @item

    if @item_post.save
      redirect_to item_path(@item), notice: '経過投稿を追加しました。'
    else
      render :new
    end
  end

  private

  def item_post_params
    params.require(:item_post).permit(:review, :image, :status, :item_id, item_attributes: [:star, :deadline])
  end
end

✅ ここでのポイント:

  • ItemPostsController では params[:item_id] から親を取得
  • 子投稿を @item_post.item = @item で親に紐づけて保存

4. ビューでの実装例

親投稿の詳細ページ(app/views/public/items/show.html.erb)

<h2><%= @item.title %></h2>
<p><%= @item.body %></p>

<h3>経過投稿</h3>
<% @item.item_posts.each do |post| %>
  <div class="child-post">
    <p><%= post.review %></p>
    <%= image_tag post.image if post.image.attached? %>
  </div>
<% end %>

<h3>経過投稿を追加</h3>
<%= form_with model: [@item, @item_post], local: true do |f| %>
  <div>
    <%= f.label :review, "レビュー" %>
    <%= f.text_area :review %>
  </div>
  <div>
    <%= f.label :image, "画像" %>
    <%= f.file_field :image %>
  </div>
  <div>
    <%= f.label :status, "ステータス" %>
    <%= f.select :status, ItemPost.statuses.keys.map { |k| [k, k] } %>
  </div>
  <%= f.submit "投稿する" %>
<% end %>

✅ ポイント:

  • @item.item_posts.each で親に紐づく子を一覧表示
  • form_with model: [@item, @item_post] で子投稿を親に紐づけて作成

まとめ

  • 親投稿(Item)と子投稿(ItemPost)の親子関係を作ることで、1つの投稿の経過を追加できるようにした
  • モデルで has_manybelongs_to を設定するのが基本
  • コントローラで params[:item_id] を受け取り、子に親を紐づけるのがポイント
  • ビューでは [親, 子] の形でフォームを組むことで親子関係を維持できる

👉 これで、投稿の親子関係(親:Item、子:ItemPost)を作り、親に対して経過投稿を追加できるようになりました!
次回は個人投稿だけじゃなくグループで投稿や管理ができるような仕組みを振り返ります!
ポートフォリオ構築の振り返り(第11回:グループ機能を作る)


用語説明

  • 親子関係 … データ同士が「1対多」で紐づく関係。Railsでは has_many(親)と belongs_to(子)で表現する。
  • accepts_nested_attributes_for … 子モデルの属性を親モデルのフォームから更新できる仕組み。
  • form_with model: [親, 子] … ネストしたリソース(例:/items/:item_id/item_posts)に対応する書き方。
  • dependent: :destroy … 親が削除されたとき、関連する子も一緒に削除するオプション。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?