iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 19
1
Modern Web

「VR 」前端後端交響曲 - 30天開發 Vue.js feat. Ruby on Rails即時互動網站系列 第 19

[VR 前後端交響曲Day19] Rails專案開發 - 建立Vue元件: Column component

昨天的鐵人賽,我們利用rails的scaffold指令,迅速地將看板KanbanCRUD調整成符合專案適合的樣貌,並完成了使用者登入後頁面,列出了目前筆者在現實生活中、需要進行敏捷開發的兩個Rails專案的kanban


(寫個專案來改善real-life situation會遇到的問題,改善自己的生活,才是最寶貴的經驗啊~~)

那麼,點進Kanban裡之後,揪竟~~會發生什麼事呢?

本日開發目標

Column的業務邏輯如下:

  • 使用者可以建立很多Kanban
  • 每個看板Kanban可以建立很多Column
  • 每個Column可以有很多張票Ticket。(明天實作)

並且將Column換成Vue元件!

首先,建立第三個Model: Column

# position欄位是為了之後的拖拉效果做準備
rails g scaffold Column name kanban:belongs_to position:integer

檢視一下model,確定kanbancolumn的關聯性:

kanban.rb

每個kanban有很多columns
根據dependent相依性,如果刪掉了kanban,裡面的column也就一起刪掉

class Kanban < ApplicationRecord
  has_many :columns, dependent: :destroy
  belongs_to :user
  validates :name, presence: true
end

column.rb

class Column < ApplicationRecord
  belongs_to :kanban
  validates :name, presence: true  
end

在rails console建立幾筆資料column資料

rails db:migrate將欄位具現化後,通常在Rails專案裡,當model增加越來越多、model的關聯相對複雜的情況,
我們為了要確定model的關係,會先利用console見幾筆假資料來輔助接下來網頁的UI設計以及功能製作。

還記得昨天用網頁直接UI建立了兩個kanban

  • 我們想要抓出id=1使用者(就是我自己啦~):
> u1 = User.first

=> #<User id: 1, email: "秘密", created_at: "2020-10-01 01:43:03", updated_at: "2020-10-01 07:12:27", name: "Ting">
  • 並找到這位使用者的第2個看板:
> k2 = u1.kanbans.find 2

=> #<Kanban:0x00007fa40f8e4df0
 id: 2,
 name: "Vue.js feat. Rails專案",
 description:
  "相對容易上手的前端框架Vue.js,要如何整合網站後端開發最迅速的框架Rails呢?讓我們用30天來探索及實作~來一場「VR」Vue.js feat. Ruby on Rails前端後端交響曲吧!",
  • 而且要在裡面建立幾筆column:

根據想致敬的trelloSoftware Development template:

我建立的columns欄位名稱如下:

> k2.columns.create(name: "Backlog")
> k2.columns.create(name: "Sprint Backlog")
> k2.columns.create(name: "Working On")
> k2.columns.create(name: "Bugs")
> k2.columns.create(name: "Done")
> k2.columns.create(name: "Testing")

點擊dashboard的kanban,可導向該看板的column

我期待的是,點入登入後首頁的任一kanban,就可以導向該kanban下,看到該專案的開發流程樣貌。

如下所示,點擊連結後應該會導向
kanbans/2/columns

設計column的routes

Rails.application.routes.draw do
  resources :kanbans do
    resources :columns, except: [:new, :edit] do
    end
  end

  devise_for :users
  root 'pages#index'  // 登入前的首頁
  get "dashboard", to: "pages#dashboard" // 登入後的dashboard
end

MVC: 修改columns controller

由本專案架構下,預期的routes路徑推測
kanbans/2/columns (點擊2號kanban,列出所有column)

進入columns列表之前,我們要先準備好@kanban這個實體變數,之後才能取到kanban的id:

columns_controller.rb

  def index
    @kanban = Kanban.find(params[:kanban_id])    
    @columns = @kanban.columns.all
  end

準備好了路徑,我們該如何設計column這個元件呢?

製作Column元件

Step 0. 事前準備:利用 Vue.js Lifecycle的概念,決定使用哪個Lifecycle hook把資料抓回來

因為接下來我們需要請Vue.js在適當的時機點把目前Rails專案裡的資料庫把抓資料來並渲染在網頁上,
所以來觀察第14天的鐵人賽曾經整理過的這張Lifecycle paragram:

Mounting: 掛載階段

hooks 用途
beforeMount 在執行元素掛載,畫面渲染至瀏覽器前的階段,此時render method第一次被呼叫,可以讓我們預處理DOM。
mounted 元素已掛載,el建立完成。

以本日的實作需求來說,我們希望在render前就能把資料取得,所以掛Lifecycle hook最佳的時機點是beforeMount()

Step 1. 確定column元件的資料要從哪裡得到

使用scaffold時,rails已經幫我們長好了json檔,可以直接拿來使用

例如第2個kanban裡的column有這些:

接下來就是重頭戲了!

Step 2. 決定Vue app的掛載點

我們的要掛Vue.js的Rootid="column"div

這個div也偷偷藏了kanbaniddataset(剛剛column controller鋪好的梗,讓@kanban實體變數可以直接拿來用)
以利第三步用ajax打api到後端

接著當我們要到資料時,會用v-for把column一個一個渲染在頁面上。

columns#index.html.erb

<div id="column" class="mt-2 px-3 flex" data-kanbanid="<%= @kanban.id%>" >
  <!-- Column元件的位置 -->
  <!--  -->
  <Column v-for="column in columns" :column="column" :key="column.id"></Column>  
</div>

還記得資料綁定v-bind嗎?

<Column v-for="column in columns" :column="column" :key="column.id"></Column>
這句的意思是
是v-for迴圈的每個column值,透過:column傳給子元件

Step 3. 設計column元件

第9天鐵人賽,曾經練習用props在Vue裡從父元件裡傳遞資料給子元件。

而在本專案我們的column元件是掛在root之下,因此會利用props傳進來column以供子元件使用。然後用css美化一下印出來的結果,看起來有一格一格欄位的感覺~

components/kanban/column.vue

<template>
  <div class="column">
    <!-- 使用props裡的column -->
    <div class="column-name">{{ column.name }}</div>
  </div>
</template>

<script>
  export default {              
    name: 'Column',
    // 父層餵資料給子元件    
    props: ["column"]
  }
</script>

<style lang="scss" scoped>
  .column{
    @apply .bg-teal-100 .mx-2 .w-64 .rounded;

    .column-name{
      @apply .px-3 .py-2 .font-thin;
    }
  }
</style>

Step 4. 在application.js引入並註冊元件

要使用元件,必須要先引入及註冊
這點應該大家都不陌生了:
import Column from "components/kanban/column"
components: { Column }

application.js

require("@rails/ujs").start()
require("turbolinks").start()
require("@rails/activestorage").start()
require("channels")

const images = require.context('../images', true)
const imagePath = (name) => images(name, true)

import 'scripts'
import 'styles'

import Vue from "vue/dist/vue.esm";
import Column from "components/kanban/column"
import Rails from '@rails/ujs'

document.addEventListener("turbolinks:load", () => {
  let el = document.querySelector("#column");
  if (el){
    new Vue({
      el,
      data: {
        kanban_id: el.dataset.kanbanid,
        //columns陣列, 預設為空值
        columns: []
      },
      components: { Column },

      beforeMount(){
        // 打API
        Rails.ajax({
          url: `/kanbans/${this.kanban_id}/columns.json`,
          type: 'GET',
          dataType: 'json',
          success: result => {
            // 把ajax回傳結果放進columns陣列
            this.columns = result;
          },
          error: error => {
            console.log(error);            
          }
        });
      }
    });
  }
})

而本部分最重要的地方就是在

beforeMount(){
  });

裡面打ajax跟資料庫取得資料。
而在做這一步前,記得在開頭要引入ujs

import Rails from '@rails/ujs'
這可以讓我們可以在不更動原有的controller的情況下,就能用Rails的慣例處理route與action。

完成圖:

Column的元件搞定啦~~

這篇鐵人賽的文,從做專案到寫文章研究了大概五到六個小時...(擦汗)
但第一次成功地在專案使用Vue.js生命週期的概念,很有收穫~

明天要來寫Ticket的元件!


上一篇
[VR 前後端交響曲Day18] Rails專案開發 - 第2個Model: 建立看板 Kanban
下一篇
[VR 前後端交響曲Day20] Rails專案開發 - 建立Vue元件: Ticket component
系列文
「VR 」前端後端交響曲 - 30天開發 Vue.js feat. Ruby on Rails即時互動網站30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

1 則留言

0
Bater
iT邦新手 4 級 ‧ 2020-10-04 15:56:07

一天一天功能越來越完整,真有成就感!

/images/emoticon/emoticon08.gif請為我加油XD

我要留言

立即登入留言