オブジェクトとハッシュを照合するには？flattenメソッドの使用

この記事はプログラミング学習者がアプリ開発中に躓いた内容を備忘録として記事におこしたものです。内容に不備などあればご指摘頂けると助かります。

###### 制作しているクローンアプリの中でControllerで取得したある２つのデータをハッシュとオブジェクトの文字列という形で保存していました。これらのデータを称号する為に調べて実装した内容を掲載します。

## 実装したコードの紹介

```ruby:tweets_controller.rb
  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
```

```ruby:show.html.slim
- @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内で取得している２種類のデータについて解説します。

```ruby
@comments = @tweet.comments.includes(user: { icon_attachment: :blob }, images_attachments: :blob)
```
`@tweet`に属する全てのコメントをユーザー及びそのアイコン画像、そしてコメントとセットで投稿されている画像をN+1問題が発生しないようにオブジェクトの配列として取得します。

```ruby
@comments.each do |comment|
      @replies[comment.id] = Comment.where(parent_id: comment.id) if Comment.where(parent_id: comment.id).present?
end
```
上のコードで取得した`@comments`をeach文で１つずつ展開、commentのidをparent_idに持つコメントオブジェクトが有る場合、commentのidをキーとしハッシュで保存します。
parent_idを持つ場合、それはそのparent_idを持つコメントに対する返信となります。

```ruby:show.html.slimの抜粋
- @comments.each do |comment|
  - if not @replies.values.flatten.map(&:sentence).include?(comment.sentence)
```
viewファイルで投稿されているコメントを表示する機能を実装するのですが、表示前に省きたいデータがありました。
それはコメントもコメントに対する返信も同じCommentオブジェクトなので、`@comments`と`@replies`で取得してデータが一部重複する部分です。
省かないとコメントに対する返信として表示した後に通常のコメントとしても表示されてしまい、重複して表示されてしまいます。
そこで上記のif文を使った分岐で重複を確認するようにしました。
データの内容は下記例のようになります。
```ruby
@replies = {
    1 => [Commentオブジェクト1, Commentオブジェクト2]
    2 => [Commentオブジェクト3]
} #ハッシュの構造になっている( キー => 値
```
```ruby
@replies.values
=> [[Commentオブジェクト1, Commentオブジェクト2], [Commmentオブジェクト3]]
# 多次元配列になる
```
```ruby
@replies.values.flatten
=> [Commentオブジェクト1, Commentオブジェクト2, Commentオブジェクト3]
# 多次元から1次元の配列になる
```
```ruby
@replies.values.flatten.map(&:sentence)
=> ["コメント1", "コメント2", "コメント3"]
# 配列から１つずつ取り出してオブジェクトのsentenceを配列として返す
```
`@replies.values.flatten.map(&:sentence)`でCommentオブジェクトのコメント部分を配列としたデータを取得できました。
後は`.include?(comment.sentence)`で`@comments`から取り出した`comment.sentence`の文字列を含むかどうかを照合します。

これで取得したハッシュ形式のデータとオブジェクト(文字列)を照合することができました。

最後まで読んで頂き有難うございます。

参考にしたサイト
[flattenメソッドについて](https://qiita.com/wangqijiangjun/items/525fd47724b69a241790)