---
# System prepended metadata

title: RL-?? CRUD 投票功能
tags: [Rails]

---

# RL-?? CRUD 投票功能

在既有CTRD中加入。

## 第一階段＝網頁連結
在View的網頁，連結根據路徑表的Helper。
```ruby=
<%= candidate.votes %> #看票數

<%= link_to "投票", vote_candidate_path(candidate.id) %>
```
## 第二階段＝路徑表
手動新增路徑表route
```ruby=
get '/candidates/:id/vote', to: 'candidates#vote''
```
或建議在resources下用do end包住：
1. member 新增成員方法
```ruby=
resources :candidates do
    member do
      post :vote #投票
    end
end
```
2. collection 新增方法，不帶ID
```ruby=
resources :candidates do
    collection do
      post :vote #投票
      get :vote_list #看投票列表
    end
end
```
## 第三階段＝做出「vote」
在Controller新增方法「vote」。
第3行也能寫成 @candidate.increment(:votes)

```ruby=
def vote
    @candidate = Candidate.find_by(id: params[:id]) #抓出它
    @candidate.votes = @candidate.votes + 1 #欄位名稱寫在db的schema裡 用a=a+1邏輯投票
    @candidate.save #儲存它
end

    flash[:notice] = "投票完成"
    redirect_to '/candidates'
```
## 投票紀錄表
### 在Model

建立一個Model。
* 欄位包括候選人id（candidate_id:integer）、IP位址（ip_address）
    * 使用 candidate:references 也會指向id流水編號
* 時間戳記會自動產生，不用另外寫。

```ruby=
$rails g model VoteLog candidate:references ip_address
``` 
兩個檔案（"app/model"與"db/migrate"之下的）沒問題的話，開始實體化:
```ruby=
$rails db:migrate
```

### 在Controller
在原Vote方法中，新增一筆資料庫
* request.remote_ip 可以抓IP
* 注意new方法只是暫存記憶體，要另外save儲存。建議用create。

```ruby=
VoteLog.create(candidate: @candidate, ip_address: request.remote_ip)
```
也能從候選人角度新增一筆資料庫
> 這一行也包括了新增、儲存功能，可將原本那2行刪除
@candidate.votes = @candidate.votes + 1
> @candidate.save
> 
```ruby=
@candidate.vote_logs.create(ip_address: request.remote_ip)
```

### 在Model（候選人角度）
若Controller使用候選人角度，必須建立新寫的vote_logs方法。
在models/candidate.rb 必須手動建立關係。
```ruby=
has_many :vote_logs
```
### 在View
顯示票數。
可在rails c 裡面調出VoteLog詳細資料。
```ruby=
<%= candidate.votes %>
```

## 以Counter Cache計算票數（混亂 先別管）
先修教材「純手工」最後2集
### 在migration

新增vote_log_count欄位，讓表單vote_logs的結果回到 表單candidtes裡面。

1. 新增/刪除/修改資料表時，要針對magration。因此在終端機新增一個:
```ruby=
$rails g migration add_counter_cache_to_candidate
```
2. 在新增的db/migrate檔案內，在def change內新增add_column方法（表單名, 欄位名, 型態, 其他預設值等）

```ruby=
add_column :candidates, :vote_logs, :integer, default: 0
```
有migtation就要具現化。若成功，可在schema內看到。
```ruby=
$rails db:migrate
```

在vote_logs的model檔內加寫 counter_cache:true，令票數寫入時同時更新票數到migration的新欄位。
```ruby=
belongs_to :candidate, counter_cache:true
```


###### tags: `Rails`