はじめに
前回の投稿では、アルバムページの作成方法についてご紹介いたしました。 その後、私はdeviseを使用してログイン機能の追加や各種投稿機能を実装し、 Railsアプリっぽくなってきた事に満足していたのですが、 重要な欠陥に気付きました。それは、このままではどのユーザでログインしても投稿画面やアルバム一覧が全て見えてしまうという事です。。。。
絶対嫌ですよね。見知らぬ方にプライベートな写真や投稿を見られるのは。
このままではいけないと思い、各ユーザ毎に閲覧可能なページの権限設定方法について調べ、
実装しましたので備忘録として記事に残したいと思います。
下記の動画を参考にしました。非常に分かりやすくおすすめです。
お困りの方は是非ご覧いただければと思います。
https://www.youtube.com/watch?v=1bOhcNLkmec&t=579s
やりたいこと
UploadモデルをUserモデル(deviseにて作成)に紐付け、権限設定を行う環境
macOS:10.15.2 Ruby:2.6.5 Rails:5.2.4.1 deviseインストール済み手順
1. UploadモデルとUserモデルを紐付ける。
まずは、UploadモデルとUserモデルの紐付けを行う為に、マイグレーションファイルを用意します。
※今回は新規モデル作成ではなく、既存モデルの紐付けの為、追加という形になります。
※新規にモデルを追加される方は下記コマンドで関連づけるモデルを作成いただければと思います。
"rails g model モデル名(単数形) user:references name:string"
■以下コマンドの実行
$ rails g migration add_user_id_to_uploads user:references
すると次のようにマイグレーションファイルが作成されます。
class AddUserIdToUploads < ActiveRecord::Migration[5.2]
def change
add_reference :uploads, :user, foreign_key: true
end
end
問題なく、作成されていたら、"rails db:migrate"を実行してください。
これでUploadモデルとUserモデルがuser_idカラムを通じて紐付いた関係となりました。
次にmodelの編集を行います。
class Upload < ApplicationRecord
belongs_to :user <!--追記-->
mount_uploader :image, ImagesUploader
validates :title, presence: true
validates :image, presence: true
validates :body, presence: true
end
class User < ApplicationRecord
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable, :trackable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable,
:validatable, :lockable, :timeoutable
# ,:confirmable,
has_many :uploads, dependent: :destroy <!--追記-->
end
こちらの記述でUserを消すと紐づいているUploadモデルのデータも削除されるようになります。
2. 権限設定を行う
deviseにはログインしていない場合、トップ画面に戻すという機能がデフォルトで実装されています。 その機能を実装したいControllerの上部に下記記述をしてください。class UploadsController < ApplicationController
before_action :authenticate_user! <!--追記-->
<以下省略>
これで、ログインしていないとアルバムページにアクセス出来なくなりました。
次にAのユーザが投稿したアルバムはAしか閲覧が出来ないという設定をコントローラに記述していきます。
class UploadsController < ApplicationController
before_action :authenticate_user!
before_action :set_upload, only: [:show, :edit, :update, :destroy]
before_action :validate_user, only: [:show, :edit, :update, :destroy]
<!--追記 下部のprivateメソッドの内容をshow, edit, update, destroyに反映させます。-->
def index
@uploads = current_user.uploads.order(created_at: :desc)
end
<!--こちらの記述により、一覧画面ではAが投稿したデータはAにしか表示されなくなります。-->
def show
end
def new
@upload = Upload.new
end
def edit
end
def create
@upload = Upload.new(upload_params)
@upload.user_id = current_user.id
<!--作成した画像にuser_idを持たせ、current_user.idと結びつけます-->
respond_to do |format|
if @upload.save
format.html { redirect_to @upload, notice: 'Upload was successfully created.' }
format.json { render :show, status: :created, location: @upload }
else
format.html { render :new }
format.json { render json: @upload.errors, status: :unprocessable_entity }
end
end
end
<以下省略>
private
def set_upload
@upload = Upload.find(params[:id])
end
def upload_params
params.require(:upload).permit(:image, :title, :body)
end
def validate_user
if @upload.user != current_user
redirect_to uploads_path, alert: "自分の投稿ではありません"
end
end
<!--こちらのvalidate_userの記述でURLからの不正アクセスを拒否します。-->
end
以上で、記述は終了となります。
まとめ
1.Userモデルと各種モデルを紐付ける(今回はUploadモデルが例でしたが、他投稿機能などがあれば、それに使用しているモデルも紐づける) 2.紐付け後にコントローラ側でアクセス権限を設定する権限設定はもっと複雑な記述が必要になると思いましたので、
意外とシンプルな形で実装出来て驚きました。
是非お困りの方は参考にしていただければと思います。