gem使わなくても簡単にできるrailsのtips
それgem使わなくてもできるよまとめ
gemは便利なのですが闇雲に入れるべきものでもありません。とくに用途が限られていて、わざわざgemを使うまでもないことや使用目的以上にgemが巨大な場合は簡単に自分で代替物を作ったほうがメンテナンスやコントロールが容易な場合もあります。
Devise
Deviseのような認証機構はシンプルなものであればこういったsessionにuser_idを格納するだけで十分です。
user.rb
class User < AR::Base has_secure_password end
session_controller.rb
if user.authenticate(params[:password]) sign_in(user) end
application_controller.rb
def sign_in(user) session[:user_id] = user.id end def sign_out session[:user_id] = nil end def current_user User.find_by(id: session[:user_id]) end def user_sign_in? !!current_user end
Railsのsessionはデフォルトではcookieに暗号化された値として保存されます。基本的にuser_idのような固有値を入れてもクライアント側では復号化できないはずです。(secrets.ymlの値があれば復号できると思います)
セキュリティ上の優先順位としては SSL通信にする、cookieにsecure属性を付与する ことが重要で、理想的にはcookie storeではなくmemcacheなどをサーバ側に用意することでより安全になります ^1
仮にDeviseの主要機能であるメール認証、パスワードリセット、ロックなどをすべて実装するにしても自分で作ってもさほど難しくない上保守性が高いのでオススメです。(というよりDeviseを使っても結局Deviseのコントローラをオーバーライドする羽目になる気がします)
friendly_id
user.rb
class User < AR::Base before_create :set_uuid private def set_uuid self.uuid = SecureRandom.hex(10) end end
routes.rb
get 'users/:uuid' => 'users#show', as: :user
users_controller.rb
def show @user = User.find_by(uuid: params[:uuid]) end
view.html.slim
= link_to user.name, user_path(user.uuid)
Railsのデフォルトである連番idが嫌な場合にfriendly idを使うケースがあると思いますが、単にルーティングをいじればいいのでこっちのほうが簡単です。 とりあえず適当な値が欲しいならSecureRandomを使えばまず大丈夫です。
secure randomで作った値を使うほうが権限チェックのミスがあっても漏洩リスクを多少緩和できると思います。
連番idのとき
/secure_photos/3
# 本当はcurrent_userから引っ張らないとダメ # current_user.secure_photos.find(params[:id]) # SecurePhoto.find(params[:id])
/secure_photos/7997a08d65b56628
SecurePhoto.find_by!(uuid: params[:uuid])
といっても本気でアタックする人にとっては意味がないのでしっかり権限チェックしてください。
Draper
Draperのすべての仕組みを理解していませんが、SimpleDelegatorを使うだけで十分な気がしています。
user_decorator.rb
class UserDecorator < SimpleDelegator def h1_title "#{name}のページ" end end
user.rb
include Decoratable
app/models/concerns/decoratable.rb
module Decoratable def decorate klass = begin "#{self.class.to_s}Decorator".constantize rescue NameError "#{self.class.base_class.to_s}Decorator".constantize end klass.new(self) end end
これだけで使う時は@user.decorate
とするだけでデコレータのクラスに変換されます。
この方法がいいのは自分でデコレータのクラスと生のモデルクラスをコントロールできる点、軽い点、適宜デコレータを増やしてdecorate
のメソッドを変えればモデルとデコレータを1対多対応させられる点にあります。
各viewやAPIごとにdecoratorを分割し、デコレータが必要な文脈ごとに変換をかけるのは少し手間ですが、暗黙に変換されると挙動がよくわからなくなることがあります。
画像アップロード
これは上記とは仕組みが違いますが、carrierwaveやminimagickを使わなくても画像をアップロードする仕組みは作れます。
簡単に言えば画像自体を受け取らず、アップロード先を別に持ってURLや識別子だけ受け取って保存すればいいのです。
Cloudinary
このようなサービスを使えば画像のストレージとサイズ変換などの面倒をすべて見てくれるので、gemでいえばcarrierwave, minimagick, fogあたりを省略できます。
まとめ
以上、少しやってみればgemを使わなくても労を少なく、下手をするとgemを使うより簡単に必要なことができることがあります。 gemを入れ過ぎるとgem同士がバッティングしたりバージョンアップに苦労します。もちろんgemのようにメンテナンスが繰り返されるソフトウェアには一定のメリットがあるので必要な局面では使うべきでしょう。例を上げればStateMachineは一見自分で実装可能なようで、ライブラリに依存したほうが確実に見通しがいいケースが多かったです(あくまで私の経験です)。