iT邦幫忙

2024 iThome 鐵人賽

DAY 8
0

Current Sprint: 1. 完成 HappyPath: 可以建立一場遊戲,玩到結束
repo: https://github.com/side-project-at-SPT/ithome-ironman-2024-san-juan
swagger docs: https://side-project-at-spt.github.io/ithome-ironman-2024-san-juan/

前情提要

昨天開了 GET /api/v1/games 取得所有遊戲

今天把後面做完

Sprint 1 需求

  1. 「使用者」可以建立一場遊戲 -> 遊戲建立成功,「使用者」成為了「玩家」
  2. 「玩家」可以選擇職業:礦工 -> 執行行動成功
  3. 「使用者」可以查看遊戲狀態

「使用者」可以查看遊戲狀態

  1. 目前的 api 回應

https://ithelp.ithome.com.tw/upload/images/20240910/201509870kUPhggHf7.png

因為目前沒有資料

「使用者」可以建立一場遊戲

  1. 在 games_controller 新增 create action
  2. 在 routes.rb 新增 create
  3. 在 games_spec.rb 增加 post ...
  4. 重新產生 swagger rails rswag
  5. 建立遊戲
    https://ithelp.ithome.com.tw/upload/images/20240910/20150987l61kKJHKyq.png

我們只需要回傳 id, status

  1. Gemfilejbuilder 註解取消
  2. bundle install
  3. 新增 app/views/api/v1/games/create.json.jbuilder
json.id @game.id
json.status @game.status

https://ithelp.ithome.com.tw/upload/images/20240910/20150987Lzmec9aGzU.png

  1. 新增 index.json.jubilder
json.games @games do |game|
  json.partial! "api/v1/games/game", game: game
end
  1. 新增 _game.json.jbuilder
json.id game.id
json.status game.status
  1. 更新 create.json.jbuilder
json.partial! "api/v1/games/game", game: @game
  1. 更新 games_controller.rb
class Api::V1::GamesController < ApplicationController
  def index
    @games = Game.all
  end

  def create
    @game = Game.new(status: "playing")
    unless @game.save
      render json: { error: @game.errors.full_messages }
    end
  end
end
  1. 測試看看

https://ithelp.ithome.com.tw/upload/images/20240910/20150987lc2y2EzlVO.png

https://ithelp.ithome.com.tw/upload/images/20240910/20150987tdHZGX4QpU.png

收工

「玩家」可以選擇職業:礦工

  1. 在 games_controller 新增 play action
class Api::V1::GamesController < ApplicationController
# ...
    
  def play
    @game = Game.find(params[:id])
    @game.play

    return render status: :unprocessable_entity, json: { error: @game.errors.full_messages } if @game.errors.any?

    @message = "你選擇了礦工"
  end

# ...
end
  1. 在 routes.rb 新增路徑
Rails.application.routes.draw do
# ...
    
  namespace :api do
    namespace :v1 do
      resources :games, only: [ :index, :create ] do
        member do
          post :play
        end
      end
    end
  end
    
# ...
end
  1. 增加測試案例
require 'swagger_helper'

RSpec.describe "Api::V1::Games", type: :request do
  path '/api/v1/games' do
    get 'List all games' do
      tags 'Games'
      produces 'application/json'

      before do
        Game.create
        Game.create(status: 'playing')
      end

      response '200', 'Games found' do
        schema type: :object,
          properties: {
            games: {
              type: :array,
              items: {
                type: :object,
                properties: {
                  id: { type: :integer },
                  status: { type: :string }
                },
                required: [ 'id', 'status' ]
              }
            }
          },
          required: [ 'games' ]

        run_test! do
          json = JSON.parse(response.body)
          expect(json['games'].size).to eq(2)
          expect(json['games'].any? { |game| game['status'] == 'unknown' }).to be_truthy
          expect(json['games'].any? { |game| game['status'] == 'playing' }).to be_truthy
        end
      end
    end

    post 'Create a game' do
      tags 'Games'
      consumes 'application/json'
      produces 'application/json'

      response '200', 'Game created' do
        schema type: :object,
          properties: {
            id: { type: :integer },
            status: { type: :string }
          },
          required: [ 'id', 'status' ]

        run_test! do
          json = JSON.parse(response.body)
          expect(json['status']).to eq('playing')
        end
      end
    end
  end

  path '/api/v1/games/{id}/play' do
    post 'Play a game' do
      tags 'Games'
      consumes 'application/json'
      produces 'application/json'

      let(:game) { Game.create(status: 'playing') }

      parameter name: :id, in: :path, type: :integer, required: true
      parameter name: :game, in: :body, schema: {
        type: :object,
        properties: {
          choice: { type: :string }
        },
        required: [ 'choice' ]
      }

      response '200', 'Game played' do
        schema type: :object,
        properties: {
          id: { type: :integer },
          status: { type: :string },
          message: { type: :string }
        },
        required: [ 'id', 'status', 'message' ]

        let(:id) { game.id }
        run_test! do
          json = JSON.parse(response.body)
          expect(json['status']).to eq('finished')
          expect(json['message']).to eq('你選擇了礦工')
        end
      end
    end
  end
end
  1. models/game.rb 增加 play
class Game < ApplicationRecord
# ...
    
  def play
    return errors.add(:status, "can't be blank") unless status_playing?

    self.status_finished!
  end
    
# ...
end
  1. 更新 swagger
  2. 測試看看

建立遊戲
https://ithelp.ithome.com.tw/upload/images/20240910/201509877LXjJuweIK.png

查看
https://ithelp.ithome.com.tw/upload/images/20240910/20150987ylrwiaifsn.png

行動(選擇礦工)
https://ithelp.ithome.com.tw/upload/images/20240910/20150987edroqaeTrC.png

再次查看
https://ithelp.ithome.com.tw/upload/images/20240909/20150987mv1Cidri57.png

收工

小結

明天做個中場休息

明天要做什麼

  1. 設計 table?
  2. 設計階段細項實作?

以上不代表明天會做,如有雷同純屬巧合


工商服務

SPT (Side Project Taiwan) 的宗旨是藉由Side Project開發來成就自我,透過持續學習和合作,共同推動技術和專業的發展。我們相信每一個參與者,無論是什麼專業,都能在這個社群中找到屬於自己的成長空間。

歡迎所有對Side Project開發有興趣的人加入我們,可以是有點子來找夥伴,也可以是來尋找有興趣的Side Project加入,邀請大家一同打造一個充滿活力且有意義的技術社群!

Discord頻道連結:https://sideproj.tw/dc


上一篇
Day 07 - 建立 games controller
下一篇
Day 09 - 期中檢討
系列文
透過實作網頁遊戲練習網站工程師的基本素養,以 San Juan(聖胡安) 為例。30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言