LoginSignup
0
0

More than 1 year has passed since last update.

【rails 】他ユーザーが作成したルームに後から参加する、誰がルームを作成したかわかるようにする

Posted at

テックキャンプ現役受講生がWebアプリを開発するのDay9です。アプリ完成の目標をとりあえず6月末までとしていますので、残り1週間です。終わる気がしません。しかし、嘆いても仕方ないので、明日以降ももやるべきことをコツコツやっていくのみです。さて、今日は他者が作ったルームに、後から他のユーザーが参加する方法について「DB設計、アソシエーション、コントローラーへの記述」の3部分に分けてアウトプットします。

※当方はエンジニア初心者ですので、もっとスマートな方法があるかもしれません。その点ご容赦ください。

今回のシチュエーションの設定

登場するテーブルは4つです。Userとroom、User_room、Ownerの4つです。
Userはroomを作成することができ、Roomの中ではチャット等の会話ができる空間を想定しています。
roomを一番はじめに作ったユーザーはOwner(オーナー)として登録し、Ownerにはroomの名前変更等の権限を与えられるものとします。
User_roomはUserとroomの中間テーブルです。下図を見ていただくとイメージが湧きやすいと思います。

DB設計

テックキャンプ-12.jpg

マイグレーションファイルの記述

user
class DeviseCreateUsers < ActiveRecord::Migration[6.1]
  def change
    create_table :users do |t|
      ## Database authenticatable
      t.string :email,              null: false, default: ""
      t.string :encrypted_password, null: false, default: ""
      t.string :nickname, null: false
      #以下省略
room
class CreateRooms < ActiveRecord::Migration[6.1]
  def change
    create_table :rooms do |t|
      t.string :name, null: false
      t.timestamps
    end
  end
end
中間テーブル
class CreateUserRooms < ActiveRecord::Migration[6.1]
  def change
    create_table :user_rooms do |t|
      t.references :user, foreign_key: true
      t.references :room, foreign_key: true
      t.timestamps
    end
    add_index :user_rooms, [:user_id, :room_id], unique: true #←この記述でルームとユーザーの組み合わせが一意であることを設定しています。
  end
end
Owner
class CreateOwners < ActiveRecord::Migration[6.1]
  def change
    create_table :owners do |t|
      t.string :name, null: false
      t.references :owner, foreign_key: { to_table: :users }#ユーザーの外部キーですが、別の名前をつけてわかりやすくしています。
      t.references :room, foreign_key: true
      t.timestamps
    end
  end
end

Userの外部キーはカラムに"User_id"と登録されますが、この名前を変更することができます。OwnerテーブルではUserの外部キーに、任意の名前(Owner)をつけてわかりやすくしています。

アソシエーション

アソシエーションに関係のあるところのみ抽出して記述しています。

class User < ApplicationRecord
  has_many :user_rooms
  has_many :rooms ,through: :user_rooms
  has_many :owners
end
room
class Room < ApplicationRecord
  has_many :user_rooms
  has_many :users, through: :user_rooms
  has_one :owner
end
中間テーブル
class UserRoom < ApplicationRecord
  belongs_to :user
  belongs_to :room
end
Owner
class Owner < ApplicationRecord
  belongs_to :owner, class_name: "User"
  belongs_to :room
end

Ownerは中間テーブルではないので、アソシエーションにご注意を。

コントローラーの記述

リクエストからは取得する情報は以下の通り
・Roomの名前
・ログインしているユーザーの情報(これはdevisを導入していると、current_userで簡単に取得可能)
ヘルパーメソッドのform_withでparams送信します

new.html.erb
<%= form_with(model: @room, local: true) do |f| %>
<%= f.text_field :name, placeholder: "ディスカッションのテーマを入力してください",class:"input-name"%>
<%= f.submit "作成", class:"input-name submit-bottom"%>
<% end %>

コントローラー内部で三段階に分けて処理をします。
①roomのテーブルに保存
②中間テーブルに情報を保存
③保存したroomの情報をもとにOwnerテーブルにデータを保存

controller
class RoomsController < ApplicationController
  def create
    @room = Room.new(room_params)
    if @room.save
      Owner.create(name:current_user.nickname, owner_id: current_user.id,room_id:@room.id)
      redirect_to room_path(@room)
    else
      render 'new'
    end
  end

private
  def room_params
    params.require(:room).permit(:name).merge(user_ids: [current_user.id])
  end
end

中間テーブルの保存は「user_ids:〜」という部分で可能になります。↓を参照ください。

まとめ

・”他ユーザーが作成したルームに後から参加する”という機能を実装するには中間テーブルを利用すレバOK。
・”誰がルームを作成したかわかるようにする”には新しく作成したのかわかるように、そのデータを管理するテーブルを新たに作成する。
技術的に難しいところはなく、発想次第で解ける問題でした。

反省点

ルーム作成者を明確にするには、そのデータを管理するためのテーブルを新たに作成する必要があることがわかりました。今後、機能を追加する際は、現状のテーブルだけでうまく対処しようとせず、その機能を管理するためのテーブルを作ることも視野に入れなければなりません。また、1つの送信で、2つのテーブルのデータを書き換えているので、今後form_objectを導入するべきだと思いました。

解決したかったけど、できなかったこと。

Ownerテーブルにnameというカラムを導入していますが、これはUserテーブルにあるのと同じものです。データが冗長になっていると思いました。これを解決するために、最初の方はアソシエーションでどうにはOwnerの名前をUserのnameカラムから引っ張ってこようと思っていましたが、アソシエーションによる呼び出しの仕方がわからず、どうにもできませんでした。今説明したことを抽象化すると
「親:子のアソシエーションが1対多の時、アソシエーションを利用し子から親を1つ特定する」
ということだと思います。今後も勉強して、いつか理解したいです。

参考サイト

0
0
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
0
0