この記事はプログラミング学習者がアプリ開発中に躓いた内容を備忘録として記事におこしたものです。内容に不備などあればご指摘頂けると助かります。
制作しているクローンアプリの中でControllerで取得したある2つのデータをハッシュとオブジェクトの文字列という形で保存していました。これらのデータを称号する為に調べて実装した内容を掲載します。
実装したコードの紹介
def show
@tweet = Tweet.includes(images_attachments: :blob).find(params[:id])
@comments = @tweet.comments.includes(user: { icon_attachment: :blob }, images_attachments: :blob)
@replies = {}
@comments.each do |comment|
@replies[comment.id] = Comment.where(parent_id: comment.id) if Comment.where(parent_id: comment.id).present? #今回の記事で解説に関わる部分
end
end
- @comments.each do |comment|
- if not @replies.values.flatten.map(&:sentence).include?(comment.sentence) #今回の記事で解説に関わる部分
= link_to comment_path(comment.id) do
ul
li
object = link_to image_tag(comment.user.icon, alt: "Icon image", class: "icon_image", size: '50x50'), profile_path(comment.user.id)
li
object = link_to comment.user.name, profile_path(comment.user.id)
li 投稿日: #{comment.created_at.strftime('%Y/%m/%d %H:%M:%S')}
- if not @replies[comment.id].present?
p = comment.sentence
- else
.reply-box
.reply-space
.reply-line style="background-color: #a9a9a9; width: 1px;"
.reply-space
span = comment.sentence
- if comment.images.attached?
- comment.images.each do |tweet_image|
= image_tag tweet_image, size: '250x200', class: "tweet_image"
- if @replies[comment.id].present?
- @replies[comment.id].each do |reply|
= link_to comment_path(reply.id) do
ul
li
object = link_to image_tag(reply.user.icon, alt: "Icon image", class: "icon_image", size: '50x50'), profile_path(reply.user.id)
li
object = link_to reply.user.name, profile_path(reply.user.id)
li 投稿日: #{reply.created_at.strftime('%Y/%m/%d %H:%M:%S')}
- if reply == @replies[comment.id].last
p = reply.sentence
- if reply.images.attached?
- reply.images.each do |tweet_image|
= image_tag tweet_image, size: '250x200', class: "tweet_image"
- else
.reply-box
.reply-space
.reply-line style="background-color: #a9a9a9; width: 1px;"
.reply-space
span = reply.sentence
- if reply.images.attached?
- reply.images.each do |tweet_image|
= image_tag tweet_image, size: '250x200', class: "tweet_image"
end
hr
コードの解説
まず、tweets_contorller内で取得している2種類のデータについて解説します。
@comments = @tweet.comments.includes(user: { icon_attachment: :blob }, images_attachments: :blob)
@tweet
に属する全てのコメントをユーザー及びそのアイコン画像、そしてコメントとセットで投稿されている画像をN+1問題が発生しないようにオブジェクトの配列として取得します。
@comments.each do |comment|
@replies[comment.id] = Comment.where(parent_id: comment.id) if Comment.where(parent_id: comment.id).present?
end
上のコードで取得した@comments
をeach文で1つずつ展開、commentのidをparent_idに持つコメントオブジェクトが有る場合、commentのidをキーとしハッシュで保存します。
parent_idを持つ場合、それはそのparent_idを持つコメントに対する返信となります。
- @comments.each do |comment|
- if not @replies.values.flatten.map(&:sentence).include?(comment.sentence)
viewファイルで投稿されているコメントを表示する機能を実装するのですが、表示前に省きたいデータがありました。
それはコメントもコメントに対する返信も同じCommentオブジェクトなので、@comments
と@replies
で取得してデータが一部重複する部分です。
省かないとコメントに対する返信として表示した後に通常のコメントとしても表示されてしまい、重複して表示されてしまいます。
そこで上記のif文を使った分岐で重複を確認するようにしました。
データの内容は下記例のようになります。
@replies = {
1 => [Commentオブジェクト1, Commentオブジェクト2]
2 => [Commentオブジェクト3]
} #ハッシュの構造になっている( キー => 値
@replies.values
=> [[Commentオブジェクト1, Commentオブジェクト2], [Commmentオブジェクト3]]
# 多次元配列になる
@replies.values.flatten
=> [Commentオブジェクト1, Commentオブジェクト2, Commentオブジェクト3]
# 多次元から1次元の配列になる
@replies.values.flatten.map(&:sentence)
=> ["コメント1", "コメント2", "コメント3"]
# 配列から1つずつ取り出してオブジェクトのsentenceを配列として返す
@replies.values.flatten.map(&:sentence)
でCommentオブジェクトのコメント部分を配列としたデータを取得できました。
後は.include?(comment.sentence)
で@comments
から取り出したcomment.sentence
の文字列を含むかどうかを照合します。
これで取得したハッシュ形式のデータとオブジェクト(文字列)を照合することができました。
最後まで読んで頂き有難うございます。
参考にしたサイト
flattenメソッドについて