iT邦幫忙

2022 iThome 鐵人賽

DAY 14
1

完成 view 以及 controller 後
我們就要來做 model 拉!

建立 File-Based Models

我們的 model 會以 file 為基礎,會使用 JSON 文件格式

step 1 打開 rainbow.gemspec

加入 multi_json 套件

# rainbow/rainbow.gemspec
  gem.add_runtime_dependency "rack"
  gem.add_runtime_dependency "erubis"
  gem.add_runtime_dependency "multi_json"
end

Rails 的許多應用程式及函式庫是基於套件而建構而成

當我們在部署大型專案時,不需要安裝好幾個套件,讓整個系統保持乾淨、簡潔

安裝 multi_json

> bundle install

我們用 JSON 主要是因為好讀、好寫的特性

來看一下,我們該怎麼建立一個 JSON 物件

{
  "submitter": "Jeff",
  "quote": "A penny saved is a penny earned.",
  "attribution": "Ben Franklin"
}

接下來我們來建立 db

step 2 建立一個資料夾

建立 best_quotes/db/quotes,其中 db 會作為資料庫

quotes 子資料夾會包含一個表格

裡面有 quote 的 JSON 資料

在這之前,我們需要先建一個 Rainbow 物件

打開 rainbow/lib/rainbow.rb

增加一個套件 file_model

 # rainbow/lib/rainbow.rb (excerpt)
    require "rainbow/dependencies"
    require "rainbow/controller"
    require "rainbow/file_model"

打開 rainbow/lib/rainbow/file_model.rb

# rainbow/lib/rulers/file_model.rb
  require "multi_json"
  module Rainbow
    module Model
      class FileModel
        def initialize(filename)
          @filename = filename
          # If filename is "dir/37.json", @id is 37
          basename = File.split(filename)[-1]
          @id = File.basename(basename, ".json").to_i
          obj = File.read(filename)
          @hash = MultiJson.load(obj)
       end
       def [](name)
         @hash[name.to_s]
       end
       
       def []=(name, value)
         @hash[name.to_s] = value
       end
       
       def self.find(id)
         begin
           FileModel.new("db/quotes/#{id}.json")
         rescue
            return nil
         end
       end
     end 
   end
end

初始化時,我們把檔案做切分,然後取最後一個

MultiJson 可以從 Ruby hash 做簡單的編碼及解碼,他會以多工的方式進行解碼,跟 Rails 運作機制一樣

我們有一個 square-bracket 方法,所以可以做到像 Rails 中的 hash 引用 key 的模式

你可以寫 obj["field"] 而不是 obj.field

在 Active Record 中,你會根據參數或者 ID 建立一個物件

假設是使用 ID 來建立,你就得先尋找這個物件的 ID

我們來快速看一下 self.find(id) ,他會幫我們去搜尋物件的 id

假設我們在字串中插入 #{},他會自動把裡面的東西轉換成字串

如果 find() 找不到 id ,就會回傳 nil

Ruby 會用 FileNotFound 來解決這個意外

所以找不到的時候,我們要來設定 RecordNotFound 作為 exception

# best_quotes/app/controllers/quotes_controller.rb
  class QuotesController < Rulers::Controller
    # (excerpt)
    def quote_1
      quote_1 = Rainbow::Model::FileModel.find(1)
      render :quote, :obj => quote_1
    end
  end

再來用 view 來渲染

<%# best_quotes/app/views/quotes/quote.html.erb %>
  <p>
    &quot;<%= obj["quote"] %>&quot;
    <br/> &ndash; <%= obj["attribution"] %>
  </p>
  <p>
    Submitted by <%= obj["submitter"] %>
  </p>

現在,我們到 best_quotes 做 bundle
把 multi_json 這個套件加進來

重啟 server

http:// localhost:3001/quotes/quote_1

Model 就這樣建立好囉!

controller 擴充方法

讓 controller 擴充 model 的方法

打開 rainbow/lib/rainbow/controller.rb

在上面加一個 require

# rainbow/lib/rainbow/controller.rb (excerpt)
  require "rainbow/file_model"
  module Rainbow
    class Controller
      include Rainbow::Model
      #... 
    end
  end

把 model 資料渲染到 view 上

現在我們可以搜尋物件的 id

ActiveRecord 也提供了 find all 方法

打開 rainbow/lib/rainbow/file_model.rb

用 map 來對 files 裡的每個資料做一個做出新的實體

module Rainbow
  module Model
    class FileModel
      def self.all
        files = Dir["db/quotes/*.json"]
        files.map { |f| FileModel.new f }
      end 
    end
  end 
end

打開 best_quotes/app/controllers/quotes_controller.rb

增加一個 index 方法

# best_quotes/app/controllers/quotes_controller.rb
  class QuotesController < Rainbow::Controller
    def index
      quotes = FileModel.all
      render :index, :quotes => quotes
    end
  end

新增一個新的 view

<%# best_quotes/app/views/quotes/index.html.erb: %>
  <% quotes.each do |q| %>
    <p> <%= q["quote"] %> </p>
  <% end %>

這樣就完成囉


上一篇
Day 13 - 讓 view 更像 view
下一篇
Day 15 - Rack 的 Request 及 Response
系列文
從0開始刻 淺談 Rails 的運作魔法30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言