Ruby on Rails ~お気に入り登録（ブックマーク）機能の実装2 - ブックマークしたユーザー数と一覧の表示（コードメモ）

今回は、以前実装したお気に入り登録(ブックマーク)に、いくつか機能を付け加えていきます。

前回:Ruby on Rails ~お気に入り登録（ブックマーク）機能の実装　http://qiita.com/wtb114/items/39367a39bd6a65701db7

実装するもの
1.ブックマークしたユーザー数の取得
2.ブックマークしたユーザーの一覧を取得
3.同じユーザーによるブックマークの重複登録を防ぐ
※「いいね！」などを実装する場合も、コピペで使用できます。

#1.修正前の確認
◆イベント一覧から興味のあるイベントをブックマークする機能です。
イベントは"Event"、ブックマークに使うモデルは"Clip"を使っています。


・ルート

```config/routes.rb
  resources :events do
    member do
      post "add", to: "clips#create"
    end
  end

  resources :clips, only: [:destroy]
```

・モデル

```app/models/clip.rb
class Clip < ActiveRecord::Base
    belongs_to :user
    belongs_to :event
end
```
```app/models/event.rb
class Event < ActiveRecord::Base
    has_many :clips
    has_many :users, through: :clips
end
```
```app/models/user.rb
class User < ActiveRecord::Base
    has_many :clips
    has_many :events, through: :clips
end
```

・コントローラー

```app/controllers/clips_controller.rb
class ClipsController < ApplicationController
  def create


    @user_id = current_user.id
    @event_id = Event.find(params[:id]).id
    @clip = Clip.new(event_id: @event_id, user_id: @user_id)


      if @event.save
        redirect_to user_path(current_user)
      end

  end

  def destroy
    @clip = Clip.find(params[:id])
    if @clip.destroy
      redirect_to user_path(current_user)
    end
  end

end
```

・ビュー

```app/views/events/show.html.erb
      <div>
      <%= link_to "このイベントをクリップ", add_event_path(event), method: :post %>
      </div>
```

#2.ルートの編集
```config/routes.rb

resources :events do
    member do
      post "add", to: "clips#create"
      get "show_clips" => "clips#show_clips"
    end
  end
  resources :clips, only: [:destroy, :index]
```
後ほど、"show_clip"で、あるイベントをブックマークしたユーザーを表示させるビューを作ります。
get "show_clips" => "clips#show_clips" を :eventsにネストし記述することで、clipにeventのidを紐付けます。

```
$ rake routes
=> 
show_clips_event GET      /events/:id/show_clips(.:format)         clips#show_clips
```
このようなルートができていると思います。

#3.モデルの編集

```app/models/clip.rb
class Clip < ActiveRecord::Base

    validates :user_id, :uniqueness => {:scope => :event_id}

    belongs_to :user
    belongs_to :event
end
```
Clipモデルに"validates :user_id, :uniqueness => {:scope => :event_id}"を記述します。
こうすることで、同じユーザーが同じイベントをブックマークできないようになります。(すでに保存されているClipのevent_idの場合に、user_idがユニークであるかどうか。)
"いいね！"機能など、重複して保存されないような機能を実装する場合にも使えます。

```app/models/event.rb
class Event < ActiveRecord::Base
    has_many :clips
    has_many :users, through: :clips
end
```
```app/models/user.rb
class User < ActiveRecord::Base
    has_many :clips
    has_many :events, through: :clips
end
```

#4.コントローラーの編集

```app/controllers/clips_controller.rb
class ClipsController < ApplicationController
  def create

    @user_id = current_user.id
    @event_id = Event.find(params[:id]).id
    @clip = Clip.new(event_id: @event_id, user_id: @user_id)
    
#以下、追記############################################################
    if @clip.save
      redirect_to clips_path(current_user)
    else
      redirect_to clips_path(current_user)
    end
###############varidateの結果、ブックマークに成功した場合と失敗した場合の処理を記述

  end

  def destroy
    @clip = Clip.find(params[:id])
    if @clip.destroy
      redirect_to user_path(current_user)
    end
  end
end
```
さらに２つのビューをつくるため。下記を追記。
"index"はユーザーがブックマークしたイベントを一覧で取得するページ。
"show_clips"は、あるイベントにブックマークしたユーザー一覧を取得するページ。

```app/controllers/clips_controller.rb
  def index
    @user = current_user
    @clips = Clip.where(user_id: @user.id).all
  end

  def show_clips
    @event = Event.find(params[:id])
    @clips = Clip.where(event_id: @event.id).all
  end
```

#5.ビューの編集
2つのビューを追加。

・ユーザーがブックマークしたイベントを一覧で取得するページ。

```app/views/clips/index.html.erb
  <h2>参加中のイベント</h2>
    <% @clips.each do |clip| %>
      <% event = Event.find(clip.event_id) %>
            <div class="name3"><%= link_to event.event_name, event_path(event) %></div>
            <div class="name2"><%= link_to "参加中のイベントから削除",clip_path(clip), method: :delete %></div>
            <div class="name2">
            <%= event.event_date.strftime("%Y-%m-%d %H:%M:%S")  %>
            </div>
            <div class="name2">
            <%= event.event_location %>
            </div>
    <br />
    <% end %>
</div>
```

・あるイベントにブックマークしたユーザー一覧を取得するページ。

```app/views/clips/show_clips.html.erb

  <h2>ユーザー一覧(<%= @clips.length %>人)</h2>

    <% @clips.each do |clip| %>
      <% @user_id = clip.user_id %>
      <% user = User.find(@user_id) %>
      <div class ="name2">
        <%= link_to user.username ,user_path(user) %><br/>
      </div>
    <% end %>
```

以上で実装が完了しました。