moxt

Just another Blog site

意識低いRuby on Rails再入門5

      2015/07/03

http://railstutorial.jp/chapters/sign-in-sign-out?version=4.0#top

この辺を読んだメモ。

Controllerに書かれたモデル系のロジックをHelperに切り出す

Controllerに書くのがなぜ悪いのだろう。。
と、はじめは思う。

正直『その追加する処理が1行程度なんだけど。。』とかであれば、Controllerにはモデル系のロジックを書いてはいけない!!!と、神経質にならずに書いちゃっても良いと思う。

ただ、その追加する処理があらゆるControllerで使われるとか、行数が複数行になりそうといった場合はモデルの中に押し込むか、HelperやDecoratorに押し込めないか検討する。

仮にモデルやHelperに処理Aを押し込んでおくと、その処理Aが変更になったとしても処理Aの中身を変えれば処理Aを参照してる箇所全てに変更が反映される。
処理AをいろんなControllerにベタ書きすると、処理Aを変更するときにあらゆるControllerを書き直す必要がある。
書き換え作業が面倒だし、あるControllerで書き換えをミスったためにバグが出てしまった、なんてことが想像できる。
共通する処理はどこかに集約することで変更に強くなる。
一方で、集約しすぎると複数人が1つのクラスを同時に編集することが起きる。
すると、gitなどを使ってる場合コンフリクトが発生することが想像できる。
この辺のバランスやテクニックについてまだまだ自分の中で確立できてないので学びの余地がある。

それから単純にControllerの中で処理がベタ書きされているとコードの見通しが悪くなる。
Controllerの外に追い出せるなら追い出したいし、それが難しそうであれば処理をメソッド化してベタ書きされた『どうやるか』コードを、メソッドの呼び出しに変更して『なにをしているか』に変えてゆくと見やすくなる。

前回SessionsControllerというログイン系を管理するControllerを書いた。こんな感じ。

このsign_inをhelperに委譲する。
SessionsHelperにsign_inというメソッドを追加する

Controllerに書いてた処理をSessionsHelperにコピペしただけ。

これでログイン処理をControllerから分離できた。

ログイン状態であるか確認したい

ログインの処理はできた。
何度か触れているが、ウェブアプリを作っているとログインが必須な画面やアクションと遭遇する。
それらを対応するたびにログイン画面を表示させられて、必要な情報を入力することをユーザ側は煩わしいと思う。
なので、セッションという手形情報を追加した。

ログイン状態が必須な画面・アクションではセッションの状態を確認する処理が必要になる、ということが分かると思う。
そうするとログイン状態が必要な何かしらのControllerの中でCookieのremember_tokenを引っ張ってきて、

こんな感じの照合作業を行う必要がある。

ログインが必要な様々な画面で↑のような処理を書くのは煩雑だろう。

この辺りの処理をSessionsHelperに任せられないだろうか。

def sign_in?
User.find_by(remember_token: cookies[:remember_token]).nil?
end

こんな感じ。

これで、sign_in?をController内で呼べるようになった。
ログイン状態の確認が必要なControllerにinclude SessionsHelperと書けばsign_in?を呼び出せる。

いちいちControllerにinclude SessionsHelperを書くのも面倒だ、という場合は

  • ApplicationControllerでinclude
  • LoginRequiredControllerみたいなモノを作って、その中にSessionsHelperをincludeしログインが必要なControllerはLoginRequiredControllerを継承するようにする

などなど、楽にするやり方はいろいろあると思うのでやってみるとよい。

メモ化を使ってログイン状態の確認を少し効率化する

先ほどSessionsHelperに追加したsign_in?メソッドは毎回find_byを呼び出している。
特にキャッシュしていない限りは毎度DBにアクセスしている、ということだ。

  • ログイン状態であるか確認する
  • ログイン状態であればユーザの名前を表示する

このような2つの処理をController内で行うと、Userを探す処理を2回実行することになる。
一度取得したUserを使い回すと効率は良さそうだ。

『メモ化』という方法を使うと良いらしい。

SessionsHelperに次のようなメソッドを追加する。

current_userを呼ぶと@current_userの値が返ってくる。
@current_userはSessionsHelperのインスタンス変数ではなく、includeしているControllerのインスタンス変数、という扱いになる。

このcurrent_userをつかってsign_in?を次のように書き換える。

参考元だと要素代入を利用したコードになってる。

 - プログラミング

  • このエントリーをはてなブックマークに追加
  • follow us in feedly

  関連記事

no image
Python(Anaconda)とOpenCVを使って動画から顔画像を抽出してみる

今話題のディープラーニングをやってみたい。 いろいろ見た感じCaffeというフレームワークが良さそう。 …

no image
iOSアプリの設計ってどうやるの?

ViewControllerに処理を詰め込みすぎて保守が大変になるのはあるあるネタですよね。 じゃあ、ViewControllerでやることってなんだろうって問われると、まあ、こんなんだろうなってフワッとしてる。 …

ReactとFluxとReduxについて順を追って整理する

書き途中 Contents1 …

Docker Machineのメモ

随時追記する Contents1 …

ReactなComponent同士を連携させたい

実践的なサンプルに塗れてなんとなく使ってると破綻する。 分かってること、分かってないことを整理しておきたい。 …

no image
goで無限ループ

しょうもないが忘れるので。。

no image
意識低いRuby on Rails再入門6 ~ログイン必須のControllerを作りたい~

ログイン状態を取得するためのSessionsHelperを前に書いた 新規投稿画面を表示したり、実際に投稿するときにはログイン必須であることを保証したい。 …

no image
SeleniumでChromeを自動操作したい

Seleniumという便利なソフトウェアがあります。 これはブラウザ上の操作をスクリプト化し自動化することを目的としています。 …

Ruby,Railsのチートシート

こういうのブログ形式じゃなくてwikiの方が良いのでは。。 と、遠い目をしつつ。 …

no image
SwiftでOSのバージョンが8.0.0以下とそれより大きいヤツで処理を分岐させたい

前置き push通知のデバイストークン取得方法がiOS8から変わりました。 …