穠纖合度的整合 Rails、Webpack、Vuejs

前言

如果您曾經閱讀過小弟的vue + webpack 起手式一文,裡面我曾提到關於容易與傳統 MVC 框架(Rails, ASP.NET MVC)等結合。這篇文章主要就是用來介紹其作法與為什麼我會這麼說。

我先承認吧!我不總是需要使用 SPA 的架構 雖然它很好,但對於很多小型專案,或者我們應該說 UI/UX 設計本身非常單純的專案 - 殺雞焉用牛刀。所以這邊文章的作法針對的是那些專案不是使用 SPA 搭配 API 的架構的人,而是您覺得既有的 MVC 框架對於您的需求開發已經非常足夠且想保留大多數這些框架提供的功能(本文僅針對 Rails 介紹)。

網路上有非常多關於 Rails 與 Webpack 整合的方式,其實都非常不錯。而關於本文只是介紹其中一種小弟認為剛剛好的整合方式,其中許多觀念都不是新創的,都只是整理過去學習經驗而成。

繼續閱讀

Heroku 運行類別、 Procfile、常用指令筆記

Procfile 是一種定義指令是否可以在 Heroku dynos(一種輕量化的容器,可以執行特定用戶設定的指令)上執行的機制。
它遵循著 Unix 的程序模型(process model)。這裡為了簡化概念,我們可以說 dyno 就是執行指令的一個個體。舉例來說一個 web dyno 就意味著執行一個 web server 的程式。希望這樣的說明可以理解這些特殊的名詞概念。

繼續閱讀

Vue.js in Slim 語法的小問題 Slim::Parser::SyntaxError

當我們使用 Vue.js 搭配 slim 時(事實上 Angular 應該也有相同的問題)時

1
2
3
4
5
6
7
8
9
10
div id="app"
p {{message}}

javascript:
new Vue({
el: '#app',
data: {
message: "Hello, Vue.js"
}
})

立馬收到Slim::Parser::SyntaxError的錯誤訊息。

但是改成這樣卻又正常

1
div id="app" {{ message }}

好啦!答案很明顯了就是我們有地方寫錯,讓 slim engine 誤會了。

這邊紀錄一下解法:

補上屬性

第一個最簡單的方式就是幫 p 補上隨意一個屬性

1
2
3
4
5
6
7
8
9
10
div id="app"
p class="" {{ message }}

javascript:
new Vue({
el: '#app',
data: {
message: 'Hello Vue.js',
}
})

加上 [], (), {} 任何一種

1
2
3
4
5
6
7
8
9
10
div id="app"
p () {{ message }}

javascript:
new Vue({
el: '#app',
data: {
message: 'Hello Vue.js',
}
})

使用 |

1
2
3
4
5
6
7
8
9
10
11
div id="app"
p
| {{ message }}

javascript:
new Vue({
el: '#app',
data: {
message: 'Hello Vue.js',
}
})

修改設定

上面的解法都是因為 slim 預設會把 {} () [] 和 tag 後面接的 property=value 當作屬性(attributes)來解析。
所以我們只要把 {} 拿掉就正常了。

新增或修改 config/initializers/slim.rb 加入

1
Slim::Engine.set_options :attr_list_delims => {'(' => ')', '[' => ']'}

關於 delete 變數詭異行為與解釋

問題

發生在當我們撰寫下面程式碼的時候所發現的奇怪行為。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
var a = 1;
b = 2;

console.log(a); // 1
console.log(b); // 2

// 使用瀏覽器測試請使用 window 如果是用 node 的 REPL 環境那請改成 global
console.log(window.a); // 1
console.log(window.b); // 2

// 但接下來這麼操作

delete a; // false 不能刪
delete b; // true 可以刪

a; // 1
b; // undefined

解釋

首先根據ECMA-262 §10.3,的定義 Variable environment 是一種特定
型別的 Lexical environment,我們沒辦法透過任何方式直接存取。

一個 Lexical environment 用來記錄執行環境的資訊,可以把它想成是一個物件,我們會把在一個執行環境 Context的變數,函數都存在這個物件的屬性上
針對函數那些定義的參數(Parameter)也會被記錄,舉例來說 function foo (a, b)() 中的 ab 就會被記在 foo 的執行環境資訊中。

一個 Lexical environment 也有一個連結可以連結到外在的 Lexical environment 就是所謂的 scope chain
這個機制可以協助我們取得目前執行環境以外的變數,舉例來說就是 function 裡面可以拿到 global 的變數。

一個 Variable environment 就只是 Lexical environment 的一部份,本質上就是透過 var 宣告在執行環境中的變數或函數。

使用了 var

上面的 a 使用了 var 根據 ECMAScript 定義會被記錄在 Variable environment 根據定義 Variable environment 是不能手動刪除的。
也就是說除非用了 eavl,否則是不能被 delete 的。

1
2
3
4
5
6
7
var a = 1;
delete a; // false
console.log(a); // 1

// 記得清除整個環境
eval('var a = 1; delete a; console.log(a)'); // undefined

沒使用 var

當我們賦值卻沒有用 var,Javascript 會嘗試在 Lexical environment 尋找同名的參考。
最大的不同是 Lexical environment 是嵌套的,就是它可以關聯到外面其他的 Lexical environment
當在本地找不到的時候就會往上層去找,換句話說每個 Lexical environment 都有個爸爸,而最外層的就是 global
所以當我們不使用 var 而宣告一個變數時會開始在各個 scope 尋找同名變數,最終 Javascript 會拿一個 window(global) 的屬性來當作參考。
而物件的屬性是可以刪除的。

結論就是第一個 var 的變數被放在 Variable environment 是不能 delete 的而第二個沒有 var 的變數它是 global 的屬性。

然後你就會問我,那為什麼第一個 a 可以用 window.a 取得,因為全域的 variable object 就是 global(window) 本身。
但誰是屬性誰放在variable environment是有差的,因為程式碼看起來沒差所以會搞死人啊。

開發時期,CarrierWave 重產不同 version 圖片

當增加不同 version 的尺寸需要對已上傳的圖片從新產生新尺寸的圖片時

1
> rails c

輸入

1
2
3
4
Attachment.all.each do |att|
att.image.recreate_versions!
att.save!
end

Heroku 無法 fetch gem

當我們在本機設定 gem 的時候有時候會採用直接從 github 下載的方式

1
gem 'datetimepicker-rails', github: 'zpaulovics/datetimepicker-rails', branch: 'master', submodules: true

不過當我們要把程式碼部署到雲上的主機時,有些時候會碰上該機器無法去 fetch repo 的狀況

這個時候請參考這邊改變設定即可

rake db 常用指令備註

1
2
3
4
5
6
7
8
9
10
11
12
$ rake db:create          # Create the database from DATABASE_URL or config/database.yml for the current Rails.env (use db:create:all to create all dbs in the config)
$ rake db:drop # Drops the database using DATABASE_URL or the current Rails.env (use db:drop:all to drop all databases)
$ rake db:fixtures:load # Load fixtures into the current environment's database
$ rake db:migrate # Migrate the database (options: VERSION=x, VERBOSE=false)
$ rake db:migrate:status # Display status of migrations
$ rake db:rollback # Rolls the schema back to the previous version (specify steps w/ STEP=n)
$ rake db:schema:dump # Create a db/schema.rb file that can be portably used against any DB supported by AR
$ rake db:schema:load # Load a schema.rb file into the database
$ rake db:seed # Load the seed data from db/seeds.rb
$ rake db:setup # Create the database, load the schema, and initialize with the seed data (use db:reset to also drop the db first)
$ rake db:structure:dump # Dump the database structure to db/structure.sql
$ rake db:version # Retrieves the current schema version number

Devise 快速上手

devise 使用筆記

Devise 是一套彈性的驗證機制解決方案,它是根據 Warden 為架構的基礎延伸的。Devise 本身具備

  • 支援 rake
  • 架構在 Rails 之上提供完整的 MVC 方案
  • 提供您可以使用多個 Model 在同一時間登入
  • 模組化,您只需要採用您需要的部份
繼續閱讀

ActionPack 雜記

Action Pack

Action Pack 是整個 Rails 的核心部份,由 ActionDispatch, ActionController, ActionView 組成
ActionDispatch 處理接收到的請求(Requests),即網址的部分,ActionController 負責把請求對應轉換成回應(Responses)
接著 ActionController 調用 ActionView 來處理回應的格式(html, js, json, xml) 等

繼續閱讀

ActiveRecord 雜記

優化 Model count

1
2
3
class Like < ActiveRecord::Base
belongs_to :guestbook_entry, counter_cache: true
end
繼續閱讀