LoginSignup
7
0

More than 1 year has passed since last update.

グループごとに投稿できる機能

Last updated at Posted at 2022-12-21

こんにちは。寒すぎて凍えているGeeksalonの限界メンターです。

「アーティストごとにアルバムを投稿したい」、「飲み会ごとに飲んだ量でランキングを実装したい」、「旅行プランごとに行き先を登録したい」etc...

そんな声に応えた機能を実装してみました。ユーザーのグループ機能はあったんですが、投稿をグループ化するのはぱっと見つからなかったので、初めてですが記事を書いてみました。未熟者ではありますが、温かい目で読んでみてください♪


【目次】

  1. 開発環境
  2. 概要
  3. アソシエーション
  4. 機能実装
     ➢ モデルの作成
     ➢ コントローラーの作成
     ➢ アソシエーション
     ➢ HTMLの実装
      ・ おまけ:ランキング

【 1. 開発環境 】

・ruby 3.0.4
・rails 6.1.6

- 前提 -
・Userの機能は実装済み
・TweetのCRUD機能は実装済み


【 2. 概要 】

  • コントローラー・モデルは以下3つ
    • User:ユーザー
    • Tweet:投稿(好きなものに置き換えて実装してください)
    • Room:グループ(Groupは予約語なのでRoomで実装しています)
  • ユーザーは自由にルームを作成できる
  • 投稿の際にルームを登録する。投稿は1つのルームに所属する。
  • ユーザーは複数ルームに所属する。
    • 今回の実装では、複数回所属してしまっている状態。これを逆手にとって後述のランキングを実装している。
    • おいおいルームのページから投稿するボタンを実装して自動的にそのルームでの投稿になるようにしたい。

- 完成図 -
・ ルーム一覧ページ
image.png
・ ルーム詳細ページ
image.png


【3. アソシエーション】

image.png

  • UserとTweetは1対多
  • RoomとTweetは1対多
  • UserとRoomは多対多
    • Tweetが中間テーブルとなってくれます。

【4. 機能実装】

➢ モデルの作成
 まずRoomモデルを作成しましょう。

terminal
$ rails g model Room roomname:text
$ rails db:migrate

➢ コントローラーの作成
 コントローラーを作成します。

terminal
$ rails g controller rooms

できたら中身に以下を記述していきましょう。

rooms_controller
class RoomsController < ApplicationController

    def index
        @rooms = Room.all
    end

    def new
        @room = Room.new
    end

    def create
        room = Room.new(room_params)

        if room.save
            redirect_to :action => "index"
        else
            redirect_to :action => "new"
        end
    end

    def show
        @room = Room.find(params[:id])
        @users = User.all
        
        #ランキング実装部分
        @roomtweets = Room.find(params[:id]).tweets
        @ranks = User.find(@roomtweets.group(:user_id).order('count(id) desc').pluck(:user_id))
    end
  
    private
      def room_params
        params.require(:room).permit(:roomname)
      end
end

tweet投稿時にRoomを割り振れるように、tweet_controllerも書き加えます。

tweets_controller
 # ~ 省略 ~

def new
        @tweet = Tweet.new
        rooms = []
        #tweet新規投稿の際、Roomを選択できるように配列にしてプルダウンに
        Room.all.each do |r|
            room = []
            room.push(r.name)
            room.push(r.id)
            rooms.push(room)
        end
        @rooms = rooms
    end

 # ~ 省略 ~

 private
    def tweet_params
        params.require(:tweet).permit(:body, :room_id)
    end

 # ~ 省略 ~

➢ アソシエーション
Tweetsテーブルにroom_idカラムを追加します。

terminal
$ rails g migration AddRoomIdToTweets room_id:integer
$ rails db:migrate

アソシエーションを記述していきます。

user.rb
class User < ApplicationRecord
  has_many :rooms, through: :tweets

  #Tweetsテーブルを介してRoomを関連付ける
  has_many :joined_rooms, through: :tweets, source: :room

  # 所属しているRoomを表示する際、使用する
  def already_joined?(room)
    self.tweets.exists?(room_id: room.id)
  end
end
tweet.rb
class Tweet < ApplicationRecord

    belongs_to :user
    belongs_to :room

end
room.rb
class Room < ApplicationRecord
  has_many :tweets
  
  #tweetsテーブルを介してUserを関連付ける
  has_many :users, through: :tweets
  #Tweetsテーブルを介して所属しているUserを関連付ける
  has_many :joined_users, through: :tweets, source: :user

  #所属しているユーザーを表示する際、使用する
  def already_joining?(user)
    self.tweets.exists?(user_id: user.id)
  end
end

➢ HTMLの実装
まずはルーティングを記述しておきましょう。

routes.rb
  resources :rooms

以下はRoom一覧ページです。

views/rooms/index.html.erb
<div class="rooms-container">
  <%= link_to "new", new_room_path %> #roomの新規作成
  <br>
  <% @rooms.each do |r| %> #roomの一覧表示
    ・<%= link_to  room_path(r.id) do %><%= r.roomname %><% end %><br>
  <% end %>
</div>

つぎはRoom新規作成ページです。

views/rooms/new.html.erb
<%= form_for(@room, :url => { controller:'rooms', action:'create'}) do |f| %>
  <%= f.label :room %>
  <%= f.text_field :roomname, :size => 140, class: "imput" %>
  <%= f.submit %>
<% end %>

<%= link_to "Room一覧に戻る", rooms_path %>

そして、Roomの詳細ページです。

views/rooms/show.html.erb
<%= link_to "rooms一覧に戻る", rooms_path %>

<br>

<h4>room名:<%= @room.roomname %></h4>

<% @users.each do |u| %>
  <% if u.already_joined?(@room) %>
    <%= u.name %><br>
  <% end %>
<% end %>

<br>
<h4>メンバーの投稿</h4>
<% @room.tweets.each do |t| %><%= t.body %>
  /<%= t.user.name %><br>
<% end %>

<br>

<h4>Room内 投稿数ランキングTop3</h4>
<% @ranks.each.with_index(1) do |u, i| %><%= i %>位:<%= u.name %><br>
<% end %>

そして最後に、tweetの投稿ページも少し手を加えておきましょう。

views/tweets/new.html.erb
<%= form_for(@tweet, :url => { controller:'tweets', action:'create'}) do |f| %>

 <%# 中略 %>

<%# Roomの登録 %>
    <%= f.label :room %>
    <%= f.select :room_id, @rooms %>

 <%# 中略 %>

<% end %>

まとめ

以上がグループ機能実装の簡単な説明です。基本的にはグループチャットの原理を利用していることが分かるかと思います。
しっかり細かいところまで考えられていない&実装も中途半端なので、今後詰めていければと思っています。

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