0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Sinatra環境で簡易ログイン機能を実装

Last updated at Posted at 2022-09-13

はじめに

掲示板を作成する中でログイン機能を実装する必要がある場合があるので、初心者でも理解しやすい簡易的なログイン機能の作り方をまとめることにした。

開発の概要

アカウント作成時にusersテーブルにログインIDとパスワードを保存し、ログイン時に一致するものがあればログイン成功とする。ログイン情報はCookieに保存し、ページを切り替えてもログインが維持されるようにする。

必要なファイル

マテリアル内のbbsを複製しbbs_loginとして使用
これ以降、bbs_loginをルートフォルダとして進める

usersテーブルの作成

まずconfig/database.yml内のデータベース名を変更する(これをしないと、掲示板を既に作っている場合データベース名が被って正しくデータベースの作成ができない)

config/database.yml
default_env: &default
  adapter: postgresql
  encoding: unicode
  database: bbs_login #変更

development:
  <<: *default

production:
  <<: *default

  
データベース名を変更後、データベースを作成

bash
$ rake db:create

  
マイグレーションファイルを作成

bash
$ rake db:create_migration NAME=create_users

  
マイグレーションファイルを編集
必要なのは表示名、ログインid、パスワードの3つ
カラム名はそれぞれ name, login_id, passとする。

db/migrate/xxxxxxxxxxxxxx_create_users
class CreateUsers < ActiveRecord::Migration[6.1]
  def change
    create_table :users do |t|
      t.string :name
      t.string :login_id
      t.string :pass
    end
  end
end

  
マイグレーションを実行

bash
$ rake db:migrate

  
マイグレーション実行後のschema.rb(確認)

db/schema.rb
ActiveRecord::Schema.define(version: xxxx_xx_xx_xxxxxx) do

  create_table "users", force: :cascade do |t|
    t.string "name"
    t.string "login_id"
    t.string "pass"
  end

end

Userモデルの作成

初期状態ではcontribution.rbというファイルになっているので、これをuser.rbに変更する
「ファイル名を変更」で行ってもいいが、ターミナルを用いて変更する場合には以下のコマンドを実行する。

bash
$ mv models/contribution.rb models/user.rb

  
ファイル名を変更することができたら、ファイル内のクラス名も変更する。

models/user.rb
ActiveRecord::Base.establish_connection
class User < ActiveRecord::Base #変更

end

  
app.rbで読み込むファイル名も変更しておく。

app.rb
require 'bundler/setup'
Bundler.require
require 'sinatra/reloader' if development?

require "./models/user.rb" #変更

  
以上でusersテーブルおよびUserモデルの作成が完了した。

アカウント作成画面の作成

~amazonaws.com/signupでアカウントを作成できるようにする。
まずはapp.rbでルーティングし、テンプレートファイルとしてsignup.erbをレンダリングする。

app.rb
get "/signup" do
  erb :signup
end

  
続いてindex.erbを複製しsignup.erbを作成。ターミナルを用いて実行する場合はcpコマンドを用いる。

bash
$ cp views/index.erb views/signup.erb

  
signup.erbにアカウント作成用のフォームを作成。POSTリクエストの送信先は/signupとする。
inputタグの属性を複数用いているので、詳しくは以下のサイト等を参照。

views/signup.erb
<!--略-->

<body>
  <form action="/signup" method="post">

    <label>ユーザー名</label>
    <input type="text" name="name" required>

    <label>ログインID(8文字以下、英数字で入力してください)</label>
    <input type="text" name="login_id" maxlength="8" pattern="^[0-9A-Za-z]+$" required>

    <label>パスワード(16文字以下、英数字で入力してください)</label>
    <input type="text" name="pass" maxlength="16" pattern="^[0-9A-Za-z]+$" required>

    <button type="submit">アカウント作成</button>

  </form>
</body>

<!--略-->

アカウント作成機能の実装

app.rbにリクエスト送信時の処理を記述する。
ユーザー名およびパスワードの被りは問題ないが、ログインIDの被りは許容することができないので、既に使われているログインIDを入力した場合はデータベースに登録せずに/signupへリダイレクトするようにした。

  • find_by
    テーブル内のレコードから条件に一致するものを探し、見つけた場合ひとつだけ返し、見つからなかった場合はnilを返す。今回はlogin_idparams[:login_id]と一致するレコードを探している。

  • nil?
    値がnilである場合にはtrueを返し、それ以外の場合はfalseを返す。

app.rb
post "/signup" do

  if User.find_by(login_id: params[:login_id]).nil?
        User.create({
            name: params[:name],
            login_id: params[:login_id],
            pass: params[:pass]
        })
        redirect "/"
    else
        redirect "/signup"
    end

end

ログイン画面の作成

今度は/loginでログインできるようにする。先程同様app.rbでルーティングを行い、テンプレートファイルとしてlogin.erbをレンダリングする。

app.rb
get "/login" do
  erb :login
end

  
index.erbを複製してlogin.erbを作成。

bash
$ cp views/index.erb views/login.erb

  
login.erbにログイン用のフォームを作成。リクエストの送信先は/loginとする。

views/login.erb
<!--略-->

<body>

  <form action="/login" method="post">

    <label>ログインID</label>
    <input type="text" name="login_id" required>

    <label>パスワード</label>
    <input type="password" name="pass" required>

    <button type="submit">ログイン</button>

  </form>

</body>

<!--略-->

ログイン機能の実装

まずsessionの保存先としてcookieを使用するためにapp.rbに以下の記述をする。

app.rb
require 'bundler/setup'
Bundler.require
require 'sinatra/reloader' if development?

require "./models/user.rb"
use Rack::Session::Cookie #新たに追加

  
続いてリクエスト送信時の処理を書く。
checkという変数を用意し、フォームに入力されたlogin_idと値が一致するレコードがあればこの変数に格納するようにした。続くif文で、もしcheckが空でなければcheck.passparams[:pass]を比較し、さらにこれが一致していればsession[:user]checkを格納しcookieに保存している。また、フォームに入力されたlogin_idと値が一致するレコードが存在しないか、存在していたとしてもパスワードが間違っている場合は/loginにリダイレクトするようにした。

app.rb
post "/login" do

  check = User.find_by(login_id: params[:login_id])

  if check
    if check.pass == params[:pass]
      session[:user] = check
    else
        redirect "/login"
    end

end

ログイン状態の維持

ログインしているかどうかの判定をapp.rb内のbeforeブロックに記述する。ログインされている場合はsession[:user]@userに格納してテンプレートファイルに渡せるようにする。

app.rb
before do

  if session[:user]
    @user = session[:user]
  end

end

ログアウト機能の追加

views/index.erb
<!--略-->

<body>

  <a href="/logout">ログアウト</a>

</body>

<!--略-->
app.rb
get "/logout" do
  session[:user] = nil
  redirect "/login"
end

マイページの作成

先程までの内容で基本的なログイン機能が完成したので、後は追加の機能を作成していく。

app.rb
get "/" do

  if session[:user].nil?
    redirect "/login"
  end

  erb :index
end
views/index.erb
<!--略-->

<body>

  <!--新たに追加-->
  <h1><%= @user.name %>さんのマイページ</h1>

  <a href="/logout">ログアウト</a>

</body>

<!--略-->

投稿機能の実装

bash
$ rake db:create_migration NAME=create_contributions
xxxxxxxxxxxxxx_create_contributions.rb
class CreateContributions < ActiveRecord::Migration[6.1]
  def change
    create_table :contributions do |t|
      t.string :body
      t.integer :user_id
    end
  end
end

  
schema.rbは以下のように更新される。

schema.rb
ActiveRecord::Schema.define(version: xxxx_xx_xx_xxxxxx) do

  enable_extension "plpgsql"

  create_table "contributions", force: :cascade do |t|
    t.string "body"
    t.integer "user_id"
  end

  create_table "users", force: :cascade do |t|
    t.string "name"
    t.string "login_id"
    t.string "pass"
  end

end

  
Contributionモデル及びアソシエーションを作成。ユーザーと投稿は一対多の関係になってる。

models/user.rb
ActiveRecord::Base.establish_connection
class User < ActiveRecord::Base
    has_many :contributions
end

class Contribution < ActiveRecord::Base
    belongs_to :user
end

  
投稿フォームの追加

views/index.erb
<!--略-->
    
<a href="/logout">ログアウト</a>

<!--新たに追加-->
<form action="/new" method="post">

  <input type="text" name="body" placeholder="投稿内容">
  <button type="submit">投稿</button>

</form>
<!--ここまで-->

<!--略-->

  
リクエストに対する処理を追加する。アソシエーションの記述をしているため、通常ではContribution.createとするところを@user.contributions.createとしており、これによってuser_idには自動で投稿したユーザーのアカウントのidが入る。

app.rb
get "/new" do
  @user.contributions.create({
    body: params[:body]
  })
  redirect "/"
end

  
全投稿の表示(最新のものが上に来るように降順で並び替え)

app.rb
get "/" do
    
    if session[:user].nil?
        redirect "/login"
    end
    
    @contributions = Contribution.all.order("id desc") #新たに追加
    
    erb :index
end
views/index.erb
    </form>
    
    <!--新たに追加-->
    <% @contributions.each do |contribution| %>
    
      <div>
        <h3><%= User.find(contribution.user_id).name %></h3>
        <p><%= contribution.body %></p>
      </div>
    
    <% end %>
    <!--ここまで-->
    
  </body>

まとめ

今回はCookieを用いて簡易的なログイン機能を実装した。Ruby関連の記事はRails環境であることが多く、Sinatraに関連する記事が少ないと感じたのでもしよければ参考にして欲しい。また、本格的なログイン機能を実装する場合とも基本的な部分は共通しているので、has_secure_password等を用いたログイン機能の開発の礎となれば幸いである。

パスワードの暗号化に関しては以下のgithubを参照
https://github.com/bcrypt-ruby/bcrypt-ruby

0
1
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?