kent備忘ログ

お仕事と趣味生活と

1月の学習振り返り(selfキーワード復習、devise、OmniAuth)

1月に取り組んだ学習を振り返りです。先月に続いてRailsのWebアプリ制作でしたが、実装を通してrubyの文法の再確認やRailsの仕組みについて新しく学んだことが大半でした。

1月上旬

まず始めに、ruby学習時から曖昧にしてしまっていたselfキーワードについて学び直しました。
  • selfキーワードはレシーバ自身を表し、省略する事ができる。
    • インスタンスメソッド内で定義された場合はクラスのインスタンスそのものを表す。
    • クラスメソッド内で定義された場合はクラスそのものを表す。

当初、アクションのビジネスロジックをモデルファイルを使用せず、全てコントローラ上に記述していた為、コントローラ上のコード量が多過ぎになり、Rubocop先生からも怒られていましたが、selfキーワードを理解し、モデルファイルにビジネスロジックを移動させることで、コントローラ上のコードをすっきりさせる事ができました。

coupon.rb

# クーポンモデルのis_validカラムのbooleanをtrueからfalseにする
  def nullification
    return unless is_valid? # 値が既にfalseの場合は変更せず戻る

    update!(is_valid: false)
  end
続いて、表示されているビューと対応するアクションの場所についての復習になりました。

課題で3つの項目を1ページ内に表示させているレイアウトでしたが、当初、モデルのDBを更新・取得させるアクションはそのモデル名のコントローラ内でアクションを記述するものであると思い込んでおり、案の定、意図した通りに表示されず、どのアクションがどのビューに対応するのか学び直しとなったきっかけでもありました。

shopping_cart_controller.rb

class ShoppingCartController < ApplicationController
def index # 一つのインデックスの中に多数のインスタンスを記述。
  @shopping_cart_items = ...
  @total_price =...
  @discount_price =...
  @payment =...
end
if文を用いた条件分岐が増えてきた中で、コード記述量を減らす為、「&.」通称ぼっち演算子を学びました。

&.を使用することで、メソッドのレシーバの値がnilとなる場合でもエラーが発生しなくなります。 Ruby on Rails 5速習実践ガイドより

shopping_cart_controller.rb

class ShoppingCartController < ApplicationController# paymentがnilであってもエラーにならない
      @code = payment&.code
      @rate = payment&.rate
end

他にもテーブルへの一意性制約の設定に一度モデルのindexの作成が必要であることや、boolean型のカラム以外でも、モデルファイルにenum型を使用して真偽値を設定する方法を学びました。

coupon.rb

  enum status: { '有効': 0, '無効': 1 }

  def nullification
    return unless status == '有効'

    update!(status: '無効')
  end

schema.rb

    t.string "code", null: false
                  ︙
    t.index ["code"], name: "index_discounts_on_code", unique: true

プロモーションコード機能の表示・適用処理を追加できたので課題提出→LGTMを頂けました。

1月中旬

1月中旬からは次の課題に移りました。
今回はsns型のアプリの為、ユーザ登録・ログインにdeviseのgemを使用しました。そもそも触った事が無かったので、いざdeviseの仕組みから理解していこうと思いましたがとても奥が深いです。
未だ全てを理解出来ていませんが、わからないながらも手を動かして実装していく内に、既にユーザー管理に必要なアクションはgemで管理されており、恐ろしく簡単にユーザー登録・管理機能を実装できる事がわかりました。

その中でも当時の私自身のXポストでもdeviseで簡単にユーザ管理機能が実装できる理由として、

  • Deviseの実体はApplicationControllerにモジュールとしてincludeされている。
  • Deviseで作成したモデル(scope)のcontrollerは、本家Deviseの機能を継承している。
  • controllerのメソッドをコメントアウトしてオーバライドすればアクションをカスタマイズ出来る。

とざっくりと表現していました。

一方でフロント側になるビューでは初めてerbではなく、Railsのテンプレートエンジンであるslimを使用した実装を行いました。

erbだけしか使用した事が無かった最初は、使いにくいと感じていましたが、それでも使い続ける内にそもそものコード記述量が低いのもあり、だんだんと簡潔にコードが書けることにメリットを感じる事ができました。

_post_form.html.erb

        <%= f.text_area :content, class: "form-control border-0 shadow-none bg-light", placeholder: "いまどうしてる?"%>
          <div class=d-flex justify-content-between mx-4 mb-2>
            <i class=bi bi-image>
              <div class=actions>
                <%= f.submit "ポストする", class: "btn btn-outline-secondary rounded-pill" %>
              </div>
            </i>
          </div>

_post_form.html.slim

        = f.text_area :content, class: "form-control border-0 shadow-none bg-light", placeholder: "いまどうしてる?"
        .d-flex.justify-content-between.mx-4.mb-2
          i.bi.bi-image
          .actions
            = f.submit "ポストする", class: "btn btn-outline-secondary rounded-pill"

1月下旬

通常のログインの他に、他webサービスの認証機能を利用したOAuthについて学びました。
  • deviseにおけるOAuthに役割を持つgemは'OmniAuth'になります。
  • 解説はdeviseのGitHub wikiが参考になります。

OmniAuth自体、各Webサービスの認可に対応したgemを配布しています。
OmniAuth List-of-Strategies

今回は、GitHubを利用した認証を導入しました。今回初めて各Webサービスの開発者ページにアクセスしましたが、実際にOAuth認証機能の編集画面が用意されていたことにも驚きました。

omniauth_callbacks_controller.rb

# devise wikiより引用(実際は各Webサービスに応じてカスタムして使用)
  
class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController
  # See https://github.com/omniauth/omniauth/wiki/FAQ#rails-session-is-clobbered-after-callback-on-developer-strategy
  skip_before_action :verify_authenticity_token, only: :facebook

  def facebook
    # You need to implement the method below in your model (e.g. app/models/user.rb)
    @user = User.from_omniauth(request.env["omniauth.auth"])

    if @user.persisted?
      sign_in_and_redirect @user, event: :authentication # this will throw if @user is not activated
      set_flash_message(:notice, :success, kind: "Facebook") if is_navigational_format?
    else
      session["devise.facebook_data"] = request.env["omniauth.auth"].except(:extra) # cookieのオーバフロー対策
      redirect_to new_user_registration_url
    end
  end

deviseを使用したユーザ登録・ログイン機能の追加・各Webサービス(今回はGitHub)を利用した認証ログインを追加できたので課題を提出→LGTMを頂けました。