Try T.M Engineer Blog

多摩市で生息するエンジニアが「アウトプットする事は大事だ」と思って始めたブログ

BCryptLibを使ってログイン画面を実装

学びシリーズ第2弾です。

作ってみた機能

BCryptライブラリを使ってログイン画面を実装

環境構成

全体構成・完成イメージ

f:id:special-moucom:20180430175646p:plain

[DB]TABLE

 "managers" ("manager_name" varchar NOT NULL, "hashed_password" varchar NOT NULL)

プログラムコード等

Controller


class SessionsController < ApplicationController
  def create
    ss_manager = Manager.authenticate(params[:manager_name], params[:password])
    if ss_manager
      session[:manager_id] = ss_manager.id
    else
      flash.alert = "名前とパスワードが一致しません。"
    end
    redirect_to :root
  end

  def destroy
    session.delete(:manager_id)
    redirect_to :root
  end
end

createメソッドでは、画面で入力した名前とパスワードをauthenticateメソッドに渡して、名前とパスワードの一致確認を行います。authenticateメソッドは、後記にも記載しますが、Modelのクラスメソッドです。パスワードの一致確認ができたら、セッションIDを取得します。
destroyメソッドでは、createメソッドで取得したセッションIDを削除しています。

class ApplicationController < ActionController::Base
  private
  def current_manager
    Manager.find_by(id: session[:manager_id]) if session[:manager_id]
  end
  helper_method :current_manager
end

異なるController間で共通に使用するメソッドは、ApplicationControllerに定義します。
ここでは画面参照時にセッションIDの保有有無を判定するcurrent_managerメソッドを実装しています。画面参照時なので、HelperのようにViewで使いたい&DBへアクセスしたいという要件があるので、ControllerにあるメソッドをHelperのようにViewで使う事ができるhelper_methodを定義します。

Model


  class << self
    def authenticate(name, password)
      manager = find_by(manager_name: name)
      if manager && manager.hashed_password.present? &&
          BCrypt::Password.new(manager.hashed_password) == password
        manager
      else
        nil
      end
    end
  end

Modelのクラスメソッドauthenticateです。セッションは、仕組み上Modelを持ちません。
そのため、セッションからDBや外部サービスへアクセスする場合は、Model内にクラスメソッドを定義して、セッション内で使えるようにする必要があります。ここでは名前をキーにDBからパスワードを取得し、そのパスワードをBCryptで復号化して画面で入力したパスワードと一致確認をしています。

ERB


<% if flash.alert %>
  <p class="alert"><%= flash.alert %></p>
<% end %>

<%= form_tag :session do %>
  <table id="login_form">
    <tr>
      <td style="text-align: right">ユーザー名</td>
      <td><%= text_field_tag "manager_name", "", style: "width: 120px" %></td>
    </tr>
    <tr>
      <td style="text-align: right">パスワード</td>
      <td><%= password_field_tag "password", "", style: "width: 120px" %></td>
    </tr>
    <tr>
      <td colspan="2" style="text-align: center">
        <%= submit_tag "ログイン" %></td>
    </tr>
  </table>
<% end %>

<% if current_manager %>
  <p class="manager">
  <%= current_manager.manager_name %>さん|
  <%= link_to "ログアウト", :session,
    method: :delete, data: { confirm: "ログアウトしますか?" } %>
  </p>
<% end %>

form_tag :sessionを定義する事で、submit時にsessions#create(POST)メソッドを呼び出す事ができます。Controllerで定義したhelper_methodのcurrent_managerがここで使われています。セッションIDを保持している場合のみログアウトのリンクが出てくる様になっています。

学んだ事

Webアプリケーションで頻繁に使われるログイン・ログアウトの基本的な実装を学ぶ事ができました。helper_methodの定義方法についても勉強になりました。
次回は、このセッションIDを使ってどんな事ができるのか勉強していきたいと思います。

BCryptLibを使ってユーザー登録画面の実装

Railsについて、勉強を初めてみました。
いやぁ、勉強してみて実感しますが、本やブログ記事等の解説は簡単に書かいているのに、実際使ってみると「あれ?どうやるんだっけ?どういう仕組で動いているんだっけ?」と疑 問に思う事ばかりです。ちゃんと理解できているのか・・・不安でしょうがないです。
さて、まだまだ勉強中なのですが、Railsを使って学んだ事をブログ記事に残して置こうと思ったので、「学びシリーズ」(新コンテンツ?)というカテゴリーを設けて書いていきたいと思います。内容は主に、自分で小さな機能を作って、その振り返り記事がメインになると思います。豆知識や小技等、いわゆるTIPS的な事はQiitaに書いていきたいと思います。

作ってみた機能

BCryptライブラリを使ってユーザー登録画面を実装

環境構成

全体構成・完成イメージ

f:id:special-moucom:20180425015618p:plain

[DB]TABLE

 "managers" ("manager_name" varchar NOT NULL, "hashed_password" varchar NOT NULL)

プログラムコード等

Controller


class ManagersController < ApplicationController
  def new
    @manager = Manager.new
  end

  def create
     @crt_manager = Manager.new(params[:manager].permit(:manager_name, :password, :password_confirmation))
     # DBにデータ保存
     if @crt_manager.save
       render "show"
       p "登録が完了しました。"
     else
       render "new"
     end
   end

   def show
   end
end

newメソッドでは、Managerのインスタンス変数:@managerを生成しています。
createメソッドでは、newメソッドで宣言したインスタンス変数:@managerから画面で入力した名前とパスワード2つを取得しています。permitメソッドを呼ぶことでModelに余計な属性を保存させないようにする事が可能です。DBに入れる値を制限し、余計な属性をDBに保存させない事をストロング・パラメータと言います。その後は、名前と暗号化したパスワードをDB(SQLite)に保存して、show画面に遷移しています。

Model


class Manager < ActiveRecord::Base
  attr_accessor :password, :password_confirmation

  def password=(val)
   if val.present?
       self.hashed_password = BCrypt::Password.create(val)
   end
     @password = val
   end
end

ここではControllerのcreateメソッドで取得したパスワード(password)をBCryptライブラリを使って暗号化しています。
present?メソッドは「unless 変数.blank?」と同じ意味を持ち、変数が空かそもそも変数自体が存在しないかを聞いています。今回は、変数が空か変数自体が存在しない場合はスキップしています。なお、上記プログラムではpassword_confirmationの変数は参照しておらず、passwordのみ参照しています。

ERB


<p>ユーザー登録ページ</p>
<%= form_for @manager do |form| %>
  <table>
    <tr>
      <td style="text-align: right">ユーザー名</td>
      <td><%= form.text_field :manager_name, style: "width: 120px" %></td>
    </tr>
    <tr>
      <td style="text-align: right">パスワード</td>
       <td><%= form.password_field :password, style: "width: 120px" %></td>
     </tr>
     <tr>
       <td style="text-align: right">再パスワード</td>
       <td><%= form.password_field :password_confirmation, style: "width: 120px" %></td>
     </tr>
     <tr>
       <td colspan="2" style="text-align: center">
       <%= form.submit "登録" %></td>
     </tr>
   </table>
<% end %>

こちらはControllerのnewメソッドを通して表示されるERB画面です。newメソッドで作られた@managerとfrom_forタグを使ってフォームを生成しています。なお、show画面の説明は割愛します。

学んだ事

Webアプリケーションの基本である画面に入力した値をDBに保存するという流れを理解できた事。また、Rails 4.0から導入されたセキュリティ強化策の1つであるストロング・パラメータというのがある事を知りました。これだけの少ないコードで、これだけの機能を実装できるRailsってやっぱり凄いなと改めて実感しました。
ブログに書くこと。図にする事で、自分の理解も深まった気がするので、このコンテンツは引き続き続けていきたいと思います。

LINE Message APIとRubyを使って写真共有サービスのプロトタイプを作った話

今年の1月、中学時代の友人が結婚するとの連絡がありました。
何かでお祝いできないかなと思い、以前「結婚式でLINE Message APIを使った写真共有サービスを作った」というブログ記事を読んだ事を思い出し、同じマイクロサービスを作れないか考えました。

tomoima525.hatenablog.com

ブログ記事を書いた人は、そのマイクロサービスをPythonを使って実装していました。しかし、私にはPythonの知識が無かったので、趣味で勉強していたRubyを使って実装できないかを考えました。その時に考えた全体構成イメージは以下の様な感じです。

<全体構成イメージ>
f:id:special-moucom:20180408102427p:plain

動くものを作る事を優先にして、プロトタイプを作成

私は、LINE Message API、Heroku、Cloudinary、WebSocket、Git/GitHub等、全て初めて扱う超初心者です。
1つ1つの学習コストが大きいので、とにかく動くものを作ってモチベーションを保つ事を優先しました。そのため、当初フレームワークRailsを使う事を考えていましたが、Railsについての知識が十分では無かったのと、最初からRailsを使って実装すると構造が複雑になり、エラー等の原因分析が困難になると考え、まずはSinatraを使ってプロトタイプを作る事にしました。

1. プロトタイプ作成

  • クライアントサイド
    LINE Message API
    参考にさせて頂いたブログ記事にも書いていましたが、とにかくサンプルやドキュメントが充実していたので、殆ど迷うこと無く実装する事ができました。ちょうど「Heroku+Ruby+Sinatraでオウム返しするLINE Botを作った」という記事も見つけたので、こちらも大変参考にさせて頂きました。
    qiita.com

  • サーバーサイド
    Sinatra
    こちらもサンプルやドキュメントが充実していたので、殆ど迷うこと無く実装する事ができました。 RailsのようなMVCモデルを意識せずに作れるので、「とにかく動くものを作りたい」という私の希望にとても合っていました。後から調べてみると、アップル等でも使われている結構有名なフレームワークだったので驚きました。
    Heroku
    こちらも初めて使わせてもらいました。Herokuへのデプロイ方法は、GitHubへのデプロイ方法と変わらないので、とても使い易いです。Git/GitHubの使い方は不安があったので「わかばちゃん本」で学びました。SourceTreeを使えばデプロイ先を簡単に切り替えられるので、とても簡単に扱えました。
    kodak.hatenablog.com Cloudinary
    まさにこんなサービスがあったのか。と思ったサービスです。画像をアップロードするタイミングで加工できるので、携帯で撮った画像の解像度を抑える(ファイルサイズを縮小できる)事ができます。これによりファイルサーバーの容量を抑えたりレスポンス速度を向上できるので、この辺りは触っいてとても面白かったです。
    WebSocket
    一番苦戦したのが、このWebSocketです。Java Scriptを使って実装していますが、詳細な説明を記載している書籍が無かったので、ネットの情報だけを使って実装しました。ネットの情報は、具体例としてチャットを使って説明しているものが多く、ブラウザから入力した情報をトリガーにして、サーバーサイドで処理させるものが殆どでした。
    私が実装したかったのは、サーバーサイドの情報をトリガーにして、ブラウザに画像を表示させる事だったので、その方法についてはどこにも記述が無く、1つ1つトライ&エラーを繰り返して実装していきました。どこかのタイミングで記事に纏めたいですね。

2. プロトタイプの完成

約2ヵ月間、試行錯誤してRubySinatraフレームワークで「LINE Message APIRubyを使って写真共有サービスのプロトタイプ」を作る事ができました。
友人に見せた感じだと「LINEに送った画像が瞬時に表示されるのが良いね。」「工夫すれば、色々なところで使えそうだね。」等の感想を頂きました。

f:id:special-moucom:20180408102511p:plain

3. 今後のサービス改善に向けて

プロトタイプで満足せず、以下機能を実装していく予定です。

1) Railsを使って実装する
2) LINEグループを使った画像送信・表示を可能にする
3) アップロードした画像を振り返る機能を実装する

※ 3)は友人の意見で、今のままだと画像が下に流れてしまうので、振り返る機能を実装した方が良いとの助言をもらいました。

4. 作ったのはいいけど使えるの?

プロトタイプでも使えそうな気はしていますが、果たして反応はどうなのか。色々と気になる事はありますが、例え使われなくても、やってきた事は無駄にはならないですし、今回のプロトタイプ作りで個人的には大変勉強になりました。技術力の無いSEでも勉強すれば「こんなサービスが作れるぞ!」という自信にも繋がった気がします。
今後も、どんどん新しい事にチャレンジして自己研鑽していきたいと思います。

最後に

アイディア参考にさせていたtomoima525さんには、この場を通して感謝申し上げます。
なお、参考にさせて頂いたのはアイディアのみであり、ソースコードのコピー等は一切行っておりませんので、御認識ください。 今後ともブログでの御活躍、応援しております。

わかばちゃんと学ぶ Git使い方入門を読んでみた

わかばちゃんと学ぶ Git使い方入門〈GitHub、Bitbucket、SourceTree〉

わかばちゃんと学ぶ Git使い方入門〈GitHub、Bitbucket、SourceTree〉

ネットを見ていると良く見かけるGitやGitHubという単語。
クラウドを使ったバージョン管理ツールなんだろうなぁ…と勝手な想像をして、なんとなく適当な使い方をしていました。Git、GitHubを使い始めて1ヶ月が立ち、さすがにそろそろ理解しておいた方が良いと思ったので、この本を手にしました。

何故この本を選んだかと言うと、一応、仕事でSCC、CVSSVNと、色々なバージョン管理ツールに触れてきた経験があったので、ゆるーく理解できそうなこの書籍を購入しました。(漫画形式で解説してくれる技術本も珍しいなと思ったのも理由の一つです)

結論から言うと、買って良かったです。
ボリューム的には漫画のところは、2割程度で、ほとんど普通の技術書と変わりないです。
「あーしたいけど、どうすればいい?」「これってどういう意味なんだっけ?」等、わかばちゃんが疑問に思う箇所が、漫画になってる感じです。
内容的にもGit、GitHabを使う上で、必要なポイントは押さえている感じがしました。ただ、あくまで初心者向けで、ガッツリ理解したい人には、別の本が良さそうです。

この本は、SourceTreeと呼ばれるツールを使う事を前提にGit、GitHabの使い方を説明しています。
SourceTree自体の使い勝手は悪くなく、私もこの本を読んで初めてこのツールを使ってみましたが、ツール自体は良くできており、とても使い易かったです。
また、SourceTreeのUIベースでの説明・解説(しかも漫画付き)なので、初心者には非常に取っつき易く、楽しく読めるし、分かりやすいと感じました。
しかし、デメリットもあります。アップデート等でツールのUIが変わってしまうと読者側で読み変えないといけない。という問題が起きてしまう事です。なので、時間が経った後でこの本を読み返すのは辛いだろうなと思いました。

メリット、デメリットありますが、冒頭に書いたとおりトータル的には、買ってよかったですし、この本を通してGit、GitHabの基本的な使い方は理解できたと思います。
次のステップとして、以下を理解したいですね。
・commitの粒度
・commit時のコメントの書き方
・やっぱりGit、GitHabのコマンドベースでの使い方(ツールが使えない時も考えて....)

※commitの粒度については、以前伊藤さんが記事にしていたと思うので、こちらを参考にしたいと思います。

コミットはドラクエのセーブと同じ!?Qiitaに「適切なコミット粒度」に関する記事を書きました - give IT a try

ブログの(少し)リニューアル

ブログを少しリニューアルしました。

ブログ名は「川-かわ-」から「Try T.M Engineer Blog」に変わりました。
ブログ名を変えたのは「川-かわ-」だと意味が分からなかったからです(笑)
「"挑戦"、"試す"の意味を持つTry」と「多摩市在住なので、T.M」の2つのキーワードを入れたブログ名に変更しました。

リニューアルした理由


当初、ブログを立ち上げた時は、OUTPUTの練習用くらいにしか考えていませんでした。
しかし、実際にブログを書き始めて、自分のOUTPUTの下手さが浮き彫りとなり、このままではいけないと思ったのと、ちゃんとOUTPUTを残しておけば、自身の振り返りにも使えると改めて実感したからです。

他に変わったこと


OUTPUT強化のため、外への連携も増やしました。

・ Qiitaアカウントの登録、ブログとの連携
Twitterとブログの連携

これからも宜しくお願い致します。