---
tags:
- Rails Develoepr Foundation
- Rails 開發者的進階實戰
---
# 2023-05-28 - Rails 開發者的進階實戰
## 事前準備
考慮到練習的時間,課程基本上會以 Pair/Mob Programming 的形式進行,然而仍建議有自己的開發環境方便未來練習。
### 開發環境
請以能夠運行這個 [GitHub Repository](https://github.com/StarPortal/rails-developer-foundation-template) 的前提下安裝環境,相關的安裝說明可以參考 README 的內容。
| 環境 | 版本 |
|-------------|-------|
| Ruby | 3.2+ |
| PostgreSQL | 14 |
| Node.js | 18 |
| [Cloudflared](https://developers.cloudflare.com/cloudflare-one/connections/connect-apps/install-and-setup/installation/) | 2023+ |
#### 命令
請確認可以確運行以下命令
| 命令 | 說明
|------------------------|----------------------------
| `bundle exec cucumber` | 驗收測試用,本次課程只會使用這個
| `bundle exec rspec` | 單元測試用
| `./bin/dev` | Rails 伺服器
### 工具
上課過程會使用以下工具
| 名稱 | 說明 |
|------------------|---------------------------------|
| FigJam | 需求分析練習,請確認瀏覽器可以正常開啟 |
| JetBrains Client | 安裝連結上課當天公布 |
| 習慣的編輯器 | VSCode、Vim 等皆可 |
## 課後問卷
麻煩大家協助填寫改善課程品質,以及了解大家對哪些類型的內容更有興趣
https://www.surveycake.com/s/vKRQO
## 講師資訊
課程內容無法涵蓋的部分,可以追蹤網誌、YouTube 會以小單元或者系列連載的方式分享出來。
| 網站 | 介紹 |
|-----------------|------|
| [個人網誌](https://blog.aotoki.me) | 系列文章連載、主題式討論
| [Facebook 粉絲專頁](https://fb.me/aotoki.me) | 主題式討論
| [YouTube 頻道](https://www.youtube.com/channel/UCcABbJfCL0DfNh3wDk_-7lg) | 技術講解
| [Discord 社群](https://discord.com/invite/t2Kd6PNvvA) | 技術討論,上課的問題也可以在此發問
| [訂閱電子報](https://mailchi.mp/aotoki/rails-developer-foundation) | 即時收到網誌通知
## 實作練習
為了方便查詢最近上映的電影,我們決定實作一個查詢網站來取得最近推出的幾部電影。
> https://github.com/elct9620/classroom-2023-05-28
### Key Examples
* 當蒼時開啟列表頁面時,顯示最新的 5 筆電影
* 假設有三部電影
* 2023-06-04 SANKYO PRESENTS WALKURE FINAL LIVE TOUR 現場直播
* 2023-05-23 小美人魚
* 2023-05-17 玩命關頭X
* 當蒼時開啟列表頁面
* 那麼會看到
1. SANKYO PRESENTS WALKURE FINAL LIVE TOUR 現場直播
2. 小美人魚
3. 玩命關頭X
```gherkin
#language: zh-TW
功能: 影片列表
場景: 當蒼時開啟列表頁面時,顯示最新的 5 筆電影
假設 這裡有幾部電影
| date | name |
| 2023-06-04 | SANKYO PRESENTS WALKURE FINAL LIVE TOUR 現場直播 |
| 2023-05-23 | 小美人魚 |
| 2023-05-17 | 玩命關頭X |
當 開啟電影列表
那麼 會看到 "1. SANKYO PRESENTS WALKURE FINAL LIVE TOUR 現場直播"
並且 會看到 "2. 小美人魚"
並且 會看到 "3. 玩命關頭X"
```
```ruby=
Given('這裡有幾部電影') do |table|
table.hashes.each do |movie|
# ...
end
end
When('開啟電影列表') do
visit movies_path
end
Then('會看到 {string}') do |string|
expect(page).to have_text(string)
end
```
* 當蒼時在列表頁面輸入「最近 1」的時候,可以看到離當天日期最近的 1 部電影
* 假設有三部電影
* 2023-06-04 SANKYO PRESENTS WALKURE FINAL LIVE TOUR 現場直播
* 2023-05-23 小美人魚
* 2023-05-17 玩命關頭X
* 當蒼時開啟列表頁面
* 並且輸入 "最近 1"
* 並且點選 "查詢"
* 那麼會看到
* 1. 小美人魚
```gherkin=
#language: zh-TW
功能: 影片列表
背景:
假設 這裡有幾部電影
| date | name |
| 2023-06-04 | SANKYO PRESENTS WALKURE FINAL LIVE TOUR 現場直播 |
| 2023-05-23 | 小美人魚 |
| 2023-05-17 | 玩命關頭X |
場景: 當蒼時開啟列表頁面時,顯示最新的 5 筆電影
當 開啟電影列表
那麼 會看到 "1. SANKYO PRESENTS WALKURE FINAL LIVE TOUR 現場直播"
並且 會看到 "2. 小美人魚"
並且 會看到 "3. 玩命關頭X"
@wip
場景: 當蒼時在列表頁面輸入「最近 1」的時候,可以看到離當天日期最近的 1 部電影
當 開啟電影列表
並且 在 "Search" 填入 "最近 1"
並且 點選 "查詢"
那麼 會看到 "1. 小美人魚"
```
```ruby=
When('在 {string} 填入 {string}') do |label, value|
fill_in label, with: value
end
When('點選 {string}') do |text|
click_on text
end
```
* 當蒼時在列表頁面輸入「最新 1」的時候,可以看到最新公開的 1 部電影
* 假設有三部電影
* 2023-06-04 SANKYO PRESENTS WALKURE FINAL LIVE TOUR 現場直播
* 2023-05-23 小美人魚
* 2023-05-17 玩命關頭X
* 並且還有一部電影
* 2023-06-07 變形金剛:萬獸崛起
* 當蒼時開啟列表頁面
* 並且輸入 "最近 1"
* 並且點選 "查詢"
* 那麼會看到
* 1. 變形金剛:萬獸崛起
```gherkin
場景: 當蒼時在列表頁面輸入「最新 1」的時候,可以看到最新公開的 1 部電影
假設 這裡有幾部電影
| date | name |
| 2023-06-07 | 變形金剛:萬獸崛起 |
當 開啟電影列表
並且 在 "Search" 填入 "最新 1"
並且 點選 "查詢"
那麼 會看到 "1. 變形金剛:萬獸崛起"
```
```ruby=
class Movie
include AcitveModel::Model
include ActiveModel::Attributes
end
```
```ruby
# controller
class MoviesController < ApplicationController
def index
@movies = if params[:search] == '最近 1'
Movie.recently(1)
elsif params[:search] == '最新 1'
Movie.newest(1)
else
Movie.all
end
end
end
```
```ruby
# model
class Movie
attr_reader :date, :name
class << self
def all
[
Movie.new(date: '2023-06-04', name: 'SANKYO PRESENTS WALKURE FINAL LIVE TOUR 現場直播'),
Movie.new(date: '2023-05-23', name: '小美人魚'),
Movie.new(date: '2023-05-17', name: '玩命關頭X')
]
end
def recently(qty)
base_date = Date.current
all.each_with_object({}) do |movie, result|
date_diff = ((base_date - Date.parse(movie.date)).to_i).abs
result[date_diff] = movie
end.sort_by { |date_diff, _movie| date_diff }.map { |_date_diff, moive| moive }.first(qty)
end
def newest(qty)
[Movie.new(date: '2023-06-07', name: '變形金剛:萬獸崛起')]
end
end
def initialize(date:, name:)
@date = date
@name = name
end
end
```
* 當蒼時在列表頁面輸入「最新 3」的時候,可以看到最新公開的 3 部電影
* 假設有三部電影
* 2023-06-04 SANKYO PRESENTS WALKURE FINAL LIVE TOUR 現場直播
* 2023-05-23 小美人魚
* 2023-05-17 玩命關頭X
* 並且還有一部電影
* 2023-06-07 變形金剛:萬獸崛起
* 當蒼時開啟列表頁面
* 並且輸入 "最近 1"
* 並且點選 "查詢"
* 那麼會看到
* 1. 變形金剛:萬獸崛起
* 2. SANKYO PRESENTS WALKURE FINAL LIVE TOUR 現場直播
* 3. 小美人魚
```gherkin
場景: 當蒼時在列表頁面輸入「最新 3」的時候,可以看到最新公開的 3 部電影
假設 這裡有幾部電影
| date | name |
| 2023-06-07 | 變形金剛:萬獸崛起 |
當 開啟電影列表
並且 在 "Search" 填入 "最新 3"
並且 點選 "查詢"
那麼 會看到 "1. 變形金剛:萬獸崛起"
並且 會看到 "2. SANKYO PRESENTS WALKURE FINAL LIVE TOUR 現場直播"
並且 會看到 "3. 小美人魚"
```
> 額外挑戰:
> * 如何不透過資料庫串接真實資料(e.g. 威秀)
> * 如何改寫成 LINE Bot
> * 如何用 LINE 的 Carousel 方式呈現跟測試?
* 當蒼時輸入非關鍵字的訊息時,固定回覆 "請使用「動作 參數」的格式處理"
* 當蒼時輸入「最新 1」的時候,可以看到上映日期最晚的 1 部電影
* 假設有三部電影
* 2023-06-04 SANKYO PRESENTS WALKURE FINAL LIVE TOUR 現場直播
* 2023-05-23 小美人魚
* 2023-05-17 玩命關頭X
* 當 "蒼時" 輸入 "最新 1"
* 那麼結果包含 "SANKYO PRESENTS WALKURE FINAL LIVE TOUR 現場直播"
* 當蒼時輸入「最近 1」的時候,可以看到離當天日期最近的 1 部電影
* 假設有三部電影
* 2023-06-04 SANKYO PRESENTS WALKURE FINAL LIVE TOUR 現場直播
* 2023-05-23 小美人魚
* 2023-05-17 玩命關頭X
* 當 "蒼時" 輸入 "最近 1"
* 那麼結果包含 "小美人魚"
* 當蒼時輸入「最近 5」的時候,可以看到離當天日期最近的 5 部電影
* 假設有三部電影
* 2023-06-04 SANKYO PRESENTS WALKURE FINAL LIVE TOUR 現場直播
* 2023-05-23 小美人魚
* 2023-05-17 玩命關頭X
* 當 "蒼時" 輸入 "最近 5"
* 那麼結果包含 "小美人魚"
* 並且結果包含 "玩命關頭X"
## 共筆區域
> 歡迎在這裡撰寫筆記跟其他同學協力紀錄
> [name=蒼時弦や]