プロフィール編集機能の実装
ルーティングの設定
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' %>
参考文献