👻

[Rails]resource・resourcesの違い

2025/02/03に公開

今回のエラーについて

Rails.application.routes.draw do
  devise_for :users
  root to: "homes#top"
  get "/homes/about" => "homes#about", as: "about"

  resources :post_images, only: [:new, :create, :index, :show, :destroy] do
    # 下記が間違い
    resources :favorites, only: [:create, :destroy]
    resources :post_comments, only: [:create, :destroy]
  end
  resources :users, only: [:show, :edit, :update]
end

ルーティングで上記書き方をしたらエラーが出ました。

# 複数形が間違い
resources :favorites, only: [:create, :destroy]
# 正しくは単数形
resource :favorite, only: [:create, :destroy]

「resources :favorites」と複数形で書いてしまったことにより、
複数形でいいねをしようとすると、「Routing Error」が出て、URLが"/tasks/3/favorites/3"になってしまう。

resourceresources で、生成される URL とルーティングが異なる。


resources(複数形・間違い)

resources は、リソースが複数のインスタンスを持つ場合に使う。
つまり、データベースに保存される 複数のインスタンス(レコード) を管理するために使われる。

ルーティング例:

resources :favorites, only: [:create, :destroy]

生成される URL:

POST /favorites → favorites#create(「いいね」作成)
DELETE /favorites/:id → favorites#destroy(「いいね」削除)
  • POST /favorites のリクエストで、新しい「いいね」を作成できる。
  • DELETE /favorites/:id では、どの「いいね」を削除するのか id が必要になる。
  • これは「1つの投稿に対して、複数のユーザーがいいねをつける」場合に適している。

resources は、リソースが複数存在するケースを対象としているため、/favorites/:id のように :id が URL に含まれる。

resources を使う場合のデータモデル

class Favorite < ApplicationRecord
  belongs_to :user
  belongs_to :post_image
end

favorites テーブルには、以下のようなデータが入る:

id user_id post_image_id
1 2 5
2 3 5
3 2 6

→ つまり、1つの投稿 (post_image_id: 5) に対して、複数のユーザー (user_id: 2, 3) が「いいね」をつけられる。


resource(単数形・正しい)

resource は、今回のような「リソースが 1つだけ しか存在しない」ことが前提。
つまり、「特定のユーザーが1つの投稿に対して、1回だけ いいねをつける」場合に適している。

ルーティング例:

resource :favorite, only: [:create, :destroy]

生成される URL:

POST /favorite → favorites#create(「いいね」作成)
DELETE /favorite → favorites#destroy(「いいね」削除)
  • URL に :id が含まれない(/favorite/:id ではなく /favorite)。
  • これは「1つの投稿に対して、1人のユーザーが1回だけ いいねをつける」場合に適している。
  • 例えば、Twitter の「いいね」のように、ユーザーが同じ投稿に2回いいねできない設計。

resource を使う場合のデータモデル

class Favorite < ApplicationRecord
  belongs_to :user
  belongs_to :post_image

  validates :user_id, uniqueness: { scope: :post_image_id }
end

favorites テーブルのデータは、同じユーザーが同じ投稿に2回以上「いいね」できないようにする

id user_id post_image_id
1 2 5
2 3 6

→ つまり、各ユーザー (user_id) は、各投稿 (post_image_id) に 1回だけ いいねできる。

Discussion