about 6 years ago

經過我們不眠不休(真的是不眠不休...)的努力!Logdown 現在支援 Custom Theme 了!

設定位置:

佈景的設定在 Blog > Settings > Theme 。

目前我們官方提供三個已經客製好的 Theme。並且也提供 Customize HTML 的選項。在未來幾週內,我們會釋出更多官方客製的好的 Theme。

歡迎馬上登入 試用!

API 文件:

我們目前整理了一些佈景的 API 用法放在:

http://github.com/logdown/themes-guide

不過因為剛開放這個功能,文件還不是寫的很完整,你可以直接看佈景原始碼,了解一個 Blog 大概要怎麼編排。如果你有想要我們開發的新 API method 也歡迎上去開 issue。我們會設法加進去。

Submit 自製 Theme

我們的 Theme 都會放在這邊。若你想要 submit theme 的話。請 fork 這個 theme repo 並且拉 pull request。我們會在收到你的 Theme 之後僅快審核上架。

http://github.com/logdown/themes

 
about 6 years ago

上篇: Secure Your Application : The Basic (3)

7. Same secret token

Rails project 裡的 config/initializers/secret_token.rb 這個檔案。裡面的 secret_token 是用來 verify signed cookie 的。在產生 Rails project 時,每個 project 也都會生一把不同的 key...

狀況 1 : fork opensource project

不過如果你的 project 不是你產生的,而是 Github 上 clone 的呢?那麼有 99% 的機率,你這個 application 已經暴露在高度風險之上。

  • clone 的人忘記跑 rake secrect 產生一把全新的。
  • opensource 的人忘記把 secret_token.rb 設進去 .gitignore
  • google://secret_token.rb site:github.com 超精彩...

狀況 2 : opensource project owner

  • opensource 的人忘記把 secret_token.rb 設進去 .gitignore
  • 而且 production 用的就是這一把...

該檢查的地方以及怎麼處理

  • 如果你的 application 是從 github 上 fork 下來的。抓下來第一件事就是砍 secret_token.rb,重跑 rake secrect
  • 如果你是 opensource project 維護者,發布之前,請砍掉 secret_token.rb,設進 .gitignore,然後換 key。
  • Redmine 的作法是預設移除,然後設進 .gitignore
  • Discourse 的作法是保留,但用 condition 設定 production 和 development 跑不同的 token,production 跑的是環境變數:ENV[‘SECRET_TOKEN’]

8. scopes

很多 Application 是這種常見的設計,利用一個 check_permission 去應付多種狀況。

class TopicsController < ApplicationController
  before_filter :login_required
  before_filter :check_permission, :only => [:edit]
  def edit
    @topic = Post.find(params[:id])
  end
end

但是 check_permission 的狀況很容易不小心寫漏了,就能夠進到該頁面。

問題與解法

  • by case 設計在 controller 不是好解法,因為 helper / view 有時候也需要類似邏輯
  • 邏輯經過幾次擴充之後就變成漿糊了。擴充了 Controller 忘記改 View ...etc.
  • 改用 Cancan 這種 Rule Engine 式的設計方法,全上黑名單,再一個一個設白名單解開,而且寫一次可以套用在所有地方。

9. Upgrades

Rails 在 3.2.11 前的版本,都有一個致命漏洞:可以被 Remote code execution。Remote code execution 表示攻擊者可以對你的 application 你的 server 作 任何事

原理詳見:http://blog.codeclimate.com/blog/2013/01/10/rails-remote-code-execution-vulnerability-explained/

基本上只要這個洞還留著。其他地方再怎麼防都沒有用

解法

  • 升級到 3.2.11+


Recap

Security 是一件讓人很頭痛的事。Rails 的 core member : Aaron Patterson 就曾經抱怨,其實他最討厭處理 securtiy
事件。

  • 因為,attacker 不會主動回報,就算它跟你講了,你也不知道這個洞已經多久了
  • 即便他好心跟你講(寫信到 Rails security mailing list),你也只有「很短」的時間修。很短可能是幾天,也可能是幾小時,但總之...火會燒得超級快。每次遇到資安事件,security team 的人就不用睡了...
  • patch 得馬上得 Release。不同於其他 feature release,feature release 都會有時間公測。唯有 security patch 沒有這個時間。而這種 patch 最危險的是不保證會不會炸了其他沒問題的地方。(某次 patch 炸了 Github ...)
  • 你努力了拯救了整個世界,但沒人會感謝你。但如果你寫的 patch 炸爛了大家的 production,肯定一堆人角你...

洞是真的防不慎防的。

有時候就算框架本身是沒問題的。但是還是會因為人為疏失被摸進去。

不過如果是人為疏失,其實還是有幾招可以降低發生的機率:

  1. 注意使用者塞給你的東西 Pay attention of user geneate content
  2. 不要繞過 Rails 的預設機制 Avoid bypass default design
  3. 盡量套用 Rails 4 的新機制 Apply new features introduce by Rails 4
  4. 不要忘記更新 Don’t forgot to upgrade


全集連結:

投影片:http://xdite.github.io/security-basic

 
about 6 years ago

上篇: Secure Your Application : The Basic (2)


5. bypass HTML Escape

Rails 預設對所有 helper 出來的字串,先都過了一層 html escape。所以是相當安全的。

def render_post_title(post)
  link_to(post.title, post_path(post))
end

但是,在開發者設計一些複雜的元件時,通常會不小心打破這個原則。如美術設計師對該元素下了複雜的 HTML,程式設計師為了貪方便可能就會這樣串接,最後再下一個 raw / html_safe ...

def render_post_title(post)
  str = “”
  str += <li>
  str += link_to(post.title, post_path(post))
  str += </li>”
  return raw(str) 
end

原來那層天然防護罩就不見了。

網站上哪一些設計容易有這種問題:

  • 列表 list
  • 麵包屑 breadcrumb
  • user name with glyphicons

解法:

回歸最初,該是 HTML 的就不要用 helper,用 partial

def render_post_title(post)
  render :partial => "posts/title_for_helper", :locals => { :title => post.title }
end

也可能有問題的地方:TinyMCE on UGC

有些網站被迫要讓使用者使用 TinyMCE 這種所見即所得的工具。但是這種工具危險之處,在於裡面塞的 HTML 可以非常的有創意...如:

  • img
  • table
  • tbody
  • div
  • span

都是高危險地帶。

可能的解法:

Rails 提供消毒 Helper。可以設白名單黑名單..

def s(html)
  sanitize( html, :tags => %w(table thead tbody tr td th ol ul li div span font
   img sup sub br hr a pre p h1 h2 h3 h4 h5 h6),
   :attributes => %w(style src href size color) )
end

6.bypass SQL escape

Rails 在 ORM 裡面也預設提供 SQL escpe,所以這種 query 是安全的:

  User.where([name LIKE ?”, params[:q])
  # safe

但是有些時候,開發者為了實作某些功能,就會不小心用了 find_by_sql

  User.find_by_sql("name LIKE &rsquo;%#{params[:q]}%&rsquo;")
  # not safe

或者是開發者根本就不知道 where 的正確用法,在網路上 google 到一個 sample 會動就丟進去了:

  User.where("email = '#{params[:email]}'").first 
  # won't escape

高危險地帶:

  • Search Functions
  • actions with complex options, ex. :date, :order, :field
  • actions with complex joins
  • find_by_sql, count_by_sql

解法

  • 如果只是搜尋的話,可以改用 ransack 這種 gem,可以用相當漂亮的 DSL 設計出複雜的 SQL search,都沒有 SQL Injection 問題..

  • 設計 Application 時,優先使用 ORM 解,非不得已為了效能才手 drop query

延伸資料


下篇: Secure Your Application : The Basic (4)

 
about 6 years ago

上篇: Secure Your Application : The Basic (1)


3. bypass RESTful

RESTful 是初上手 Rails 的開發者,相當討厭的一個課題。因為沒有很好懂,加上被認為不自由。總之,不遵守 RESTful 設計原則原因有很多

  • 老子就是討厭 RESTful
  • 我...不懂 RESTful 要怎麼寫
  • 真的有必要把任何 action 都走 RESTful 嗎?

但是,很多開發者不知道的是:雖然 Rails 提供了 CSRF protection,攻擊者發了錯的 request,就會被導錯誤 422。但是,這樣的預設防禦只在遵守 Rails RESTful 設計規範的情形下運作。

在 Rails 3 的 routes.rb 最下面有一段被註解掉的 code

config/routes.rb
# This is a legacy wild controller route that's not recommended for   RESTful applications.

# Note: This route will make all actions in every controller  accessible via GET requests.

# match ':controller(/:action(/:id(.:format)))'

很多開發者在不知道怎麼設 routing 的情況下就把 match ':controller(/:action(/:id(.:format)))' 這行打開了。

因為打開,程式就可以動了 .....(汗)。

可以繼續快樂的寫 http://example.com/usses/eat/1234 這種直觀的 routing,而不用去管 Rails RESTful 的原則...

這等於把自家大門敞開任人打 XD。

因為 Rails 防禦 CSRF 攻擊的原則上是若對 routing 送了錯誤的 http verb 或者是送了錯的 Authenticity Token,Rails 就視為非法 request 導掉。但是 match everything 的結果是,所有的 action 都變成了 GET,一些需要保護的 POSTPUT action 就門戶洞開了。

可能的解法:

  • routes.rb 幹掉 match ':controller(/:action(/:id(.:format)))' 這行
  • 設立 coding policy,嚴禁任何人再把他加回去。

Rails4 起也已把預設的這行 example 拿掉了...

4. match in routing

這要從 routing 開始講起。

在 Rails 3 時,因為...我也不知道的原因,match 等於 matches all HTTP verb。而所有的 custom routing 的教學都推薦用 match 去實作。所以很多 application 裡的 route 很歡樂的到處都是 match

但是,到處都是 match 就會造成下面的這種類似的 code 會有中招的風險。(allow using GET to massive delete articles)

match "article/delete/:id", :to => "articles#destroy" :as => "delete_article"

解法

  • 檢查 routes.rb 幹掉所有的 `match,改用正確的 HTTP verb
  • Rails 提供正確的 verb 用法可以取代掉 matchget, post, put , delete

所以上面的 example 可以改成

delete "/article/delete/:id", :to => "articles#destroy" :as => "delete_article"
  • 或者是改用 via
match "/article/delete/:id", :to => "articles#destroy", :as => "delete_article", :via => :delete


下篇: Secure Your Application : The Basic (3)

 
about 6 years ago

這是我六月初在新加坡 Reddot Ruby Conf 給的演講。原稿投影片放在 Github 上。這篇文章是我自己整理的 Note。

其他的演講多半是重談 OWASP 那些標準需要注意的地方。這個演講當時在設計時,刻意跟其他演講不太同調。原始設計的出發點著重於:如果是一個熟 Rails 架構的 Hacker

(1) 會如何進攻你的 Application
(2) 初學者會在架構設計上犯哪些錯?
(3) 如果你是 Application 設計者,如何一開始就設計出相對安全的架構


在談 Security 之前,我們要來談談 Rails 是不是個「安全」的框架?

平心而論,Rails 的預設是比許多框架要「安全」許多的,它的設計預設就防了很多攻擊手段、屏蔽了開發者設計上的盲點,或者是預設就內置許多最佳實務。

  • Helper / View 預設提供了 HTML Escape : 防止 XSS
  • ORM 預設提供了 SQL Escape : 防止 SQL Injection
  • 表單提供 Authenticity Token :防止 CSRF
  • 在 Production mode 錯誤時直接扔 500 頁面:防止 PHP 忘記關 debug mode 結果吐程式碼這種慘劇...
  • 熱門的使用者驗證 Gem 如 Devise 直接內置密碼 Bcrypt 加密 :有些開發者懶得自己寫加密 function 乾脆明碼 password 直上
  • Sensitive data filtered from log:Rails 的 Log 自動會濾掉一些關鍵字如 [password],以免幹到 Log 就超精彩..
  • 熱門的上傳 Gem 如 Paperclip 內建 Filename Sanitization 的實作:防止 path attack

很多傳統打 PHP 網站的方式,是很難拿來直接打 Rails 的,因為一些常見的路都預設被堵死了....

但。這就表示 Rails 不好打嗎?

這也未必。Rails 是個「Framework」。所以其實也有「Pattern」可以依循。一般要打下一個站,去找 Framework 0day 效率通常太低了。找常見的「人為錯誤」其實是比較快的方式...

1. Massive Assignment

Rails 在表單設計上提供了強大的 Helper,表單的 attribute 直接對應到資料庫的欄位。

<%= f.text_field :title %>
<%= f.text_field :body %>

會生成

<input id="topic_title" name="topic[title]" size="30" type="text">
<input id="topic_body" name="topic[body]" size="30" type="text">

看出規律了嗎?所以如果是這樣,從 Chrome DOM Inspect 塞...

<input id="topic_title" name="topic[title]" size="30" type="text">
<input id="topic_body" name="topic[body]" size="30" type="text">
<input id="topic_user_id" name="topic[user_id]" size="30" type="text">

通常就可以達到目的...

因為大部分的 Rails Developer 都會寫出這樣的程式碼:

app/controllers/topics_controller.rb
class TopicsController < ApplicationController
 
   def edit
     @topic = Topic.find(params[:id])
     if @topic.update_attributes(params[:topic])
       redirect_to topic_path(@topic)
     else
       render :edit
     end
   end
end

注意 @topic.update_attributes(params[:topic]) 那一段。

也有風險的地方:role_ids

除了單一 attribute 會被攻擊外,另外還有一個虛擬的 attribute 設計會有風險。

在這個 user model 裡,使用者擁有很多角色。

app/models/user.rb
class User < ActiveRecord::Base
  has_many :roles
end

Rails 提供一個十分方便的設計。user 可以會自動擁有一個虛擬的 attribute role_id 可以用。role_id 是 Getter 也是 Setter。

如果你在系統的 rails console 下這樣的指令

  user.role_id = [1,2,3]

Rails 會自動幫這個 user 設上 Role id = 1, 2, 3 的三個角色。之所以會有這個「貼心」設計,是因為「大家」都用 checkbox 作多選角色,所以內建了這個設計方便一次設定上多個角色。範例 code 如下:

<% for role in Role.all %>
    <%= check_box_tag "user[role_ids][]", role.id, @user.roles.include?(role) %>
    <%=h role.name.camelize %>
<% end %>
<%= hidden_field_tag "user[role_ids][]", "" %>

但這也就表示,其實你的 application 有可能被這樣的假 DOM 玩到的風險....

<input id="user_title" name="user[title]" size="30" type="text">
<input id="user_body" name="user[body]" size="30" type="text">
<input id="user_role_ids" name="user[role_ids]" size="30" type="text">

特別是大家都曉得 role_id = 1 通常就是 admin

需要被檢查的地方:

  • has_many, has_many :through involve OWNERSHIP, Permission
  • user_roles, group_users, ….
  • UPDATE action

幾個可能有效的解法:

Rails 3 可以用的解法

( 這個方法在 Rails4 裡被移除了)

  • 使用 whitelist attribute
  • 打開 config.active_record.whitelist_attributes = true
  • 在 model 裡設定 attr_protected :roles
推薦的作法,同時也是 Rails 4 解法
  • 使用 Strong parameters。( Rails 4 如果沒過 permit 會直接丟 exception,算直接根除)
  • params.require(:topic).permit(:title, :body)

進階做法

使用 Reform。出發點是 validation 的責任不應該在 Model 身上,也不該丟給 Controller 去解決,這件事應該要在 Form 層面被解決掉。Reform 的作者同時也是 Cells 的作者 apotonick。

def create
  @form = SongRequestForm.new(song: Song.new, artist: Artist.new)
 
  if @form.validate(params[:song_request])
  ....
require 'reform/rails'

class UserProfileForm < Reform::Form
  include DSL
  include Reform::Form::ActiveRecord

  property :email,        on: :user
  properties [:gender, :age],   on: :profile

  model :user

  validates :email, :gender, presence: true
  validates :age, numericality: true
  validates_uniqueness_of :email
end

2. Admin

第二部分要談的是 Admin 的設計。這部分也是很讓人無言的。根據非官方統計,高達...99% 的開發者會把 admin 後台放在 ... /admin...XD

http://example.org/[admin]

這樣的設計有幾個 concern :

  1. 容易被猜到放哪裡
  2. 容易被 XSS 打到

通常建議的解法

把 admin 拆到其他地方去,如 subdomin,或者是不同 domain。

http://[admin].example.org
http://[admin].example.net
https://[admin].example.org
https://stop-here.myapp.in

一些其他的基本解法

  • 拆到 Intranet 上。(Ineternet 上基本找不到)
  • WiteList.contains?(request.remote_ip) 只准白名單
  • 拆到另外一個 Admin App 去管

也有風險的地方:admin?

這也是另外一個有風險的部份。關於 admin? 的實作。多數的開發者,是這樣做的:

  def admin?
    is_admin
  end

然後,就被針對 massive assignment 的攻擊打下來了...

一些解法

  • Setting.admin_emails.include?(email) // 起碼沒有那麼直觀
  • 使用第三方驗證 gem : 如 Github 的 team warden-github-rails 作驗證。想法是:Github 比你家難打太多了....XD 而且其實會是 Admin 的人通常也是 Github 這個 repo 的參加者,用這種方式去驗證比較方便...


下篇: Secure Your Application : The Basic (2)

 
about 6 years ago

原文 原本放在我另外一個 blog。後來覺得屬性應該適合貼在這裡,就轉貼過來了。

這集的 Teahour 的連結在這裡: http://teahour.fm/2013/08/05/interview-with-tinyfool-on-xinzazhi.html [与 Tinyfool 聊新媒体、创业经历和团队建设]


禮拜三跟 Teahour 的主持人玎玎和這期的嘉賓 Tinyfool 聊創業(會前會)。中間岔題講到 Tinyfool 開始想把自己的創業公司轉換成 Remote 工作環境。有過 Remote 經驗的我和玎玎就七嘴八舌的給 Tinyfool 了非常多意見。十幾分鐘講下來,原來大家的經驗看法幾乎都是一樣的。趁還有熱情寫這個題目,順便在 blog 把重點整理一下...

參與成員必須都要是 Senior 等級的開發者

根據所有人的經驗,Junior 是絕對不能參加 Remote 的。原因有幾個,

(1) Junior 不管在專業上或者是做事方法與態度上,都有很大的磨練空間。如果 Remote 反而會因為無法近距離與同事交流,學習的速度變得緩慢。
(2) 在 Remote 的環境中,時刻與同伴保持若即若離的非同步方式合作的技巧難度非常高,如果沒有成熟的技巧,反而會造成效率低落和合作上的挫折。
(3) Remote 其實是比較辛苦的,因為工作者反而要依靠一些遠端輔助工具,補足同步節奏的問題。但是 Junior 的做事模式和認知是「有完成交辦任務」就好。所以在 Remote 時,反而會覺得比較爽,因為沒有人管,只要「做好手頭上的事」。能完成的事品質反而比較差,打亂大家的節奏...同時也會因為「有做完就好」,變得高興什麼時候作就什麼時候作(不顧團隊節奏),晨昏顛倒(因為精神較差所以只能 deliver 出次等的程式碼)。

團隊內有很好的協作與自動化工具

  • Issue Tracking ( 如 Redmine, Pragmatic.ly )
  • Chatroom ( 如 Hipchat, Skype)
  • Code Version Control ( 如: Git or Github )
  • Log Channel ( 如 Redmine issue, Github commit log 結合 Hipchat )
  • Screenshot Tool ( 如 droplr.com )

團隊合作處理的都是比較大等級的專案,「比較大」通常意味著這個專案會有非常多 Task。在很多 Task 的狀態時,必須要有一個工具可以很好的將 Task 依序列出,有優先等級管理,有歷史紀錄,有應答功能。讓大家不至於互踩到手腳,使用版本控制管理系統也是相同的道理。

Chatroom 則補足無法面對面交流的狀況,若文字與圖片示意還是不夠,則直接使用語音交聊。

Log Channel 則是一種交流型輔助,因為 Issue Tracking 和 Code Version Control 往往都還是使用 Email 寄信輔助(有等於沒用),團隊需要一個可以一目了然今天專案即時動態的地方。Log Channel 是很好的 Dashboard。

團隊內要有 Coding Policy

除了外在的輔助工具外,內部的規矩也是很重要的。Code 要怎麼設計才能讓同事快速接手?什麼樣的設計與命名絕對不能出現,以免同事一進來就踩中地雷陣亡。或者是花上太多不必要時間的時間除雷...

團隊必須要有一致的工具默契與設計默契。如果沒有,那就必須設計一套,強迫大家遵守。

對事不對人的默契

因為大家都不是面對面,用文字和聲音交流,很容易因為一個差錯,就擦槍走火變成糾紛。團隊成員要有高度對事不對人的默契,相信大家出發點都是為了把產品做好,而不是在爭功諉過。否則團隊反而很容易 Remote 造成的誤會分崩離析。

定期的 Standup 與 On-site meeting

Remote 時很容易因為都在埋頭做事,很容易不小心做著做著就偏離原先的航道或者是原先的 schedule。每天至少還是需要一次的 Standup,確保在正確的航道上。每週一次的 on-site,把需要高度合作的項目解決掉。

了解為什麼要 Remote

有很多人誤以為 Remote 是一種輕鬆的工作型態,或者誤以為 Remote 還可以順便省房租。事實上這都是錯誤的觀念,Remote 的成本其實相當高昂,若無法有效的團隊的協作的話,掉的生產效率折算成工錢可能還會是房租的好幾倍。

Remote 能夠提供的是

  1. 讓工作夥伴省下舟車通勤勞頓之苦,把節省下來的精力與時間,效益轉到在工作的成果上
  2. 在更適合自己的設備與環境下,高速專注的做事。
  3. 在更適合自己生理作息(非朝九晚五)的時間下,產出更好品質的成果。

這三件事的共通點,以一句話來總結,Remote 是為了把事情做得更好,產出能做出好成果的心裡的爽。而不是為了不做事,能夠當時間小偷竊喜的爽。

若是 Remote 缺乏這樣的環境、成員、心態,帶來的不會是高生產力,而是災難。

 
about 6 years ago

長話短說:想學好 Ruby on Rails,Tealeaf Academy 是你最佳的選擇

承諾我的朋友 @knwang 要寫這一篇很久了,但是一直被諸多事情拖到,現在來補寫...。相信認識我很久的人,都會知道我寫這篇文章相當不尋常。我一般不幫人廣告,我又是 Rails 這個領域的專家,很少會為其他人的實力背書,而且我從來不推薦我沒用過或者用過覺得不好的服務。

TeaLeaf Academy 是 我的朋友 @knwang 的創業公司,專精 Ruby on Rails 教學。創業至今,也在世界各地上教出了接近上百位 Ruby on Rails developer。Kevin 同時也是大陸知名 Ruby Podcast Teahour 主持人之一。

我自己教過很多人 Ruby on Rails,曾經出了一兩本有關於 Rails 的書籍,平常也會在社群裡面解答各式各樣的疑難雜症。很多人練完 Rails 101 之後,都會問我:「xdite,接下來我該學些什麼?」或者是「哪裡有課繼續上?」

在以往,我的建議都會是去找個工作開始實戰,而不是繼續上課。不過今年開始,我開始推薦想要立志練好 Ruby on Rails 的開發者,可以去報名 TeaLeaf Academy

為什麼呢?我們平日在指點 Ruby on Rails 的開發者,實際上都很清楚一件事情:坊間所有的書籍和教材是很難在短時間「教」出一個 Full Stack 的 Rails Developer 的。要成為一個 Solid 的 Ruby on Rails developer,唯有不斷的實戰,在實戰中不斷的累積經驗,再從線上開發者社群吸收社群最好的實務經驗不停地自我修正,才能達到這個目標。

市面上的入門書籍還有什麼七天的速成課程,是很難幫到你達到這個目標的。原因在 (1) 它們的內容,多半是簡單的 CRUD 加上一些現成的套件,讓你很快就能拼湊出一個煞有其事的 demo application。 (2) 多半是單方面的演示學習,也不會逼迫學生動手實作與課後練習。這樣的強度,多半只能讓學生在結業時達到所謂「略為熟悉 Ruby on Rails 的開發環境,可以開始基礎的修改擴增」的程度。不過,這樣也不能說這些課程沒有營養。因為實際上,光這樣的基礎內容,初學者要靠自己摸索,可能就要掙扎奮鬥接近一兩個月才能搞定了。

從很多的線上學習課程走向,如知名的 Codeschool 以及 Thoughbot 推出的 Learn Prime,你可以觀察到一個正確觀念以及趨勢。要所謂的「吸收成長」,課程的安排走向必須要「親自動手作」才行。但即使是這兩個公司,推出的課程也都只是「片段」。

而要快速的提升實力,則唯有加入一個實戰且有技術累積的團隊操練,有一個線上的 Application 待維護,有一個已企劃好的骨架可供實現。但是,這樣的工作機會不是到處都有。而這樣的工作機會,通常也少 offer 給「新手」。

而我會推薦 TeaLeaf 的課程關鍵原因,是因為 TeaLeaf 的內容提供了這樣的一個 option,他的內容不僅是「實際動手作」,更是一個完整的 full stack 的 project。在紮實的八個禮拜開發課程,你必須藉由完成每週的 assignment,最後親手搭建出一個 high quality 的 EC 網站,徹底學到開發一個實際的商務網站,你該準備練習的方向有哪些。而更值得一提的是 Kevin 的背景,Kevin 在創辦 TeaLeaf 之前,是美國知名 Rails Consultancy :Hashrocket 的工程師,在這個課程中你也可以實際上學到不少 Hashrocket 內部本身的開發精隨。

我會這麼清楚,是因為我五月時,真的實際的(自掏腰包)報名了 TeaLeaf 的課程,從當中學到了不少連我自己以前自學都難以精熟的開發技巧(這個課程裡面也有相當全面的 TDD 以及高階的 Service Design 主題)。平常我在網路上報名過不少高階課程,還是第一次報到這麼紮實的。

這裡有一份 Kevin 當初給我的課程清單 https://gist.github.com/xdite/4044f3a037de029bc35c

Anyway, 在上過這個課程之後, 要是有人想要請我教他 Rails, 或者是想要找 Rails 課程報名, 我都直接推薦他直接去上 Kevin 所開設的課程了。而且 Kevin 拆解課程觀念以及教學的技巧,真的都非常的棒。

目前 TeaLeaf Academy 的課程有三種:

  • Introduction to Ruby and Web Development: $475 for 4 weeks (如果你連 Web Development 都不熟的話,報這個)
  • Rapid Prototyping with Ruby on Rails: $610 for 4 weeks (如果你是跨領域來學 Rails,但懂 Web Development,報這個)
  • Build Production Quality Applications: $1485 for 8 weeks (如果你寫 Rails 有一年經驗以上了,來報這個)

不過對於他們的課程,我只有一件小事情想要備註而已。因為 Kevin 的課是採取 Remote 方式授課,以交作業與每週 Live Session 的方式進行。第三階段的課程分量是非常非常重的,Kevin 曾經跟我說他有學生上 Rails 課上到必須辭職才能專心上完這門課。我本來以為 Kevin 是開玩笑,哪那麼誇張。後來上了以後,真的覺得所言不假。連我自己的程度平均每一週都要花上 8 小時來寫作業。同學花到 3-40 小時的比比皆是。若說有人要非得辭職才能上完,我看也不是沒有可能。(請斟酌你的時間分配再行報名。不過要是中途 Kevin 發現你跟不上進度,他是同意讓你到下個班補上的…)

但是若你能堅持到最後,功力是真的會有非常非常的大躍升,這點是我也可以幫忙保證的。與其花一堆錢在 CRUD 上,我誠摯的建議不如把錢省下來在這個 program 上面。甚至我現在收人的標準,也是變成希望收從 Kevin 班上畢業的 Developer 了。

祝各位能夠早日能達成自己的目標 :)

P.S. 課程是以英文進行。但是 Kevin 是華裔,所以你私下寫 mail 問他時是可以寫中文的。

 
about 6 years ago

Yesterday, we changed Logdown's assets host from local to Cloundfront. One day later, many firefox users complained about the icons are broken.

We found out the reason is: Firefox doesn’t allow cross-domain fonts

Catalin Rosu nicely explains the situation and the reason behind it here:
http://www.red-team-design.com/firefox-doesnt-allow-cross-domain-fonts-by-default

And there were also some discussions on font-awesome-sass-rails issue tracker.

The fix:

Modify Nginx Config

Add these three lines to /opt/nginx/conf/nginx.conf

   if ($request_filename ~* ^.*?\.(eot)|(ttf)|(woff)|(svg)|(otf)$){
             add_header Access-Control-Allow-Origin *;
   }
/opt/nginx/conf/nginx.conf
   server {
   .....
      location ~* ^/assets/ {
          expires 1y;
          add_header Cache-Control public;

          if ($request_filename ~* ^.*?\.(eot)|(ttf)|(woff)|(svg)|(otf)$){
             add_header Access-Control-Allow-Origin *;
          }
          break;
      }
   .....
  }

Go to Cloudfront panel to purge old content

You can find out assets path from ~/project_name/current/public/assets, by typing ls -al fontawesome-webfont-*.*

fontawesome-webfont-009f6d1f667cc42c25e712ab3429cbc7.eot
fontawesome-webfont-b4d67f1e5651506c3e80d842ee67d6ba.woff
fontawesome-webfont-f1c2889911d212e1403b68eabc1a3a56.svg
fontawesome-webfont-fb7a72c810ec644f3c26dcca68638308.ttf

Go to CloudFront Panel, create a invalidation

paste

assets/fontawesome-webfont-009f6d1f667cc42c25e712ab3429cbc7.eot
assets/fontawesome-webfont-b4d67f1e5651506c3e80d842ee67d6ba.woff
assets/fontawesome-webfont-f1c2889911d212e1403b68eabc1a3a56.svg
assets/fontawesome-webfont-fb7a72c810ec644f3c26dcca68638308.ttf

Invalidate!!

Wait about 5 minutes or longer...

It takes time to invalid CDN cache, just be patient..

By typing curl -I "https://d1vzm1nztjpyu4.cloudfront.net/assets/fontawesome-webfont-009f6d1f667cc42c25e712ab3429cbc7.eot" -s, you can checkout the status.

Once the response shows Access-Control-Allow-Origin: *, it is done :)

HTTP/1.0 200 OK
Content-Type: application/octet-stream
Content-Length: 37405
Connection: keep-alive
Server: nginx/1.4.1
......

Cache-Control: max-age=31536000
Access-Control-Allow-Origin: *
Accept-Ranges: bytes
Age: 277
Via: 1.0 96d42faebb6637ed78ff5050f67e2560.cloudfront.net (CloudFront)

.....

 
about 6 years ago

We recently launch subdomain & custom domain features in our product: Logdown, a Markdown Blogging Platform.

People keep asking me how to implement, here is how :

(1) Constraint Routing

config/routes.rb
  constraints(Subdomain) do
    get '/' => 'posts#index'
    
   
    resources :posts do
      collection do
        get :search
      end
    end
  end 

And in Subdomain class:

If it doesn't match logdown.com & www.logdown.com, then it goes straight to the constraint routing.

lib/subdomain.rb
class Subdomain
  def self.matches?(request)

    case request.host
    when Setting.host, "www.#{Setting.host}", nil
      false
    else
      true
    end  
  end

end

(2) Find Current Blog

In PostsController, we also build a method find_blog to find @current_blog.

The sequences will be : subdomain => custom domain => Not Found

app/controller/posts_controller.rb
class PostsController < ApplicationController

  before_filter :find_blog
  
  def find_blog
    case request.host
    when "www.#{Setting.host}", Setting.host, nil
    else     
      if request.host.index(Setting.host)
        @current_blog = Blog.find_by_subdomain(request.host.split('.').first)
      else
        @current_blog = Blog.find_by_fqdn(request.host)
      end

      if !@current_blog
        redirect_to Setting.domain
      end

    end  
  end
  
end

(3) Nginx Setting

/opt/nginx/conf/nginx.conf
    server {
      listen 80 default;
      .....
    }

The code is very simple, but it tooks me lots of time to figure out...

 
over 6 years ago

兩年前在舊部落格寫過一篇Web Startup 適合使用的服務與工具。最近整理舊部落格翻到這一篇,內容已經蠻過期了。這次我做Logdown 時又用了不少新工具,覺得可以來 Update 一下....

語言框架與工具

Ruby on Rails :

這還是我個人的首選

Bootstrappers

這是我過去一年來用來快速架站的工具,Best Practices 超級懶人包。跑完一次 generator,一個網站起手式該有的必備元件都有了。

chef-solo

我們公司有養 chef-solo 的 recipe,針對 Linode 和 Amazon EC2 都可以一鍵 deploy 直接開一台 Rails production-ready 的機器。

主機

Linode

Linode 現在還是首選,而且這幾年增開了東京點,蠻適合台灣的網站起步的。當然也是可以使用 Amazon EC2,但 Linode 的方便之處就是可以有 panel 快速開,快速升級。

I want my name

這是我近年來買網域的好去處,只要下好關鍵字,它可以幫你搜尋各種可能,價格也蠻優惠的。後台整合好不少 service,域名買下來照後台的 service 跑 SOP,很快可以把基本的東西都 setup 好。

團隊工具

Redmine

我們團隊的開發習慣還是開滿手的 issue,然後開始排優先權,利用 ticket branch 做 pull reqest 開發。

紙筆

信不信由你,這是我們開工前一天的草稿。在開工後就全憑默契在最初的 10 hr 內把編輯器和後台做完了...

這一兩年也是發現紙筆和 git branch 最有效率。

Github

Giuhub 應該就不用講了....這幾年應該都是標配。我們的開發習慣都是切 branch,如果需要 cowork 就幾個人在一個 branch 上合作接力。

Hipchat

今年捨棄了以往的 IRC 與 skype 搭配組合,改用 Hipchat,原因已經寫在 http://blog.xdite.net/posts/2013/04/01/move-to-hipchat/。我們開發中會把各式各樣的動作掛上 Hipchat trigger,確保同事們知道當前進度...

Droplr

我們在頻道裡面的截圖交流大部份是使用 Droplr 這個工具,截圖後馬上可上傳,支援手機傳圖。很多原型我們都是利用手機拍了之後上傳然後貼到頻道裡。這套 Mac Store 裡有得抓。

Skitch

Skitch 也是很棒的工具,目前 Logdown 的教學文裡面的示意圖標示,幾乎都是這套作的....

Server Side

Route53

DNS 直接走 AWS solution,這是目前算穩的方案。

Mailgun

其實也可以用 Amazon SES 的方式寄信,不過每次都要 verified sender 和 site 太麻煩,而且想看寄信 Log 幾乎沒辦法。所以就改用了這套服務,非常非常的方便。

FilePicker

目前 Logdown 的傳圖服務是直接走 FilePicker,FilePicker 時作了很多服務的傳圖 API 與界面,所以就不用自己重刻輪子了。不過 昨天 Logdown 剛上線的編輯超酷拖拉傳圖 就不是 Filepicker 提供的。但不可諱言的,的確 FilePicker 加速了很多開發進度...

文件撰寫

Logdown

不是自誇,但實在不得不說我現在體驗過最好的 Markdown 編輯器就是 Logdown 的後台了....。現在的 Markdown 文件我幾乎都是透過 Logdown 後台在寫得,寫完再下載...

也許你應該也來試試。

客服

Tender

我們現在的客服系統是 Tender,Tender 的好處就是整合原先站台做 Single sign on,我們在開站後幾天覺得應該之後就會蠻多人來回報問題。於是就花了一點時間串接了 SSO。果然幫上蠻多忙的。

如果有小問題但很急,使用者通常會 reply 我們寄出的問候信。大問題但不急的,使用者就會上客服系統開 ticket 等我們慢慢處理。這能夠在開站初期解決不少火燒的問題...

Summary

當然我們平常做 project 用到的流程和工具還有很多。不過我覺得這次作專案比較有倚重到的服務,也比較值得拿來講的,大概就是這些...歡迎各位交流。