投稿を管理する、またユーザーが必要としている投稿を探しやすくするようにするために、カテゴリー分けは必須ですよね。
今回は投稿(post)に紐づくカテゴリーの一覧ページを自作で作成する方法をご紹介します。
前提条件
- ruby 2.5.1
- Rails 5.2.0
まずお断り
カテゴリー分けるをする方法を検索していたら、いろいろとアンチパターンなるものがあるらしい。今回ご紹介する方法がベストプラクティス!っていうわけではないので、あくまで一つの方法って感じで試してみて下さい。
今回目指すところ
- 投稿(posts)と作成するときにカテゴリー(category)は一つだけ選択可能。
- https://xxxxt/posts → 投稿一覧を取得して表示
- https://xxxx/posts?category_id=1 → category_idが1に紐付いているの投稿一覧
データベース構造
データベースはこんな感じで設定しました。 メッセージ(posts)class CreatePosts < ActiveRecord::Migration[5.2]
def change
create_table :posts, options: 'ROW_FORMAT=DYNAMIC' do |t|
t.references :category
t.text :title, null: false
t.timestamps
end
end
end
class CreateCategories < ActiveRecord::Migration[5.2]
def change
create_table :categories, options: 'ROW_FORMAT=DYNAMIC' do |t|
t.string :slug, null: false
end
end
end
(1)Posts <-> (1)Categories
マイグレーションをしてデータベースを作成
$ rails migrate
mysql> show columns from posts;
+---------------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+---------------+--------------+------+-----+---------+----------------+
| id | bigint(20) | NO | PRI | NULL | auto_increment |
| category_id | bigint(20) | YES | MUL | NULL | |
| title | text | NO | | NULL | |
| created_at | datetime | NO | | NULL | |
| updated_at | datetime | NO | | NULL | |
+---------------+--------------+------+-----+---------+----------------+
mysql> show columns from categories;
+-------------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------------+--------------+------+-----+---------+----------------+
| id | bigint(20) | NO | PRI | NULL | auto_increment |
| slug | varchar(255) | NO | | NULL | |
+-------------+--------------+------+-----+---------+----------------+
routeの設定
投稿が表示できるようにrouteを設定します。Rails.application.routes.draw do
resources :posts, param: :id
end
Modelの設定
リレーションをmodel部分に設定します。今回は1対1なのでbelongs_toとhas_oneでリレーションをはります。
class Post < ApplicationRecord
belongs_to :category
end
class Category < ApplicationRecord
has_one :post
end
Controllerの設定
indexにPostの一覧を取得するようにします。urlにcategory_id(params)がある場合は、category_idで絞った投稿を取得してきます。
それ以外はすべての投稿を取得するようにします。
- https://xxxxt/posts → 投稿一覧を取得して表示
- https://xxxx/posts?category_id=1 → category_idが1に紐付いているの投稿一覧
class PostsController < ApplicationController
def index
# urlにcategory_id(params)がある場合
if params[:category_id]
# Categoryのデータベースのテーブルから一致するidを取得
@category = Category.find(params[:category_id])
# category_idと紐づく投稿を取得
@posts = @category.posts.order(created_at: :desc).all
else
# 投稿すべてを取得
@posts = Post.order(created_at: :desc).all
end
end
end
Viewの設定
最後に@postのオブジェクトをview側で表示します。 app/views/posts/index.html.erb<% @posts.each do |item| %>
<%= item.title %>
<% end %>
データベースの知識がまったく無かったので、どうやってCategory_idに紐づく投稿を取得するかがよくわかりませんでしたが、URLで分岐すれば簡単に取得することができました。