Rails アプリケーションで1対多のアソシエーションを作成する方法

✏️️ 2019/08/22 👍️2019/08/22 🔗

Category Model と Post Model を 1対多のアソシエーションにします。既にCategory Model と Post Model は存在するとします。

Migration

postsテーブルに外部キー(category_id)カラムを追加します。:references にすると、INDEXを自動で貼ってくれて, 外部キー制約(foreign_key: true)もマイグレーションファイルに追加してくれます。

bin/rails g migration AddCategoryPosts category:references
# db/migrate/add_category_posts.rb
class AddCategoryPosts < ActiveRecord::Migration[6.0]
  def change
    add_reference :posts, :category, foreign_key: true
  end
end
bin/rails db:migrate

Model

※ 前提条件として、記事はカテゴリーが属さなくてもOKな仕様です。

Category has many posts. なので、has_many :posts アソシエーションを追加します。 dependent: :nullify で、Categoryが削除されたら、postテーブルのcategory_id にnullを入れるようにします。

# app/models/category.rb
class Category < ApplicationRecord
  has_many :posts, dependent: :nullify
end

また、Posts belongs to category. なので、 belongs_to :category アソシエーションを追加します。optional: true にすることによって、category_idカラムのnullを許容します。つまり、記事を作成する際にCategoryは無しでもOKになります。

参考: https://www.akito.io/posts/dependent-option

# app/models/post.rb
class Post < ApplicationRecord
   belongs_to :category, optional: true
end

Controller

StrongParameterにcategory_idを追加します

# app/controllers/posts_controller.rb
def post_params
  params.require(:post).permit(:title, :content, :slug, :status, :category_id, tag_ids: [])
end

View

Postのformからカテゴリーを追加できるように以下を追加

# app/views/posts/_form.html.erb

<%= form.label :category, class: 'label' %>
<%= form.collection_select( :category_id, Category.all, :id, :name, {include_blank: '選択してください' })%>

refs: https://www.akito.io/posts/collection-select

以上で、Rails アプリケーションで1対多のアソシエーションを作成する方法は完了です。

Akito
日本のスタートアップで主にRuby on Railsを使ってプロダクト開発をしています。