【Ruby】アソシエーションを使った投稿分類【投稿分類応用】

# はじめに
筆者は 大学生限定 プログラミングコミュニティ 『GeekSalon』で活動している者です！
もし少しでも興味がありましたら、ぜひお話を聞きにきてください！

# 前提
この記事でできることを紹介します。
今回は投稿の分類をし、その後にアソシエーションを使いさらに分類するといったことをします。

例えば、音楽をジャンル毎に分ける　→ ジャンル毎にアーティストを投稿する　→ アーティストの曲ごとに分類する。
流れはこんな感じになります。

他にも、スポーツをジャンル毎に分ける　→ ジャンル毎にスポーツを投稿する　→ そのスポーツチームごとに分ける。といったこともできます。

https://qiita.com/kubochiro/items/4d80a91a6133b680cb4b

参考記事：投稿の分類はこちらの記事を参考にしました

# カテゴリー分けその１
今回は、音楽をジャンル毎に分ける　→ ジャンル毎にアーティストを投稿する　→ アーティストの曲ごとに分類することをします!
![Qiita動画2.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2613366/92dc8699-44de-31f8-ada2-ba8e0c42f5c5.gif)


**①コントローラーを作成します**
```
rails g controller musics
```

**②コントローラーに以下のコードを記載**

```musics_controller.rb
 def new
     @music = Music.new
 end
    
      #追加箇所
def create
    music = Music.new(music_params)

    if music.save
         # カテゴリーに応じてリダイレクト先を設定
    if music.category == "idol"
       redirect_to  musics_idol_path 
    elsif music.category == "japaneserock"
       redirect_to  musics_japaneserock_path 
    else
        # その他のカテゴリーに対するリダイレクト先を設定する場合、ここに追加
       redirect_to  musics_westernrock_path 
    end
    else
       render :new
    end
end

def idol
    @musics = Music.all
end 
    
def westernrock
    @musics = Music.all
end
   
def japaneserock
    @musics = Music.all
end
 

def destroy
    music = Music.find(params[:id])
    music.destroy
    redirect_to action: :index
end

private
    def music_params
    params.require(:music).permit(:content, :category, )
    end
```

**コード解説**
今回は音楽ジャンルをアイドル・邦ロック・洋ロックに分けました。そのため、各ジャンル毎にアーティストが一覧で見れるようにします。

```musics_controller.rb
def create
    music = Music.new(music_params)

    if music.save
         # カテゴリーに応じてリダイレクト先を設定
    if music.category == "idol"
       redirect_to  musics_idol_path 
    elsif music.category == "japaneserock"
       redirect_to  musics_japaneserock_path 
    else
        # その他のカテゴリーに対するリダイレクト先を設定する場合、ここに追加
       redirect_to  musics_westernrock_path 
    end
    else
       render :new
    end
end
```
こちらはif文を使い、カテゴリー毎に投稿されたものに飛ぶようにしています。
例）邦ロックのアーティストを投稿する　→ 投稿されたら邦ロックの一覧ページに飛ぶようにする。
投稿するジャンル（KPOPやHIPHOP）を増やしたい場合は、elsifを追加しコードをコピーして、カテゴリーを変更すれば増やすことができます。

```musics_controller.rb
def idol
    @musics = Music.all
end 
    
def westernrock
    @musics = Music.all
end
   
def japaneserock
    @musics = Music.all
end
```
こちらのコードでジャンル毎に投稿を分けることができます。
今回は、アイドル　　邦ロック　　洋ロックで分けました。

# ルーティング作成

```musics_controller.rb
get 'musics/idol' => 'musics#idol'
get 'musics/westernrock' => 'musics#westernrock'
get 'musics/japaneserock' => 'musics#japaneserock'

resources :musics
```

# モデル作成　
```
rails g model Music content:string category:string
```
```
rails db:migrate
```
こちらのコードでモデルとカラムを作成します。


# それぞれのviewファイルを作成

viewのmusicsディレクトリにidol.html.erbファイル,westernrock.html.erbファイル,japaneserock.html.erbファイルの三つを右クリックで作成

```idol.html.erb
<h1>アイドル</h1>
<% @musics.each do |t| %>
  <% if t.category == "idol" %>  
    <p>アーティスト名:<%= t.content %></p>
     <%= button_to "削除する", music_path(t.id), method: :delete %>

  <% end %>
<% end %>
```
洋ロックや邦ロックの際も同様に同じのをコピぺしてください。また、コピペした後にidolを変更してください。

# 新規アーティストを投稿するページ作成
```new.html.erb
<%= form_for @music do |f| %>


   <%= f.label :content,"アーティスト名" %>
   <%= f.text_field :content %>

   <%= f.select :category, [["アイドル", "idol"], ["邦ロック", "japaneserock"], ["洋ロック", "westernrock"]], include_blank: "ジャンル" %>


   <%= f.submit "投稿する" %>
<% end %>
```
**ここまでで、カテゴリーごとに投稿を分類することができるうようになりました**

# 一つのアーティストが複数の曲を持つようにする
アーティスト一覧ページ（アーティストのリストを表示するページ）とアーティストの曲一覧ページ（特定のアーティストの曲を表示するページ）を関連付けるアソシエーションは、次のようになります：

「アーティスト一覧ページ」 → 「アーティストの曲一覧ページ」
これは、アーティスト一覧ページから特定のアーティストを選択し、そのアーティストの曲一覧ページに移動するという関連性を示しています。

このようにアソシエーションを使って、アーティスト一覧ページと曲一覧ページ、そして曲一覧ページの関連性を明確に分類できます。

# モデル作成
アーティストと曲の関連性を実現するために、Music モデルと Song モデルを使い、一つのアーティストが複数の曲を持つ関係を設定します。以下に、必要なコードを示します。

```
rails g model Song title:string music_id:integer
```
マイグレーションを実行して、データベースに変更を適用します。

```
rails db:migrate
```

**Music モデルと Song モデルは関連付け、アーティストが複数の曲を持つことができるようにする**

```app/models/music.rb
class Music < ApplicationRecord
  has_many :songs
  has_many :songs, dependent: :destroy
end
```
Music モデルを修正して、has_many アソシエーションを追加します。これにより、一つのアーティスト（Music レコード）が複数の曲（Song レコード）を持つことができます。

**dependent: :destroyは、この関連付けを削除するときの振る舞いを指定しています。**
具体的には、関連する「songs」が削除されるときに、それに関連するすべての「song」レコードも削除されます。これは「親モデルが削除された場合、関連する子モデルも削除する」という一般的なデータベースの関連付けの設定です。例えば、アーティストが削除された場合、そのアーティストに関連する全ての曲（songs）も削除されます。

``` app/models/song.rb
class Song < ApplicationRecord
  belongs_to :music
end
```
この設定により、Music モデルと Song モデルは関連付けられ、アーティストが複数の曲を持つことができるようになります。

# アーティストごとの新規曲投稿を作成
``` songs_controller.rb
 def new
     @song = Song.new
 end
    
def create
    @song = Song.new(song_params)
    
    if @song.save
       redirect_to musics_artist_songs_path(@song.music), notice: "曲が投稿されました"
    else
       render :new
    end
end
    
private
  def song_params
       params.require(:song).permit(:title, :music_id)
  end
```

こちらのコードでアーティストごとの曲を投稿できるようにします。

# アーティストの曲一覧ページを作成
```musics_controller.rb
def artist_songs
    @music = Music.find(params[:id])
    @new_song = Song.new
    @songs = @music.songs
end
```
**解説**
このコードは、アーティスト（Music モデル）に関連付けられた音楽曲（Song モデル）を管理するためのアクションである artist_songs アクションを定義しています。

```musics_controller.rb
@music = Music.find(params[:id]):
```
この行は、指定されたID（params[:id]）に基づいて特定のアーティスト（Music インスタンス）をデータベースから取得します。

```musics_controller.rb
@songs = @music.songs
```
この行は、特定のアーティスト（@music）に関連付けられた音楽曲（Song インスタンス）のリストを取得します。
@music インスタンスは、データベースから特定のアーティストを取得するために使用され、そのアーティストに関連付けられた音楽曲を取得するためにも使用されます。

**ルーティング設定**
```routes.rb
  get 'musics/idol' => 'musics#idol'
  get 'musics/westernrock' => 'musics#westernrock'
  get 'musics/japaneserock' => 'musics#japaneserock'
  get 'musics/artist_songs' => 'musics#artist_songs'#ここに追加
  
  resources :musics
  resources :songs, only: [:new, :create] #ここに追加
```

**アーティストの曲投稿ページ**
```new.html.erb
<h1>アーティストごとの曲投稿</h1>

<%= form_for @song do |f| %>
  <%= f.label :title, "曲のタイトル" %>
  <%= f.text_field :title %>

  <%= f.label :music_id, "アーティスト" %>
  <%= f.collection_select :music_id, Music.all, :id, :content, prompt: "アーティストを選択" %>

  <%= f.submit "曲を投稿" %>
<% end %>
```

**曲一覧ページ作成**

```artist_songs.html.erb
<h1><%= @music.content %>曲一覧</h1>
<ul>
  <% @songs.each do |song| %>
    <li><%= song.title %></li>
  <% end %>
</ul>
```

以上でアソシエーションを使った投稿の分類は以上になります。完成系はこちらになります。


![Qiita動画2.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2613366/f7dd5612-ecda-ce4e-d9f9-cad26ff3f0f4.gif)


お疲れ様でした！