0
2

投稿アプリマイページ機能の実装

Posted at

こちらも備忘録です!

目的

  • アソシエーションの理解
  • N+1問題の対策を理解

ツイートにユーザー情報を追加

「誰が投稿したのか」わかるようになり

  • 特定のユーザーがつぶやいたツイート一覧を取得できる
  • ツイートの削除を行う際につぶやいた本人しか削除できないように設定できる
    機能が実現可能になります

tweetsテーブルにカラムを追加

tweetsテーブルに新しくuser_idというカラムを作成する
そこにツイートを投稿したユーザーのidを保存します

tweetsテーブルにuser_idカラムをinteger型で追加

ターミナル

rails g migration AddUserIdToTweets user_id:integer
rails db:migrate

ツイート保存時にユーザー情報も追加

user_idカラムに、ツイートを投稿した(現在ログイン中の)ユーザーの
idを保存する処理を記述
ここに保存すべき値は、currenr_userのid

current_userメソッド

現在ログインしているユーザーの情報を取得できる

mergeメソッド

ハッシュを結合させる時に使用するRubyのメソッド

app/controllers/tweets_controller.rb

~~
private
def tweet_params
    params.require(:tweet).permit(:name, :image, :text).merge(user_id: current_user.id)
end
~~

モデル同士を関連付け

アソシエーション

モデルを利用したテーブル同士の関連付けのこと
誰がどの投稿にツイートしたかわかるようになる

has_manyメソッド

userと他のモデルとの間に「1対多」のつながりがあることを示すこと。
一人のユーザーは複数の投稿を所有する
「User has many Tweets」
app/models/user.rb

~~
    has_many :tweets
end

belongs_toメソッド

TweetモデルとUserモデルとの間に「1対1」のつながりがあることを示す
一つの投稿は一人のユーザーが所属する
「Tweet belongs to User」
app/models/user.rb

~~
    belongs_to :user
end

ユーザーに関するshowアクションのルーティングを設定

~~
    resources :users, only: :show

マイページボタンを投稿一覧に追加

app/views/layouts/application.html.erb

  # 省略
  <header class="header">
    <div class="header__bar row">
      <h1 class="grid-6"><a href="/">PicTweet</a></h1>
      <% if user_signed_in? %>
        <div class="user_nav grid-6">
          <span><%= current_user.nickname %>
            <ul class="user__info">
              <li>
                <%= link_to "マイページ", "/users/#{current_user.id}" %>
                <%= link_to "ログアウト", destroy_user_session_path, data: { turbo_method: :delete } %>
              </li>
            </ul>
          </span>
          <%= link_to "投稿する", new_tweet_path, class: "post" %>
        </div>
      <% else %>
        <div class="grid-6">
          <%= link_to "ログイン", new_user_session_path, class: "post" %>
          <%= link_to "新規登録", new_user_registration_path, class: "post" %>
        </div>
      <% end %>
    </div>
  </header>
  # 省略

ユーザーに関するshowアクションをコントローラーに定義

rails g controller users
app/controllers/users_controller.rb

class UsersController < ApplicationController
  def show
    @nickname = current_user.nickname
    @tweets = current_user.tweets
  end
end

マイページのビュー作成

app/views/usersshow.html.erb作成
app/views/users/show.html.erb

<div class="contents row">
  <p><%= @nickname %>さんの投稿一覧</p>
  <% @tweets.each do |tweet| %>
    <div class="content_post" style="background-image: url(<%= tweet.image %>);">
      <p><%= tweet.text %></p>
      <span class="name"><%= tweet.name %></span>
    </div>
  <% end %>
</div>

投稿者となるユーザー名の表示

投稿者名を表示するようにビューを変更
現在、user_idがNULLになっていることによるエラー文発生
undefined method 'nickname' for nil:NilClass
→nicknameが参照できていない
ツイートを投稿した際、user_idの一緒に保存するようにしましたが、Sequel Proで確認すればわかる通り、
それ以前に投稿したツイートはuser_idがNULLのままになっている
このときtweet.userNULLとなるため、tweet.user.nicknameと書くと、からのクラスに対してnicknameメソッドが実行されてしまい「そんなメソッドは存在しない」というNoMethodErrorが発生
tweetテーブルのuser_idカラムに値を入れます。

投稿者名のところへ、マイページに飛ぶリンクを設置
app/views/tweets/index.html.erb

~~
<p><%= tweet.text %></p>
      <span class="name">
        <a href="/users/<%= tweet.user.id %>">
          <span>投稿者</span><%= tweet.user.nickname %>
        </a>
        <%= tweet.name %>
      </span>
    </div>
  <% end %>
</div>

これで、投稿者のリンクをクリックすると、その投稿者(ログインしてkるユーザー)が
投稿したツイートの一覧が表示されるページに、アクセスできるようになる
app/views/tweets/show.html.erb

~~
    <span class="name">
      <a href="/users/<%= @tweet.user.id %>">
        <span>投稿者</span><%= @tweet.user.nickname %>
      </a>
    </span>
~略~

ツイートからユーザー情報も先に読み込む

N+1問題

アソシエーションを利用した場合に限り、
データベースへのアクセス回数が多くなってしまう問題
アプリのパフォーマンス低下

includesメソッド

引数に指定された関連モデルを1度のアクセスでまとめて取得できる
モデル名.includes(:紐づくモデル名)
includeメソッドを使用すると全てのレコードを取得するため、allメソッドは省略可能
app/controllers/tweets_controller.rb

~~
def index
    @tweets = Tweet.includes(:user)
    end
~~

投稿画面のビューを変更

ツイートを表示する際にアソシエーションを利用して投稿者のニックネームが表示されるようになったので、nameカラムは不必要
投稿時に「Nickname」の値を入力する必要なし
app/views/tweets/new.html.erb app/views/tweets/edit.html.erb

<%= form.text_field :name, placeholder: "Nickname" %>←削除

投稿時の処理を変更

投稿時に「name」を入力する必要がなくなったので、それに合わせてtweetsコントローラーの処理も変更
nameカラムはもう使用しないので、ツイートの保存時にnameカラムへ情報を保存しないよう変更を行います
app/controllers/tweets_controller.rb

private
  def tweet_params
    params.require(:tweet).permit(:image, :text).merge(user_id: current_user.id)
  end

tweetテーブルから不要なカラム削除

rails g migration Removeカラム名From削除もとテーブル名 削除するカラム名:型

rails g migration RemoveNameFromTweets name:string
rails db:migrate

app/views/users/show.html.erb

<div class="contents row">
  <p><%= @nickname %>さんの投稿一覧</p>
  <% @tweets.each do |tweet| %>
    <div class="content_post" style="background-image: url(<%= tweet.image %>);">
      <p><%= tweet.text %></p>
      <span class="name"><%= tweet.name %></span>  # この行を削除
    </div>
  <% end %>
</div>

投稿者のマイページにアクセスできるようにする

app/controllers/users_controller.rb

class UsersController < ApplicationController
  def show
    user = User.find(params[:id])
    @nickname = user.nickname
    @tweets = user.tweets
  end
end
0
2
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
2