Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationEventAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
3
Help us understand the problem. What are the problem?

More than 1 year has passed since last update.

to_paramでURLにユーザーIDを表示する 初心者→中級者へのSTEP12/25

to_paramでURLにユーザーIDを表示する

はじめに
今回解説するのは実際に僕が実装したもので、その時困ったこと、そしてどう対応したのかを紹介します。
このテーマについてはもっと良い方法がありそうなので、ご存知の方はご指摘いただけると幸いです。

デフォルトのURL

Railsでshowアクションにルートを通すと下記のようになる。
http://localhost/users/1
http://localhost/users/2
http://localhost/users/3
これだと「ん?もしかして会員数3人しかいない?」とか思われたり、何よりセンスがない。

なので、これを下記のようにユーザーIDを表示するようにしたい。
http://localhost/users/@kamo
http://localhost/users/@buta
http://localhost/users/@tanaka

to_param

実装は簡単で、to_paramというメソッドをオーバーライドするだけ。

User.rb
  def to_param
    user_id
  end

こうすると、モデルからパスを生成する時:idを使ってたのが、:user_idを使うようになってくれます。

to_paramのソースは下記のとおり。

  def to_key
    key = respond_to?(:id) && id
    key ? [key] : nil
  end

  def to_param 
    (persisted? && key = to_key) ? key.join('-') : nil
  end

上のto_keyメソッドから見てみます。最初の1行で、idの有無、またメソッドとして呼び出せるかを確認しています。2行目で3項演算子を用いて、idを配列に格納しています。

そして次のto_paramでは、modelがDBに保存されていることを確認した後、to_keyで得たid の配列を文字列化しています。

このto_paramはパスを生成する段階で呼ばれ、その時にパスにidを返す流れになっています。
それをオーバライドして、user_idが返ってくるようにしたわけです。

問題が3点

上記のようなto_paramをオーバーライドの仕方だと問題が3点出てきました。

1,user_idにindex,newなど登録されると困る。
2,params[:id]にuser_idが入るのでコントローラーでの修正が必要。
3,omniauthなど、SNSの簡単認証などを使っていて、user_idが最初に登録されない場合、パスを生成できない。

解決したコードがこちら

User.rb
 def to_param
    user_id ? '@' + user_id : super()
 end

上記のコードではuser_idが存在するなら、@を加えてます。
@が最初に加えられればindexだろうが、newだろうが怖くありません。また、super()はuser_idを持ってないユーザーは元のto_paramの振る舞いをするようにしてます。

User_controller.rb

    def set_user
      if params[:id].chr == '@'
        user_id = params[:id].slice!(0)
        @user = User.find_by!(user_id: user_id)
      else
        @user = User.find(params[:id])
      end
    end

上記では加えた@を外してます。またuser_idを登録してないユーザー用の分岐もかけています。
これでURLにはuser_idが表示され、かつちゃんとユーザーのデータも読み込めます。

まとめ

この実装してて思ったのは、「Rails wayに反しているのでは...?」となりましたが、他に方法が見当たらないのでこの方法で実装しました。(当時)
今回調べてたら、実はgemでfriendly_idてのがあり、それでも実装できるらしいです。でもまあ、せっかくto_param覚えたし、gemの仕組みを理解するよりこっちの方が仕組みを理解するのが簡単そうだったのでこっちを採用します。

参考にしたの

【Rails】to_paramでURLをUser.nameにする
https://remonote.jp/rails-to-param-url-user-name

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
3
Help us understand the problem. What are the problem?