Rails 6 でTodoApp作る part5
プロフィールの編集を制限する
自分以外のユーザーの編集をできなくする
現状、ログインしていれば全てのユーザーの編集ページに入ることができます。
ユーザー"panda"でログイン中
[ 自分のページ ]
[ rakudaさんのページ ]
これを対処します
自分のページのみ編集ページへのリンクを表示する
URL直打ちでのアクセスを防ぐ
自分のページのみ編集ページへのリンクを表示する
[ views/users/show.html.slim ]
h1 アカウントの詳細 .nav.justify-content-end = link_to '一覧', users_path, class: 'nav-link' table.table.table-hover tbody tr th 名前 td = @user.name tr th メールアドレス td = @user.email tr th 登録日 td = @user.created_at tr th 更新日 td = @user.updated_at - if current_user.id == @user.id # 追加 = link_to '編集', edit_user_path, class: 'btn btn-primary mr-3'
- if current_user.id == @user.id
によりログイン中のユーザーのid
と詳細ページのユーザーのid
が同じ時のみ編集ページへのリンクが表示されるようになります
ユーザー"panda"でログイン中
[ 自分のページ ]
[ rakudaさんのページ ]
自分のshowページでのみ、editページへのリンクが表示されるようになりました!
URL直打ちでのアクセスを防ぐ
[ users_controller.rb ]
class UsersController < ApplicationController before_action :correct_user, only: [:edit, :update, :destroy] def index @users = User.all end (省略) private def user_params params.require(:user).permit(:name, :email, :password, :password_confirmation) end # before_action def correct_user user = User.find(params[:id]) redirect_to root_url if current_user != user end end
correct_userをprivateメソッドとして定義し、before_actionで呼び出します。
users_controller内で[:edit, :update, :destroy]
のアクションを実行する前に、実行しようとするユーザー(current_user)と編集されようとしているユーザーが一致していなければroot_url
に飛ばします。
これで自分のユーザーアカウントを他のユーザーに編集されないようになります。
フィルタを使い重複を避ける
taskコントローラーを作る際に作ったフィルタをUserバージョンでもう一度やります。
[ users_controller.rb(現在) ]
class UsersController < ApplicationController before_action :correct_user, only: [:edit, :update, :destroy] def index @users = User.all end def show @user = User.find(params[:id]) end def new @user = User.new end def create @user = User.new(user_params) if @user.save redirect_to users_url, notice: "ユーザー「#{@user.name}」を登録しました。" else render :new end end def edit @user = User.find(params[:id]) end def update @user = User.find(params[:id]) if @user.update(user_params) redirect_to users_url, notice: "ユーザー「#{@user.nsame}」を更新しました。" else render :edit end end def destroy @user = User.find(prams[:id]) @user.destroy redirect_to root, notice: "ユーザー「#{@user.name}」を削除しました。" end private def user_params params.require(:user).permit(:name, :email, :password, :password_confirmation) end # before_action def correct_user user = User.find(params[:id]) redirect_to root_url if current_user != user end end
上記は現在のusers_controllerです。
@user = User.find(prams[:id])
が連発されているのでフィルタを使いすっきりさせます。
before_action :set_user, only: [:show, :edit, :update, :destroy] def set_user @user = User.find(prams[:id]) end
set_user
を定義し、before_action
で呼び出します。
指定されたアクションが実行される前に@user = User.find(prams[:id])
を行います。
そのため、各アクションから@user = User.find(prams[:id])
の記述を消すことができるので、各アクションの中身がシンプルになります。
トータルの行数は増えてしまいますが、、、
[ users_controller.rb(変更後) ]
class UsersController < ApplicationController before_action :correct_user, only: [:edit, :update, :destroy] before_action :set_user, only: [:show, :edit, :update, :destroy] def index @users = User.all end def show end def new @user = User.new end def create @user = User.new(user_params) if @user.save redirect_to users_url, notice: "ユーザー「#{@user.name}」を登録しました。" else render :new end end def edit end def update if @user.update(user_params) redirect_to users_url, notice: "ユーザー「#{@user.nsame}」を更新しました。" else render :edit end end def destroy @user.destroy redirect_to root, notice: "ユーザー「#{@user.name}」を削除しました。" end private def user_params params.require(:user).permit(:name, :email, :password, :password_confirmation) end # before_action def correct_user user = User.find(params[:id]) redirect_to root_url if current_user != user end def set_user @user = User.find(prams[:id]) end end
i18nで日本語対応にする
所々、英語が表示されちゃってる部分を日本語にしていくう
まず、
[ Gemfile ]
gem 'rails-i18n'
bundle
以前設定したlocale.rb
をいちよう確認。
[ config/initializers/locale.rb ]
Rails.application.config.i18n.default_locale = :ja
これだけで日本語になります。(完全な英語の状態を撮り忘れました。)
しかし、まだちょっと残っている英語も日本語にします。
config/locales/
にja.yml
と言うファイルを作成します。
そして、内容修正
[ config/locales/ja.yml ]
ja: activerecord: models: task: タスク attributes: task: title: タイトル description: 詳しい説明
- モデル名はactiverecoredのmodelsの中に
- 属性名はactiverecoredのattributesの中に定義します。
サーバーを再起動すると・・
ちょっとあれですね・・・
こんな感じにします。
[ tasks_controller.rb ]
- if task.errors.any? div#error_explanation .alert.alert-danger = "#{task.errors.count}種類のエラーがあります" ul - task.errors.full_messages.each do |message| li = message = form_with model: task, local: true do |f| (省略)
application.html.slim
も変更しなくては・・
[ layouts/application.html.slim ]
doctype html html head title | TodoApp = csrf_meta_tags = csp_meta_tag = stylesheet_pack_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' = javascript_pack_tag 'application', 'data-turbolinks-track': 'reload' body = render 'layouts/header' .container - flash.each do |message_type, message| = content_tag(:div, message, class: "alert alert-#{message_type}") = yield
notice
からflash
に変更したのでコントローラーも変更しなくては・・・
[ tasks_controller.rb ]
(省略) def create @task = current_user.tasks.new(task_params) if @task.save flash[:success] = "タスク「#{@task.title}」を登録しました。" redirect_to tasks_url else render :new end end (省略) def update if @task.update(task_params) flash[:success] = "タスク「#{@task.title}」を更新しました!" redirect_to tasks_url else render :edit end end def destroy @task.destroy flash[:warning] = "タスク「#{@task.title}」を削除しました。" redirect_to tasks_url end (省略)
こっちも・・・
[ users_controller.rb ]
(省略) def create @task = current_user.tasks.new(task_params) if @task.save flash[:success] = "タスク「#{@task.title}」を登録しました。" redirect_to tasks_url else render :new end end (省略) def update if @task.update(task_params) flash[:success] = "タスク「#{@task.title}」を更新しました!" redirect_to tasks_url else render :edit end end def destroy @task.destroy flash[:warning] = "タスク「#{@task.title}」を削除しました。" redirect_to tasks_url end (省略)
あと、sessions_controller
にも・・
flash.now[:danger] = 'メールアドレスとパスワードの組み合わせが存在しません'
も追加してます!
[ sessions_controller.rb ]
(省略) def create user = User.find_by(email: session_params[:email]) if user&.authenticate(session_params[:password]) session[:user_id] = user.id redirect_to root_url, notice: 'ログインしました' else flash.now[:danger] = 'メールアドレスとパスワードの組み合わせが存在しません' render :new end end def destroy reset_session flash[:success] = 'ログアウトしました' redirect_to login_url end (省略)
users
のform
も直しておきます。
[ users/_form.html.slim ]
- if user.errors.any? div#error_explanation .alert.alert-danger = "#{task.errors.count}種類のエラーがあります" ul - user.errors.full_messages.each do |message| li = message = form_with model: user, local: true do |f| (省略)
今日はここまで、、
次回、rspec導入