約3ヶ月のインターンを終えて

インターファームでの約3ヶ月インターンをしておりました平川です。
本日はインターン最終日ということで、ブログを書かせていただきます。
技術面としてgoogleアカウント認証についてと、インターンを経て考えたことの2つを書きたいと思います。

- googleアカウント認証について

googleアカウントだけでなく、TwitterFacebookも似たような流れで実装できるという事で、自分なりのまとめとして書かせていただきます。
今回は管理画面にgoogleアカウント認証機能をつけたので、それに沿って書いていきます。

googleアカウント認証を用いたログインの流れ

googleアカウントサインイン→webアプリケーションの許可→webアプリケーションへのログイン
Twitterのクライアントアプリの初回起動時、認証画面があるなあと思っていたのですが、あの過程は上記の流れと同様だと教えていただき、とても納得しました。

・実装ーRails

まずはgem の設定…
devise, omniauth,omniauth-google-oauth2を入れます
Gemfile

gem 'devise' 
gem 'omniauth'
gem 'omniauth-google-oauth2'

ターミナルにて

$ bundle install
$ rails g devise:install
$ rails g devise admin
$ rails g migration add_omniauth_to_users

deviseのインストールと、deviseを用いてAdminモデルを作成しました。
既存のコードを編集していることで起こったですが、
既にdeviseが入っていたため、deviseが再インストールになりました。
その結果、設定が追加され、一時的に管理画面がおかしくなってしまいました。
ここは $ rails g devise:install がいらなかったんですね。
$ rails g devise admin も既存のものがあったためいりませんでした。

続いて必要なカラムを追加します。
今回はuid,provider,nameです。
db/migrate/2014...add_omniauth_to_admins.rb

class AddOmniauthToAdmins < ActiveRecord::Migration
  def change
    add_column :admins, :uid,      :string, null: false, default: "";
    add_column :admins, :provider, :string, null: false, default: "";
    add_column :admins, :name,     :string

    add_index :admins, [:uid, :provider], unique: true
  end
end

migrationを書き加えたため、上記を反映させるために
ターミナルにて

$ rake db:migrate

を実行します。

Sequel Proにて確認。カラムが追加されていました。

adminモデルでOmniAuthを有効にします。
app/models/admin.rb

class Admin < ActiveRecord::Base 
  # Include default devise modules. Others available are: 
  # :token_authenticatable, :confirmable,
  # :lockable, :timeoutable and :omniauthable 
  devise :database_authenticatable, :registerable, :recoverable, :rememberable, :trackable, :validatable, :omniauthable
end

カラム追加をしていたので、attr_accessible にuid,provider,nameを追加します。

# Setup accessible (or protected) attributes for your model
  attr_accessible :avatar, :email, :first_name, :first_name_kana, :last_name, :last_name_kana,
    :nickname, :password, :password_confirmation, :remember_me, :name, :provider, :uid


続いて、コントローラーを作成します。
app/controllers/admins/omniauth_callbacks_controller.rb

class Admins::OmniauthCallbacksController < Devise::OmniauthCallbacksController
  def google_oauth2
	@admin = Admin.find_for_google_oauth2(request.env["omniauth.auth"])
    if @admin!=nil
      set_flash_message(:notice, :success, :kind => "Google") if is_navigational_format?
      flash[:notice] = I18n.t "devise.omniauth_callbacks.success", :kind => "Google"
      sign_in @admin, :event => :authentication
      redirect_to admins_entries_path
    else
      session["devise.google_data"] = request.env["omniauth.auth"]
      redirect_to admins_entries_path
    end
  end
end

redirectでは管理画面でログインしたときに表示されているページに設定しました。
request.env["omniauth.auth"]には、ハッシュとしてレスポンスされている情報が入っているとのことで…それを用いて
adminモデルに戻ってメソッドを設定します。
app/models/admin.rb

  def self.find_for_google_oauth2(auth)
    admin = Admin.where(email: auth.info.email).first
    unless admin
      if Mail::Address.new(auth.info.email).domain == "interfirm.co.jp"
        admin = Admin.create!(
                         name:     auth.info.name,
                         last_name: auth.info.last_name,
                         first_name: auth.info.first_name,
                         last_name_kana: "",
                         first_name_kana: "",
                         nickname: "",
                         provider: auth.provider,
                         uid:      auth.uid,
                         email:    auth.info.email,
                         password: Devise.friendly_token[0, 20])
      end
    end
    admin
  end

今回、インターファームのアドレスのみが認証の対象となるようにしました。
最初は.domainなるものがある事を知らず、アドレスの最後から14文字が一致するかどうかという力技で判断しようとしていました…。
createする際は、バリデーションに沿って必要な値をとれるようにしました。
こちら側で指定したカラムについては空欄で設定しています。
エラー画面でハッシュ値がなにかを調べられるのは非常に便利ですね…!

googleのDeveloperConsoleにて、IDとSECRETが発行されるので、それを設定します。
ここはaplication.ymlにて環境変数として書きました。
config/initializers/devise.rb

  # API key
  config.omniauth :google_oauth2, ENV['APP_ID'], ENV['APP_SECRET']

config/application.yml

APP_ID: "取得したID"
APP_SECRET: "取得したSECRET"

まだ発行してなかったのでこの後入力しました…

最後に!サインインボタンを作りました。
app/views/admins/sessions/new.html.erb

<%=link_to 'Googleアカウントでサインイン', admin_omniauth_authorize_path(:google_oauth2),id:"g_Text" %>

よく見かけるボタン、コードが提供されているんですね。

・実装ーGoogle Developer Console

Google Developer Consoleにログインして、プロジェクト名を決めます。
APIと認証のAPIにて、
Contacts APIGoogle+ API
を有効に。
認証情報にて新しいクライアントIDを発行すると、IDとSECRETが出てきます。
それを上記のapplication.ymlに入力して…
できました!

試行錯誤しながら、沢山教えていただきながら、認証までたどりつけました。

- インターンを経て考えたこと

現在大学3年の私から見て考えてみた事です…。

・自分の知識や力

大学の勉強だけで身についた知識と力って、本当に少なくて、
エンジニアは自ら学んでいくことが大切だと思いました。
知らない事が沢山あることは分かりきった事ですが、いざ目の前にしてみないとその「知らない事」の大きさが分からないな、と。

・仕事にしたいかどうか

私自身の話になりますが、エンジニアを目指したいとは思っていても、実際にどんな業務をしたいのかは明確に決まっていませんでした。
インターンで実際の会社の業務に携わらせてもらって、自分が思っていたよりも考えなければいけないことは沢山あると思いました。
どんな色や形、動作など、よく考えてお話をして、作り上げていくことは、実際にやってみないとその大変さも楽しさも分からないですね。
私のように、ふわっとしか決まっていない人ほど、インターンに参加した方が良いとおもいます。
目指すものをしぼっていくのに、自己分析や性格診断もよいですが、実際に手を動かすのが一番ですね。