概要
ユーザー設定の枠組みでコメント編集機能を実装した。
ファイルアップロードの実装の詳細は「画像アップロード」にまとめており、ここでは以下の仕様のコードと説明のみまとめる。
- ユーザー設定画面に以下を表示
- 現在のプロフィール画像
- ファイル選択要素
- コメント入力要素(現在のコメント内容を入れておく)
- 送信時に画像が選択されていれば画像ファイルを保存してファイル名をデータベースに登録
- 画像保存前に 今の画像ファイルを削除
- 画像ファイル名はランダム文字列で与える
- コメント入力は入力されているテキストで更新
- 更新に成功すればプロフィール画面に遷移
- 更新に失敗すれば再度ユーザー設定画面に遷移
画像ファイル保存場所
public
ディレクトリー下にuser_images
ディレクトリーを作成。ここにプロフィール画像を保存。
users#editアクション
プロフィールコメント編集と同じ。
ルーティング
プロフィールコメント編集と同じ。
edit.html.erbビュー
画像アップロードに関する表示要素は以下のとおり。
- 現在のプロフィール画像(L6~12)
- プロフィール画像選択フィールド(L13)
app/views/users/edit.html.erb
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
<div class="user_settings"> <h1><%= @user.name %>さんのユーザー設定</h1> <div class="user_settings_form"> <%= form_with(model: @user, url: update_user_path(user_in_session), local: true) do |f| %> <h2>プロフィール画像</h2> <div class="profile_image"> <% if @user.image_file_name == nil %> <%= image_tag "https://dummyimage.com/200x200/0b0e4d/23f534.png&text=Profile+Image" %> <% else %> <%= image_tag user_image_url(@user) %> <% end %> </div> <%= f.file_field(:upload_file, class: "input file") %> <h2>プロフィールコメント</h2> <%= f.text_area(:comment, class: "input comment", placeholder: "プロフィールコメント") %> <button>この内容で設定</button> <% end %> </div> </div> |
イメージファイルをdiv
で囲んでいる(L6~12)。スタイル設定でdiv
要素のサイズに合わせて画像をフィッティング・センタリング。
file_field
のパラメーターキー:upload_file
はモデルのパラメーターには含まれない(L13)。コントローラーでファイルオブジェクトを取り出すためだけに使われる。
ボタンが押されると、update_user_path
→update
コントローラーに制御が移る(L4)。
user_image_urlヘルパー
edit
ビューでプロフィール画像を表示するのにuser_image_url
ヘルパーを使っている。このヘルパーはUser
に関して使うので、UsersHelper
モジュールに書いている。
画像ファイルのパスについては画像ファイルの配置とパス指定を参照
1 2 3 4 5 6 7 8 9 |
module UsersHelper ..... # プロフィール画像ファイルのフルパスを返す def user_image_url(user) "/user_images/#{user.image_file_name}" end end |
users#updateアクション
次の機能を追加している。
- フォームからのアップロードファイルの取得
- ファイルの保存
- データベースへのファイル名の登録
app/controllers/users_controller.rb
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
def update # セッション中のユーザーに対する処理 @user = User.find(user_in_session.id) # アップロードファイル <- file_field upload_file = params[:user][:upload_file] # 画像ファイルのパラメーターをマージするため new_user_params = user_params # 画像ファイルが選択されていれば、検証・保存・パラメーター設定 if upload_file.present? # ファイルタイプが適切でない場合はエラー・遷移 case upload_file.content_type when "image/jpeg" extention = ".jpg" when "image/png" extention = ".png" else flash.now[:danger] = "JPEGかPINGの画像ファイルを指定してください" render action: :edit and return end # 画像ファイルのファイル名をランダム文字列に upload_file_name = random_string(20) + extention # プロフィール画像を保存するディレクトリー upload_dir = Rails.root.join("public", "user_images") # アップロードするファイルのフルパス upload_file_path = upload_dir + upload_file_name # プロフィール画像がある場合は削除処理に入る if @user.image_file_name.present? # 前のファイルを削除するためのパス old_file_path = upload_dir + @user.image_file_name # 今のファイルを削除 File.delete(old_file_path) end # アップロードファイルの書き込み File.binwrite(upload_file_path, upload_file.read) # フォームから得られたparamsにファイル名の項目を追加 new_user_params = user_params.merge({image_file_name: upload_file_name}) end # 登録成功ならプロフィールページへ if @user.update(new_user_params) redirect_to profile_path(user_in_session) and return # 登録失敗ならエラーをフラッシュして再度ユーザー設定ページへ else flash.now[:danger] = "設定更新できませんでした" render action: :edit and return end end |
パラメーターからアップロードファイルのオブジェクトを取得(L6)。
user_params
で得られたパラメーターをnew_user_params
に保存しているが、ファイルが存在する場合はこれに:image_file_name
がマージが追加される。
ファイルタイプはJPEGかPINGのみで、それ以外はエラーをフラッシュして再度設定画面を表示(L11~20)。
ファイル名の衝突を避けるため、ファイル名をランダム文字列としている(L22)。
現在存在しているファイルを削除する(L27~33)。
ランダム文字列の生成
ランダム文字列の生成は記事投稿にも使うため、application_helper.rb
に書く。
app/helpers/application_helper.rb
1 2 3 4 5 6 |
module ApplicationHelper def random_string(n) chars = ("0".."9").to_a.join + ("A".."Z").to_a.join + ("a".."z").to_a.join (Array.new(n).map! {|e| chars[rand(chars.length)]}).join end end |
これを有効にするにはインクルードしておく必要がある。
app/controllers/application_controller.rb
1 2 3 4 5 6 7 8 |
class ApplicationController < ActionController::Base protect_from_forgery with: :exception # 共通で使われるヘルパーのモジュールをインクルード include ApplicationHelper # ユーザーセッションの管理に関するメソッドモジュールをインクルード include UsersHelper end |
user_paramsヘルパー
プロフィールコメント編集と同じ。
params[:user][:update_file]
は直接保存しないため、ストロングパラメーターとする必要がない。
スタイル
プロフィール画像のフィッティングとセンタリング(L20~33)。
L34ではファイル入力要素のスタイルを設定。
app/assets/stylesheets/users.scss
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
// ユーザー設定ページのスタイル .user_settings { margin: 0 auto; width: 600px; height: 100%; background-color: white; h1 { margin: 0 auto; padding: 40px 0 30px 0; font-size: 20px; text-align: center; font-weight: bold; } .user_settings_form { h2 { margin: 30px 20px 0 10px; font-size: 15px; } .profile_image { display: flex; align-items: center; justify-content: center; margin: 10px auto; width: 200px; height: 200px; img { width: auto; height: auto; max-width: 100%; max-height: 100%; } } .input { display: block; margin: 10px 20px 0 auto; width: 500px; } .comment { height: 100px; background-color: #f8f8f8; } button { display: block; margin: 10px 20px 10px auto; } } } |
フラッシュの追加
application.html.erb
にフラッシュの表示を追加(application_signed_out.html.erb
と同じ内容)。
- jQueryの読み込み
- フラッシュ表示部
- 一定時間後のスライドアップ
app/views/layouts/application.html.erb
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
<!DOCTYPE html> <html> <head> <title>ExBbs</title> <%= csrf_meta_tags %> <%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %> <%= javascript_include_tag 'application', 'data-turbolinks-track': 'reload' %> <%= javascript_include_tag 'https://code.jquery.com/jquery-3.5.0.min.js' %> <script src="https://kit.fontawesome.com/08c0548ff0.js" crossorigin="anonymous"></script> </head> <body> <% if flash.now.present? %> <% flash.each do |type, message| %> <p class="flash_message flash_message_<%= type %>"><%= message.html_safe %></p> <% end %> <% end %> <header> <%= link_to(top_path) do %> <div class="header_logo"></div> <% end %> <h1>EX-BBS</h1> <p><%= user_in_session.name %>さん</p> <ul class="header_menu"> ..... </ul> </header> <%= yield %> <script> window.setTimeout(() => { $(".flash_message").slideUp(); }, 3000); </script> </body> </html> |
プロフィール画面の変更
プロフィール画像ファイルのアップロードができたので、プロフィール画面にこれを表示させるよう変更する。
- プロフィール画面が未登録の場合はダミー画像を表示する
- 画像が存在する場合は
user_image_url
ヘルパーで画像のフルパスを取得する
app/views/users/show.html.erb
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
<div class="user_profile"> <h1><%= @user.name %>さんのプロフィール</h1> <div class="contents"> <div class="image"> <% if @user.image_file_name == nil %> <%= image_tag "https://dummyimage.com/200x200/0b0e4d/23f534.png&text=Profile+Image" %> <% else %> <%= image_tag user_image_url(@user) %> <% end %> </div> <p class="comment"> <%= @user.comment %><br> </p> </div> </div> |