Railsコールバック〜before_validationを使ってみた〜

  • 0
    いいね
  • 0
    コメント

    Railsでコールバックの一つであるbefore_validationについて勉強する機会があったので、まとめて見たいと思います。

    そもそも何がやりたかったのか

    ユーザーのプロフィール編集ページにSNSのURLを記載できる場所があり、そこではIDのみを受け付けてプロフィールに各SNSのURLを記載するようにしています。(この仕様はフロントエンド側の要求)
    スクリーンショット 2017-03-13 19.17.01.png

    スクリーンショット 2017-03-13 19.19.13.png

    当然ですが、URLをベタ打ちしてしまうユーザーがほとんだったため裏側でwww.facebookやtwitter.comなどのドメインを含む場合はその部分を削って、更新できるようにしようと思い、以下のような手順で改修していきました。

    1. まずusers_controller.rbに処理を記述。
    2. model.rbに処理を移す。
    3. before_validationに処理を移す。

    modelに処理を書いてみた。

    user.rb
    
    def check_sns_url(user_params)
        if user_params[:facebook_url] =~ /^https?:\/\/www.facebook.com\/(.+)/
          user_params[:facebook_url] = $1
        end
    
        if user_params[:twitter_url] =~ /^https?:\/\/twitter.com\/(.+)/
          user_params[:twitter_url] = $1
        end
      end
    
    

    check_sns_urlというインスタンスメソッドを作りました。
    送られてきた情報を正規表現で該当のIDの箇所を取りに行っています。

    users_controller.rb
    
    def update
       current_user.check_sns_url(params[:user])
       current_user.update(user_params)
       redirect_to userpage_path(current_user)
    end
    
    

    updateが実行される前に先ほどのモデルに記述したcheck_sns_urlを実行して、SNSのURLにドメインが含まれてしまっている場合は取り除いて、格納しています。

    『モデルに処理を移したからプルリク出したらすぐマージされるな、きっと!』と意気揚々に待っていたのですが、

    師匠からこんなコメントが来ました。

    ここの処理はモデルで before_validation を使うほうが良いですね。
    このアクション以外で User の変更が起きる場合(あまりないとは思いますが、、)に同じことを書かなくてはならなくなるので

    現段階ではそのような箇所はないのですが、一回書いた記述をいろんなところに撒き散らしたくないのでアドバイスいただいたbefore_validationというコールバックメソッドを使ってみることにしました。

    before_validation

    user.rb
    
    before_validation :check_facebook_url, on: :update
    before_validation :check_twitter_url, on: :update
    
    def check_facebook_url
       if self.facebook_url =~ /^https?:\/\/www.facebook.com\/(.+)/
          self.facebook_url = $1
       end
    end
    
    def check_twitter_url
       if self.twitter_url =~ /^https?:\/\/twitter.com\/(.+)/ 
          self.twitter_url = $1
       end
    end
    
    

    まずですが、メソッドを2つに分割することでテスコードが煩雑にならないようにしてみました。
    そして、before_validationですがインスタンスメソッド内にselfとすることでインスタンスの情報を取れるようにして、正規表現で該当箇所を探しています。今回はupdateの時のみ実行しています。
    before_validationはいくつか罠があるそうなので、それはいつかまとめてあげて見たいと思います。

    最後に

    いくつか参考にさせていただいたHP

    1. selfについて

    2. Railsコールバックまとめ