82
83

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Railsで投稿とカテゴリの紐付け機能を実装する

Posted at

はじめに

Ruby on Railsで、投稿(Post)とカテゴリ(Category)の紐付けを実装します。
モデルやコントローラの生成は割愛します。予めご了承ください。

実行環境

  • Ruby 2.5.1
  • Rails 5.2.3

完成イメージ

1.投稿に紐付けるカテゴリは、チェックボックスから複数選択できます。
ScreenShot 2019-07-15 11.43.39.jpg

2.「投稿する」ボタンをクリックすると、DBへの登録とページ遷移が行われます。
ScreenShot 2019-07-15 11.47.46.jpg

多対多のアソシエーション(関連付け)

Postは複数のCategoryに紐付き、Categoryも複数のPostに紐付きます。これを多対多の関係といいます。
多対多の関係は、中間テーブルを利用して実現します。
ScreenShot 2019-07-12 20.30.23.jpg

中央のPost_category_relationsが中間テーブルです。紐付けるモデルのpost_idcategory_idを持ちます。

モデル

まずは中間テーブルのモデルから。
PostCategorybelongs_toで関連付けます。

app/models/post_category_relation.rb
class PostCategoryRelation < ApplicationRecord
  belongs_to :post
  belongs_to :category
end

続いて、PostCategoryのモデルです。
中間テーブルのモデルであるpost_category_relationshas_manyで関連付けます。

app/models/post.rb
class Post < ApplicationRecord
  has_many :post_category_relations
  has_many :categories, through: :post_category_relations
end
app/models/category.rb
class Category < ApplicationRecord
  has_many :post_category_relations
  has_many :posts, through: :post_category_relations
end

また、PostCategoryを、CategoryPosthas_manyで関連付けます。
ここでポイントとなるのが、**through: :post_category_relations**です。
中間テーブルのpost_category_relationsを経由して、関連付けをすることを意味しています。
なお、has_manyの関連付けは、中間テーブルを先に記述しないとActiveRecord::HasManyThroughOrderErrorというエラーが発生しますので、注意してください。

ビュー

投稿を登録する画面です。
前述の多対多のアソシエーションにより、postオブジェクトにcategory_idsというプロパティが追加されます。

app/views/posts/new.html.erb
<%= form_with model: @post do |f| %>
  <p>
    <%= f.label :title, '題目' %>
    <%= f.text_field :title %>
  </p>

  <p>
    <%= f.label :body, '本文'%>
    <%= f.text_field :body %>
  </p>

  <p>
    <%= f.label :category, 'カテゴリ' %>
    <%= f.collection_check_boxes(:category_ids, Category.all, :id, :name) do |category| %> 
      <%= category.label do %>
        <%= category.check_box %>
        <%= category.text %>
      <% end %>
    <% end %>
  </p>

  <%= f.submit '投稿する' %>
<% end %>

存在するカテゴリの数だけチェックボックスを作成するために、collection_check_boxesメソッドを使用します。引数の内容は以下のとおりです。

  • 第一引数 :category_ids postオブジェクトのプロパティ名
  • 第二引数 Category.all categoryオブジェクトの配列を取得
  • 第三引数 :id チェックボックスのvalue属性の値
  • 第四引数 :name チェックボックスのラベル名

コントローラ

今回は投稿を登録すると、その投稿の詳細ページに遷移する作りにしています。
投稿に紐付くカテゴリは、投稿を登録する際のパラメータに含まれるため、strong parametersを使用しています。

app/controller/posts_controller.rb
class PostsController < ApplicationController
  def new
    @post = Post.new
  end

  def create
    @post = Post.create(post_params)
    redirect_to @post
  end

  def show
    @post = Post.find(params[:id])
  end

  private

  def post_params
    params.require(:post).permit(:title, :body, category_ids: [])
  end
end

ポイントは、post_paramsメソッドのcategory_ids: []です。
投稿に紐付くカテゴリは、チェックボックスによって複数渡される場合があるため、配列形式であることを記載します。

その他

サンプルとして、コンソールからカテゴリ名を登録しておきます。
$ rails cでコンソールを起動して、以下のコードを入力します。

%W[Ruby Java Python Go].each { |sample| Category.create(name: sample) }

投稿登録後に遷移するviewファイル(投稿の詳細ページ)は以下を使用します。

app/views/posts/show.html.erb
<p><%= "【題目】#{@post.title}" %></p>
<p><%= "【本文】#{@post.body}" %></p>
<span>【カテゴリ】</span>
<% @post.categories.each do |category| %>
  <%= category.name %>
<% end %>

ルーティングは以下のとおり。

config/routes.rb 
Rails.application.routes.draw do
  resources :posts, only: [:show, :new, :create]
end

#終わりに

$ rails sでサーバ起動後、http://localhost:3000/posts/newにアクセスして投稿登録画面を表示します。
完成イメージ通りに、投稿とカテゴリを紐付けた登録ができるでしょう👏

82
83
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
82
83

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?