はじめに
みなさん、こんにちは。torihaziです。
今回はタイトルの件について書いていこうと思います。
ちなみに初心者です。
間違いがないよう最善は尽くしていますが、何かあれば指摘をお願いいたします。
環境について
ruby 3.2.1
rails 7.0.6
結論
-
find
ならArray オブジェクト が -
where
ならActiveRecord::Relation オブジェクトで
返ってくるよということ。
例えば下記のような時。
id = [1]
@hoge_find = Hoge.find(id)
@hoge_where = Hoge.where(id: id)
これをviewのlink_toで参照しようとしたときに
= link_to hoge_path(@hoge_find)
=> /hoge/1
= link_to hoge_path(@hoge_where)
=> /hoge%23%3CHoge::ActiveRecord_Relation:・・・・・・"
生成されるURLが違ってくる。
なんで気づいたか
今、XクローンのDM機能(ユーザ同士の1対1チャット)を作っています。
Userにdevise gem は使っています。
その時に
ログインユーザがすでにDMし合っているユーザの詳細画面において
表示されているDMアイコンをクリックした際にそのユーザとのDMページに遷移する
という処理を書いていました。
処理イメージだと次の感じです。
- user1でログインし、相互フォローしているuser8の詳細ページに遷移します
- そのページにおいてDMアイコンをクリックします
- するとDMしていなければDMに関するものをcreateしてから、あればそのままDMのページに遷移します。(urlだと/users/8/conversations/2 のような感じ)
この2番において
すでにDMをし合っているか
ということを判別するために下記のロジックをUser.rbに作りました。
class User < ApplicationRecord
~~~
has_many :participants, dependent: :destroy
~~~
def find_conversation_with(other_user)
id = ( participants.pluck(:conversation_id) ) &
( other_user.participants.pluck(:conversation_id) )
id.any? ? Conversation.where(id: id) : nil
end
end
この結果をusers_controller.rbにおいて次のように使用しました。
def show
・・・
@conversation = current_user.find_conversation_with(@user)
・・・
end
そしてビュー側で次のように表示を分けました。
~~~
- if @conversation
= link_to user_conversation_path(@user, @conversation), class: "btn btn-outline-dark rounded-circle" do
i.bi.bi-envelope-plus
- else
= link_to user_conversations_path(@user), data: { "turbo-method": :post }, class: "btn btn-outline-dark rounded-circle" do
i.bi.bi-envelope-plus
この時ビュー側で/users/8/conversations/2
というlinkが生成されるのかと思いきや
恐ろしいurlが生成されていました。
この原因は
where
ならActiveRecord::Relation オブジェクトで
だからです。
そのため解決策としてはいろいろあるかと思いますが、自分は次のようにfind
で行いました。
class User < ApplicationRecord
~~~
has_many :participants, dependent: :destroy
~~~
def find_conversation_with(other_user)
id = ( participants.pluck(:conversation_id) ) &
( other_user.participants.pluck(:conversation_id) )
- id.any? ? Conversation.where(id: id) : nil
+ id.any? ? Conversation.find(id) : nil
end
end
こうすれば urlも次のように/users/1/conversations/1
のようになります。
終わりに
なんとなくで使い分けていましたが、このような違いがありました。
これからも学習を続けていきたいと思います。
ただ今回のDMし合っているかの判別は 1対1のDMまでしかできないアプリ
しか使えないと思います。
グループチャットを考えたら機能しないかと思います。
そのためその時はその時考えようかと思います。
あとコードレビューもしていただいていないため、修正入るかもです。
そしたらその時直します。