devise使わずユーザー編集・更新機能を実装する
#はじめに
今回はユーザーのマイページを実装してから、プロフィールを編集できるようにするための方法を解説します。
#前提条件
・deviseを導入済み
・deviseによるゆーざー新規登録/ログイン機能を実装済み
#開発環境
Ruby 2.6.5
Rails 6.0.0
MySQL 5.6.50
#手順
##1)ユーザー詳細(マイページの実装)
まずdeviseのものとは別にusersコントローラー
を作成します。
ターミナルにて以下コマンドを実行します。
$ rails g controller users show
コントローラーが作成できたら、以下のようにファイルを編集ます。
class UsersController < ApplicationController
before_action :set_user, only: [:show]
def show; end
private
def set_user
@user = User.find(params[:id])
end
end
次にルーティングも設定します
# 既存の記述に追記する
resources :users, only: [:show]
これでマイページへのパスとアクションの設定は終わりました。
次にビューの記述をしていきます。
views/users/show.html.erb
にて記述していきます。
マイページの実装は以上です。
##2)ユーザー編集機能の実装
ここからは、あくまでも自分の場合なので、参考までにとどめてください。
まずDB設計(マイグレーションファイル)を以下のようにしました。
deviseのusesテーブルはnickname
カラムのみ作成します。
class DeviseCreateUsers < ActiveRecord::Migration[6.0]
def change
create_table :users do |t|
## Database authenticatable
t.string :nickname, null: false
t.string :email, null: false, default: ''
t.string :encrypted_password, null: false, default: ''
# 省略
end
続いてプロフィール用のテーブルの設計をしていきます。
ターミナルにて以下のコマンドを実行します
(僕の場合はプロフィール用にintro
モデルを作成)
$ rails g model intro
マイグレーションファイルを編集します。
class CreateIntros < ActiveRecord::Migration[6.0]
def change
create_table :intros do |t|
t.string :image
t.string :first_name
t.string :last_name
t.string :website
t.text :profile
t.references :user, foreign_key: true
t.timestamps
end
end
end
以上でテーブルの設計は終了です。
2-1)モデルのアソシエーションの設定
次にアソシエーションですが、以下のような設定にしました。
has_one :intro
belongs_to :user
このように1対1の関係を結びました。
2-2)ルーティングとアクションの設定
resources :users, only: [:show]
resources :intros, only: [:new, :create, :edit, :update]
ルーティングは上記のようにし、ネストはしませんでした。
理由は、ユーザー編集用のテーブルはイメージとしてはツイートなどの投稿用のテーブルと近いような気がしたからです。
アクションもそうですが、イメージとしては投稿機能を、ユーザー編集に置き換えるとイメージを持つと実装しやすいかと思います。
次にアクションの定義を行います。
class IntrosController < ApplicationController
# 未ログインユーザーの処理
before_action :authenticate_user!, only: [:new, :edit]
# リファクタリング
before_action :set_intro, only: [:edit, :update]
def new
@intro = Intro.new
# すでに登録済みのユーザーが新規登録ページに遷移しないようにする
if Intro.find_by(user_id: current_user.id)
redirect_to root_path
end
end
def create
@intro = Intro.new(intro_params)
# 保存できたら、ユーザー詳細ページに戻るため引数にintroモデルに紐づくuserのidをわたす
# intoro.valid?でないのはバリデーションをかけていないため
if @intro.save
redirect_to user_path(@intro.user.id)
else
render :new
end
end
def edit
# ログイン中のユーザーと編集するユーザーが一致しないとページに遷移できないようにする
unless current_user.id == @intro.user.id
redirect_to user_path(@intro.user.id)
end
end
def update
# createと同じように更新できたらユーザー詳細に戻るため引数をわたす
if @intro.update(intro_params)
redirect_to user_path(@intro.user.id)
else
render :edit
end
end
private
def set_intro
@intro = Intro.find(params[:id])
end
def intro_params
params.require(:intro).permit(:first_name, :last_name, :website, :profile, :image).merge(user_id: current_user.id)
end
end
これでユーザー編集・更新機能の実装はほとんど完了です。
最後にビューを作成します。
また、この時ユーザー編集ページへ遷移するリンクに条件を指定します。
###2-3)views/users/show.html.erbの編集
<% if user_signed_in? %>
# introテーブルにUserの値が存在しなれば新規登録のリンクを表示
<% unless @user.intro.present? %>
# ログインしているユーザーとマイページに表示されているユーザーが同じなら新規登録のリンクを表示
<% if current_user.id == @user.id %>
<div class="profile-btn">
<%= link_to 'プロフィールを編集する', new_intro_path, class: "profile-edit-btn" %>
</div>
<% end %>
<% end %>
# ログインしているユーザーとマイページに表示されているユーザーが同じで、かつintroテーブルに値が存在していれば編集ページへのリンクを表示する
<% if current_user.id == @user.id && @user.intro.present? %>
<div class="profile-btn">
<%= link_to 'プロフィールを編集する', edit_intro_path(@user.intro.id), class: "profile-edit-btn" %>
</div>
<% end %>
<% end %>
僕の場合はこのような記述しかできませんでしたが、もっと良い記述があればコメントくださると嬉しいです。
僕はここにたどり着くまでに1日半かかったので、この記事を見て少しでも作業が進んだという方がいらっしゃれば幸いです。
#参考文献
Discussion