Ryota400’s blog

エンジニアを目指して書いてます。

プロフィール編集機能の実装

ルーティングの設定

routes.rb

resource :profile, only: %i[show edit update]

今回、プロフィール詳細画面と編集画面へのurlは/profile, /profile/editと 現在ログインしているユーザーの詳細と編集画面だけ表示できればいいので、urlでユーザーのidを参照する必要がない。

コントローラー設定

rails g controller profiles

userの情報は、userモデルに紐づいたデータベースに保存されていますが、今回は新たにモデルに紐づかないprofileコントローラーを生成し、profileコントローラーでプロフィールの編集ページを実装してく。

profile_controller.rb

class ProfilesController < ApplicationController
  before_action :set_user, only: %i[edit update]
  
  def edit; end

  def update
    if @user.update(user_params)
      redirect_to profile_path, success: t('defaults.message.updated', item: User.model_name.human)
    else
      flash.now['danger'] = t('defaults.message.not_updated', item: User.model_name.human)
      render :edit
    end
  end

  def show; end

  private

  def set_user
    @user = User.find(current_user.id)
  end

  def user_params
    params.require(:user).permit(:email, :last_name, :first_name, :avatar)
  end
end

アバターカラムの追加

今回は詳細ページにユーザーにアバター画像を追加するのでアバター画像のカラムを用意する カラム名avatarにするので、下記のコマンドを叩く

rails g uploader Avatar

userのアバター画像のカラムを生成したら、

rails g migration add_avatar_to_users avatar:string

最後に

rails db:migrate

app/uploaders/avatar_uploader.rb

class AvatarUploader < CarrierWave::Uploader::Base
  storage :file

  def store_dir
    "uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
  end

  def default_url
    'sample.jpg'
  end


  def extension_whitelist
    %w[jpg jpeg gif png]
  end

end

モデルと紐付け

app/models/user.rb

mount_uploader :avatar, AvatarUploader

viewの生成

app/views/profiles/show.html.erb

<% content_for(:title, t('.title')) %>
<div class="container pt-3">
  <div class="row">
    <div class="col-md-10 offset-md-1">
      <h1 class="float-left mb-5"><%= t('.title') %></h1>
      <%= link_to t('defaults.edit'), edit_profile_path, class: 'btn btn-success float-right' %>
      <table class="table">
        <tr>
          <th scope="row"><%= t(User.human_attribute_name(:email)) %></th>
          <td><%= current_user.email %></td>
        </tr>
        <tr>
          <th scope="row"><%= t(User.human_attribute_name(:full_name)) %></th>
          <td><%= current_user.decorate.full_name %></td>
        </tr>
        <tr>
          <th scope="row"><%= t(User.human_attribute_name(:avatar)) %></th>
          <td><%= image_tag current_user.avatar.url, class: 'rounded-circle', size: '50x50' %></td>
        </tr>
      </table>
    </div>
  </div>
</div>

app/views/profiles/edit.html.erb

<% content_for(:title, t('.title')) %>
<div class="container">
  <div class="row">
    <div class="col-md-10 offset-md-1">
      <h1><%= t('.title') %></h1>
      <%= form_with model: @user, url: profile_path, local: true do |f| %>
        <%= render 'shared/error_messages', object: f.object %>
        <%= f.label :email %>
        <%= f.email_field :email, class: 'form-control mb-3' %>

        <%= f.label :last_name %>
        <%= f.text_field :last_name, class: 'form-control mb-3' %>

        <%= f.label :first_name %>
        <%= f.text_field :first_name, class: 'form-control mb-3' %>

        <%= f.label :avatar %>
        <%= f.file_field :avatar, onchange: 'previewFileWithId(preview)', class: 'form-control mb-3', accept: 'image/*' %>
        <%= f.hidden_field :avatar_cache %>

        <div class='mt-3 mb-3'>
          <%= image_tag @user.avatar.url,
                        class: 'rounded-circle',
                        id: 'preview',
                        size: '100x100' %>
        </div>
        <%= f.submit class: 'btn btn-primary' %>
      <% end %>
    </div>
  </div>
</div>

ヘッダーアイコン、コメントフォームに設定した画像を表示させる

app/views/shared/_header.html.erb

   <%= image_tag current_user.avatar_url, size: '40x40', class: 'rounded-circle mr15'%>
<%= link_to (t 'profiles.show.title'), profile_path, class: 'dropdown-item' %>

app/views/comments/_comment.html.erb

 <%= image_tag comment.user.avatar_url, class: 'rounded-circle', size: '50x50' %>

参考文献

qiita.com

qiita.com