Rails5対応 自分だけログインできる環境を作る
devise gemを使うことで簡単にログイン環境と認可機能を実装できますが、自分しか使わない個人のアプリだけどHerokuにアップするから他の人がeditとかnewのページに入れないようにしたいぐらいだと、gem使うよりも独自に実装するほうが簡単だったのでご紹介。
参考サイト
ほとんど、このブログ記事を参考にしました。Ruby on Rails3.2でログイン機能を実装する。
準備
Gemfileに書かれているがコメントアウトされている bcrypt
gem を有効にします。パスワードの暗号化に必要です。
# Gemfile
gem 'bcrypt', '~> 3.1.7'
そして、 bundle install
をして準備完了。
Userモデル作成
まず、Userモデルを作ります。
$ rails g model user name:string password_digest:string
$ rails db:migrate
次にできたUserモデルファイルを変更
# app/model/user.rb
class User < ApplicationRecord
has_secure_password
validates :password, presence: true, length: { minimum: 8 }
end
これでさっき入れたbcrypt gemが使われます。
データ作成
そして、アカウント追加
$ rails c
irb(main):001:0> User.create!(name: "admin", password: "hogehoge", password_confirmation: "hogehoge")
passwordはハッシュ化された値で保存されます。
Sessionコントローラ作成
ログイン環境のsessionコントローラを生成
$ rails g controller sessions
ルートに追加
# config/routes.rb
resources :sessions, only: %i(new create destroy)
コントローラ実装
# app/controllers/sessions_controller.rb
class SessionController < ApplicationController
def new; end
def create
user = User.find_by(name: params[:name])
if user && user.authenticate(params[:pass])
session[:user_id] = user.id
redirect_to root_path
else
flash.now.alert = "該当するデータがありませんでした"
render :new
end
end
def destroy
session[:user_id] = nil
redirect_to root_path
end
end
Viewでログインフォームを作る
# app/views/sessions/new.erb
<h1>ログイン</h1>
<%= form_tag sessions_path do %>
<div class="field">
<%= label_tag :name, 'login name' %>
<%= text_field_tag :name, params[:name] %>
</div>
<div class="field">
<%= label_tag :pass, 'password' %>
<%= password_field_tag :pass , params[:pass]%>
</div>
<div class="actions">
<%= submit_tag "ログイン" %>
</div>
<% end %>
これで、createするときにセッション情報をブラウザのCookieに追加する。
ヘルパーメソッド追加
ヘルパーメソッドでログイン情報を取得できるようにします。
# app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
protect_from_forgery with: :exception
helper_method :current_user
def current_user
@current_user ||= User.find(session[:user_id]) if session[:user_id]
end
end
ログインリンクを追加
ログインへのリンクを置きたいViewに以下のコードを追加します。
<% if current_user.nil? %>
<%= link_to "ログイン", new_session_path %>
<% else %>
<%= link_to "ログアウト", session_path(current_user.id), method: :delete, data: { confirm: 'ログアウトしますか?' } %>
<% end %>
Controllerでログインしていないユーザをはじく
ログインしているユーザしかアクセスできないようにする場合には該当の controller の before_action で指定してあげます。 次のコード例は posts_controller の new edit create update destroy アクションへのアクセスをログインユーザのみに制限する場合です。ログインしていない場合は root_path へ redirect させます。
# app/controllers/posts_controller.rb
class PostsController < ApplicationController
before_action :login_check, only: %i(new edit create update destroy)
before_action :set_post, only: %i(show edit update destroy)
def index
@posts = Post.all
end
def show; end
def new
@post = Post.new
end
def edit; end
def create
@post = Post.new(post_params)
respond_to do |format|
if @post.save
format.html { redirect_to @post, notice: 'Post was successfully created.' }
format.json { render :show, status: :created, location: @post }
else
format.html { render :new }
format.json { render json: @post.errors, status: :unprocessable_entity }
end
end
end
def update
respond_to do |format|
if @post.update(post_params)
format.html { redirect_to @post, notice: 'Post was successfully updated.' }
format.json { render :show, status: :ok, location: @post }
else
format.html { render :edit }
format.json { render json: @post.errors, status: :unprocessable_entity }
end
end
end
def destroy
@post.destroy
respond_to do |format|
format.html { redirect_to posts_url, notice: 'Post was successfully destroyed.' }
format.json { head :no_content }
end
end
private
def login_check
if session[:user_id].nil?
redirect_to root_path
end
end
def set_post
@post = Post.find(params[:id])
end
def post_params
params.require(:post).permit(:title, :content)
end
end