0%

Ruby on Rails 網站開發 練習 - 014 ( 投票紀錄表 )

練習 - 014 (投票記錄表)

利用 Rails 的 Model 產生器,產生一個資料表出來,並且幫我們做好 migration。

需要的欄位有 ↓

  1. candidate_id:因為是一個參照值,可以使用candidate:references這個指令,Rails會幫我們去撈candidate的流水編號(id)欄位。

  2. ip_address:想要有記名投票的效果,所以我們需要投票人的ip位置。資料型態雖然是 string 但是這邊可以省略不寫:string。


在終端機輸入指令。

可以看到終端機顯示的資訊,有產生migration檔案也同時有建立model。

確認model目錄底下有建議了 VoteLog 這個 model,並且幫我們設定好belongs_to :candidate

再到db目錄底下看到有新增了 migration 檔案,確認檔案內容是否都正確。


確認migration檔案內容都沒問題,接著我們就可以把它「具現化」。
終端機執行 rials db:migrate 指令,終端機畫面顯示有migrate成功。


那我們現在都有投票紀錄了,接著就是要把它寫進去,因此我們回到CandidatesControllervote action裡面增加

1
VoteLog.new(candidate: @candidate, ip_address: ???)

這遇到ip位置不知道該放什麼value給它,這時候我們可以請出google大神,輸入關鍵字rails ip_address,通常前幾篇就會找到需要的答案,很幸運的我們很快就找到了。request.remote_ip

1
VoteLog.new(candidate: @candidate, ip_address: request.remote_ip)

但是如果是用new方法的話,會需要給它一個變數承接,在執行.save

1
2
v = VoteLog.new(candidate: @candidate, ip_address: request.remote_ip)
v.save


這裡我們可以換另外一種寫法,比較直接一點,不需要兩段式的方式寫入資料庫。create的方法可以直接存進去。

1
VoteLog.create(candidate: @candidate, ip_address: request.remote_ip)

打開瀏覽器,來投票試試看,先記下2號候選人ddd的目前票數2票。


接著按下左邊的vote,來觀察一下是否有變化。變成3票了!!ˊ而且畫面也有顯示「投票成功!!!」


確認有沒有確實寫入資料庫,透過rails console來確認。
輸入指令VoteLog.all就可以看到目前在VoteLog model裡面有多少的投票紀錄。

這樣每個候選人(id)被點擊一次vote就會被記錄下來。


此時我們可以換個角度從候選人角度來寫,候選人名字有被投票的就會被紀錄起來。


另外原本下面的第55-56行寫的程式碼,是針對候選人的某個欄位執行遞增,並且將結結果save到資料庫中。
因為我們現在已經寫了第53行的程式碼,所以55-56行的程式碼就可以拿掉。


打開瀏覽器,此時按下vote會顯示錯誤訊息「沒有定義vote_logs方法」

為什麼會看到,是因為剛剛我們給每一位候選人都有很多「投票紀錄」model,透過這個「投票紀錄」model,直接建立一個投票紀錄出來。這樣我們就可以計算票數。

雖然我們剛剛建立VoteLog Model時有使用references:candidate這個指令,會幫我們在vote_log.rb這個model檔案直接幫我們加上belongs_to :candidate

但是相對的Candidate Model卻沒有幫我們做這件事情。

因為Rails不曉得我們是要做「一對一」關聯?「一對多」關聯?它沒有辦法去猜,所以這邊就只能由我們自己手動來幫Model們來建立「關聯」。


進到Candidate Model手動新增has_many :vote_logs,要記得log是負數型態(logs)。

關於has_many的黑魔法,之後會有另位的章節介紹它。目前先知道它其實默默地在背後建立一個叫做vote_logs的方法。


這邊我們回到瀏覽器,回到前一頁,先確認目前每位候選人的票數。


對候選人eee按下vote,再看看是否會一樣出現錯誤訊息。


有顯示投票成功,可是票數還沒有改變一樣維持4票。這時候我們可以透過rails console來觀察一下是否真的有投票成功。

輸入指令:VoteLog.count,看到顯示有7票。

再繼續對eee候選人多按3次vote,看看數字會不會變化:

確實現在票數變成10票了。是有成功將票數寫進資料庫中。但是目前瀏覽器的畫面依然顯示票數是4票


會有這樣的原因是原本我們把票數的累進,寫在了Candidate Modelvotes欄位累進票數。不是現在我們使用的VoteLog Model

所以我們進到view/index.html.erb檔案來修改一下<%= candidate.votes %>的內容,改成<%= candidate.vote_logs %>

因為每個候選人都會有很多投票紀錄,所以<%= candidate.vote_logs %>會回傳一大包東西 (是一個陣列)。

可以透過rails console來看一下回傳的資料內容,首先我們先宣告一個c1變數=候選人的第一個c1 = Candidate.first

輸入c1.vote_logs説:「誒,聽說你有很多票。」會看到一長串長得像陣列的東西。

再輸入c1.vote_logs.count説:「那你到底有幾張票」。c1候選人告訴你:「我有2張票。」

所以這時候我們可以回到view/index.html.erb再修改剛剛的那行程式碼<%= candidate.vote_logs.count %>。這樣應該就會拿到我們想要看到的票數。

再回到瀏覽器重新整理,此時可以發現票數改變了。變成了votelogs紀錄的票數。


這時候我們對ccc候選人再投5票。看看是否票數會增加變成7。

真的有成功投票,並且寫進資料庫。

如果要確認投票紀錄,現在我們可以再透過rails console來觀察
一樣輸入:c1 = Candidate.firstc1.vote_logs

可以看到一號候選人的投票紀錄:

雖然有顯示投票紀錄了。但是不知道有沒有發現一件事情,執行rails console如果要看去投票紀錄。輸入c1.vote_logs它是會撈後選人的資料,你有幾票它會去撈幾次。

這個狀況是否似成相似?有沒有「N + 1」的感覺。如果候選人很多時,大家同時上線投票,會很佔用資源,有資源消耗的問題。


目前已經看到每次投票的紀錄,但是其實有需要優化的地方,「效能」。

下一堂課程,改善效能。

參考來源:為你自己學 Ruby on Rails (https://railsbook.tw/)