当ブログではPRや広告を掲載しています

【Rails初心者】1対多のレコード作成。シンプルなコード解説

プログラミング
この記事はこんな人向け
  • Rails に少し慣れてきた
  • コントローラーでの書き方がイマイチ理解できてない
  • 1対多のリレーションについて説明できるほど理解に自信がない
スポンサーリンク

1対多の関係について(改めて理解しよう)

この記事では、Railsでテーブルを1つでも作成したことがある人を前提とします。
なので実際にテーブルを作成するマイグレーション関連のことは割愛します。

さて、テーブルの関係性についてですが、今回は”User”と”Book”の2つのモデル(テーブル)を用いて解説していきます。

2つのテーブルをER図で

テーブルの関係性を表すER図(EntityRelationship)を見てみましょう。

“User”が1で、”Book”が多の関係となっており、これは1人のユーザーが複数のBook(本)を登録できることになります。

実際のアプリケーションの画面では、ユーザーがフォーム画面からBookを新規投稿していくイメージですね。
イメージ的には、Twitterで1人のユーザーが何回もツイートできる関係性と同じです。

Railsコードの解説

ここからは、モデルやコントローラーの記載について解説していきます。

モデルのリレーションを組む

まずは、予め作成した”User”と”Book”のそれぞれにリレーションの記述を追加します。

app/models/user.rb
class User < ApplicationRecord
  has_many :book, dependent: :destroy
end

Userモデルから見た時に、Bookモデルは複数存在する”多”の関係なので、has_many を記述します。
dependent: :destory の記述は、「ユーザーが消されると、そのユーザーに紐づくBookも削除する」という意味なので、これはあっても無くてもどちらでも大丈夫です。

app/models/book.rb
class Book < ApplicationRecord
  belongs_to :user
end

Bookモデルから見た時に、Userモデルは1つしか存在しない”1”の関係のため、belongs_to を記述します。
このモデルはこれだけで、他は特に記述不要です。

フォーム画面を作成

画面側のコードはいたって普通な感じなので、コードの紹介までにしておきます。

app/views/books/new.html.erb
<%= form_with url: books_path, local:true do |f| %>
  <div class="form-group">
    <label for="book_title">Title</label>
    <%= f.text_field :title, id:"book_title", placeholder:"", class: 'form-control'%>
  </div>
  <div class="form-group">
    <label for="book_content">Content</label>
    <%= f.text_area :content, rows:'5', id:"book_content", placeholder: "", class: 'form-control' %>
  </div>
  <div class="form-group">
    <%= f.submit "Create Book", class: 'btn' %>
  </div>
<% end %>

コントローラーでのレコード登録

2つのテーブルを関連付けた場合、どちらかのテーブルには他方のテーブルのidが登録必須になっている場合がほとんどです。

今回の場合は、Bookを新たに登録する際にUserのid (user_id) が指定必須となります。
このため、単純にコントローラーのcreateメソッド処理を書くとこのようになります。

※この例ではUserにはdeviseでログイン機能をつけているため、“current_user”が使用可能となってます。
deviseなど使っていなければ、User.find(id) などでユーザーのオブジェクトを取得するようにしてください。

app/controllers/books_controller.rb
def create
  @book =Book.new(params.permit(:title, :content)) #paramsで渡ってきたtitle,contentからBookオブジェクトを作成
  @book.user_id = current_user.id #ログインユーザーidを指定
  if @book.save #Bookをレコード登録
    redirect_to book_path(@book) #showページへ遷移
  end
end

このコードのミソは、@book.user_id に直接current_user.idを入れていることです。
これで「どのユーザーがBookを登録しようとしているか」を指定できます。

しかし、このコードをもっとスッキリさせることができます。

せっかくリレーションを組んでいるので、最大限活かしましょう。
次のようなコードになります。

app/controllers/books_controller.rb
def create
  @book = current_user.book.new(params.permit(:title, :content))
  if @book.save
    redirect_to book_path(@book) #showページへ遷移
  end
end

さきほどの user_id を指定してた箇所が無くなりました。
代わりに2行目が current_user から始まるようになっています。

これは、「current_user に紐づくレコードだよ」とあらかじめ宣言する方法です。
これによりBookのレコードの user_id カラムには current_user のidが自動的に入るようになるんです!

ちなみに今回は1対多の関係でしたが、1対1の関係性でも同じ方法で記述できます。
要は、親側のモデルを起点にするとリレーションが上手いこと自動的にやってくれる、という感じですね。

まとめ

  1. モデルでリレーションを組む
    1. has_many
    2. belongs_to
  2. (view画面を作っておく)
  3. コントローラーでレコード登録の記述をする

コメント