他のユーザとの交流をするための機能として、いいねを実装していたが、誰にいいねをしたのかや誰がいいねをしてくれたのかを確認することが難しい状態になっていた。
それでは、「みんなとするダイエット」という本来のこのサービスの目的が薄れてしまうので、いいねの機能を少し拡張することにした。
完成後
LIKESは、そのプロフィールユーザのいいねをした他のユーザ数、LIKEDはその逆で、プロフィールのユーザがいいねをされた数を示している。
また、それぞれの文字はリンクになっていて、LIKESはいいねをした他のユーザ一覧、LIKEDはいいねをしてくれたユーザ一覧が表示されるようにした。
また、遷移した先の一覧でもLIKESとLIKEDを表示することで、自分がいいねをしたあるいはされたユーザから、他のユーザを探しやすくしたり、自分がその人をいいねしているのかどうかをわかるようにした。
LIKES(いいねをした他のユーザ)
タイトル
ページタイトルは、そのプロフィールページのIDが現在ログインしているユーザと一緒なのであれば、current_user.nameを、そうではないならプロフィールページのIDからUserを探し、その名前を表示するようにした。
表示されるデータ
表示されるユーザはLIKEDと違い、非表示設定のユーザを考える必要はない(LIKEDと非表示設定のユーザについては後述)ため、単純にそのプロフィールページのIDからLikesテーブルで検索をかけ、いいねをされたIDであるpro_idをとってきてそこからいいねをされたユーザの名前、ID、そしてそこからGraphsテーブルで検索をかけ、体重・日付のグラフを取得し表示されるようにした。
追記→Adminは非公開設定ユーザにもいいねをすることができるので、もしAdminがいいねをした場合、その非公開設定ユーザがAdminのLIKESリストに表示されてしまう。そのため、ここもLIKEDと同じロジックでAdmin、非公開設定ユーザ本人以外は「非表示ユーザ」として表示するようにした。
LIKED(いいねをしてくれた他のユーザ)
タイトル
タイトルのロジックはLIKESと同じである。
表示されるデータ
LIKESと違い、LIKEDは非表示ユーザについて考慮する必要がある。
というのもLIKESは、そもそも非表示ユーザにいいねを送ることはできないことから非表示ユーザに対するいいねデータが存在し得ないので考える必要はないと判断した。
※ただし、非表示ユーザのLIKESリストについては、Before_Actionで一般ユーザから見られないようにした。paramsがUser_idで一貫しているのでprivateメソッドを流用することができた。(PrivateメソッドはparamsからUserで検索しそれのPrivateコラムがtrueであればアクセスしたユーザをリダイレクトさせるBefore_Action)
一方でLIKEDは、非表示ユーザも一般ユーザに対していいねを送ることができるという仕様上、表示されるデータに最低でも「非表示ユーザからいいねをされた」ということを明確にしておく必要があった。そのため、LIKEDでは非表示ユーザをどう表示するかを考えた。
ここでも今までの非表示ユーザと同じく、非表示ユーザを確認できるのは、非表示ユーザ本人、Adminに限られ、それ以外の一般ユーザについては非表示ユーザからいいねがあったという最低限の表示に留めた。
LIKES LIKEDのリンク
リンクは両方ともホバーしたときに浮かび上がる背景もクリックすることができるようにした。
aリンクやlink_toはインライン要素なので、そのクラスをinline-blockにすることでそのクラスの親要素にまでリンクが拡張する。
LIKESのHTML
LIKESのCSS
likesnumをインラインブロックにすることで、そのクラスのリンクを親クラスであるにまで拡大。
インラインブロックすると強制的に改行するのでレイアウトは崩れるが、今回はspanクラスの長さを短くして横に揃えた。いろいろ工夫が必要ではある。
他にはposition relativeを使ってもできるみたい。
https://qiita.com/iwato/items/840b831ad66fec0dd4c1
Fakerでサンプルデータ作成
1 faker gemのインストール
2 db seedsを下記のようにする
fakerにはいろんな種類のサンプルデータが用意されている。公式git hubのREAD MEに紹介されているのでそこから参照して、使いたいものを使う。https://github.com/faker-ruby/faker/blob/master/README.md
3 rails db:migrate:reset
4 rails db:seed
この時一度ローカルサーバは落としてからやったほうがいい。指定した数のデータが生成されなかったりした。
また、上の画像のtrue ratio0.2では100件の全データ中、20件がTrueで生成された。
fakerで発見したエラー
ユーザAをいいねして、そのユーザAが削除された時、いいねデータは削除されない仕組み(Likesテーブルは外部キーがないため、Userが消えたらそちらも消えるといった仕組みが使えない)であった。
その結果、いいねデータからユーザを探すメソッドのあるLikeslistなどでエラーが出た。
下記のように、ユーザを削除する時にそのユーザがしたいいね、あるいはされたいいねを削除することを追加し、データに齟齬が内容調整し解決した。
わかったこと
-likeの中身がなかったらこれはエラーになるんじゃないかと思ったが、どうやらならない模様。
今までの感覚からすると、ないものを探して、それを使ってメソッドを実行するとエラー吐くと予想したけどDestroyは履かなかった。
-whereのor検索はやり方がわからず、ネットでいつものように調べたがどれもうまくできなかった。結局公式のガイド通りにしたらうまくいった。バージョンの違いとかもあると思われるので、自分が使っているRailsのバージョンを次からは意識していろんなことを調べようと思う。
https://railsguides.jp/active_record_querying.html
またこれを試行錯誤している段階で確実にコードはあっているのにおかしな挙動をすることがあった。サーバの再起動で直りはした。どういうこと?
-.destroyは一つのレコード。.destroy_allはwhereなどで出した複数のレコードの削除。
その他
nil
背景
いいねリストで、コントローラから送られたいいねデータが入るオブジェクトが何もなければビューでその旨を表示するということを実装したく、object.nil?とすると期待する動きをしなかった。(中身がなにもないという判定をだしてくれなかった)
解決
object.empty?とすることで解決した。
理由と分析
まずエラーの理由を把握するためには、nilというものがなんなのかを理解する必要がある。
nilとは「なにもない」ことで、値が入る空の箱擦らない状態を示している。
nil(他の言語ではnullということも多い、「何もない」という特殊なオブジェクトです)に対してメソッドを実行しようとすると、表記のような「NilClassにメソッドがない」旨のエラーになります。
対策としては、nilが来うるところでは、nilかどうかをチェックしてからメソッドを呼ぶというのが適当でしょう。動作上nilが来てはおかしい引数であれば、メソッドに渡す段階でチェックしましょう。
今回のケースでは、コントローラで箱は生成していたため、そもそもそのオブジェクトがnilではないのでnil?というメソッドを投げてもそれに応じた評価値は返ってこなかった。(.nil?だと下記画像のif文は何一つ実行されなかった)
箱自体はあり、からであることを確認するには.emptyメソッドであり、それを使うことで解決した。
empty nil blankの違いはここを参照。
https://qiita.com/hnkyi/items/f6c615909163a30b9814
divの中央寄せ
毎回分からなくなるので明記しておく。
divはブロック要素なのでtext-align-centerでは中身の文字は親要素に対して真ん中になるが、div自体は真ん中にはいかない。
その場合は、margin-left auto, margin-right autoを使うことで真ん中に寄らせることができる。
ここがわかりやすかった。
https://saruwakakun.com/html-css/basic/centering
重要だと思ったこと
・どの値を基準とするかを貫徹すること。
paramsはユーザIDとしておくとルール化しているならば、どこでparamsをとっても混乱しないし、そこからUserを呼べる。またUserのIDを外部キーやコラムにもつテーブルがあればUserを起点に、いやparamsを起点にどのデータにもアクセスすることができてしまう。
これは非常に強力だと思った。同時に各テーブルに起点となるテーブルのコラムを持たせておくことも大事だと感じた。
・1調べたら3くらい他のことも吸収すること。
ちょっと大変だけどいろいろと調べるにあたって、それと直接の関係はなくても浅く他の知識も無視せず見るようにしている。そうすると吸収する知識が増えて、その時は理解できなかったとしても将来なにかのエラー等に遭遇した時に「そういえばこんなことあったよな」と知識のひっかかりをその時のために増やすことができると思う。
もちろん他のことに目をとられて脱線しすぎて、何を調べているのかわからなくなったら本末転倒だが、この点は意識して学習したい。
・アウトプット
改めてだが、こうやってqiitaなどでその日やったことや学んだことをアウトプットするのはとてつもなく重要なことだと思った。
その場で理解ができていたとしても絶対に忘れてしまうし、ここでアウトプットすることで、その学んだことに対して触れる機会がそれだけで倍に増える。それを学習した時と、アウトプットしている時ということだ。
また言語化するというのはなんとなくわかったでは言語化したときにロジックが破綻する文章になってしまうが(自分の書いてきた文は読みにくいしロジックも破綻している箇所だらけだけど。。。)
そうならないためにアウトプットする段階で、その不透明な理解を、その時にベストなより明確な理解に落とし込むことができる。少なくとも落とし込もうとする段階をアウトプットで踏めるのでその点も非常に有意義だと思った。
また今は雑然としてしまっているこのアウトプットも、索引つきの記録にまとめることができたらすごく強い味方になると思うのでそれは実践したい。