over 5 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)

 
over 5 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)

 
over 5 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 缺乏這樣的環境、成員、心態,帶來的不會是高生產力,而是災難。

 
over 5 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 問他時是可以寫中文的。

 
over 5 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)

.....

 
over 5 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...

 
almost 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 用到的流程和工具還有很多。不過我覺得這次作專案比較有倚重到的服務,也比較值得拿來講的,大概就是這些...歡迎各位交流。

 
almost 6 years ago

Hi, 各位, 從今日起,本部落格正式搬家到 Logdown 上 Hosting 了。

Logdown 是我們公司 Rocodev 正式開發維護的一個產品。線上使用 Markdown 寫作文章,支援 Github-Flavored Markdwon, MultiMarkdown, 以及 Latex 數學式, 提供上傳圖片介面以及 Custom Domain。Octopress 與 Wordpress 搬家服務。

正式網址還是 http://blog.xdite.net
Feed 網址還是 http://feeds.feedburner.com/xxddite

兩年前,我決定從 Wordpress 搬家到 Octopress。原因是 Wordpress 無法提供我技術寫作上的需求( Markdown 以及程式碼排版)。我找了很久,發現 Octopress 可以解決這部分大部分的問題,於是我決定轉換平台。

Octopress 在寫作上的確比 Wordpress 順暢非常非常的多。但它也不是沒有缺點。Octopress 必須作者自己尋找使用適合的 Markdown 寫作軟體書寫文章(我是用 Mou 這套軟體),寫完再執行指令 compile 出去。

Octopress 可以進行非常高度的客製化。但是,相較之下它也有一些門檻,比如說你必須略懂技術(安裝 Octopress,以及 compile 文章並發佈,設定域名...等等)。隨時想寫想發時,該台電腦必須要有 Ruby 環境,才能夠發布....貼圖的問題還是半手動,需要自己貼。但最困擾的我的兩個點還是:

  1. 沒有一個線上 / 線下 Markdown 編輯器,能夠好好的支援寫作 Code 排版以及提供 Code 即時排版。(在不干擾寫作的情況下)

  2. 當每次文章一多,Ocotpress compile 文章會變得非常非常慢。(雖然我知道 hack 可以繞過,但是我有時候還是想當作者純寫文章而已,不想解決技術問題)。

世界上也沒有任何一個 Blog Hosting 提供這樣的服務,照顧我們這些只是想專心寫作的人的需求....

重貼當初那篇文章的一段話


Developer Blogger 的需求

其實我們的需求也不多。若是可以:

輕鬆的撰寫 Markdown
輕鬆的貼圖
輕鬆的貼程式碼
改 CSS 超容易
不用煩惱佈署問題
檢視草稿變化,甚至是站台更動變化。

這樣就很開心了!


Logdown 的開發初衷就是只有這樣而已。

Logdown 提供什麼

  • 革命性的 Markdown Editor ( 即時 Markdown 高亮, 在 CJK 下不變形不跑位),程式碼與 Latex 的的即時 preview 。
  • 單篇文章下載(只喜歡 Markdown Editor 也沒關係,我們提供寫完單篇文章下載 Markdown 檔)
  • 超直覺圖片上傳 (支援拖拉上傳,以及各種網路儲存服務、社交服務上的圖片導入)
  • 自訂 Domain 與自訂 網址
  • Octopress 匯入 / 匯出 (無痛搬家)
  • 沒有站方廣告...
  • 一天六次以上的部落格備份

Logdown 未來會提供什麼

  • Multiple Blog
  • Wordpress Import ( 下個禮拜會就會推出)
  • Movabletype Import
  • Google Blogger Import
  • Custom Theme / Custome Pages / Custome CSS

如果你還有其他的需求,歡迎寄信給我們 logdown@rocodev.com,我們也會排入開發清單。

就是這樣,我正式的搬來 Logdown 了。歡迎你也一起搬來。

 
almost 6 years ago

真是一個刺激的 Hack 週末。自從 Logdown兩週前推出,得到了不少好評,這股動力讓我們寫起 Feature 更加的賣力。

這個週末(是的。你現在看到這些功能,幾乎都是我們在週末寫的....), Logdown 推出了更多功能以及 Beta Plan:

首先是

Custom Domain ( Beta / Preinum required )

大家期待已久的功能 Custom Domain 功能

Octopres Import ( Beta required )

可以把 原先的 Octopress 文章壓縮打包成 zip 後,無痛匯入 Logdown 裡面。我們預計在接下來的幾個禮拜測試 Wordpress 與 Movable Type 的匯入

Custom Handle & Custom URL

支援原先的 Octopress URL

綜合 Custom Domain / Octopres Import / Custom Handle & Custom URL 這三項。基本上把 Octopress 搬過來應該沒什麼問題了...

File Uploader ( Beta / Preinum required )

很多朋友一直在問的 File 上傳功能,我們在週末也完成了。目前 Logdown 支援 File drag & drop upload, Flickr, Instagram, Facebook Photo, Picasa, Dropbox Upload!!!! (其實還有更多...)

目前暫定 Beta 是 100 mb,Prenium Plan 會是 10GB

單篇 Markdown 下載

如果只喜歡我們的 Editor 也沒關係,我們支援在 Logdown 寫完再下載回家貼到 Octopress,但是如果你可以考慮 搬家 那就更好了。

匯出功能

如果哪一天你不喜歡 Logdown 想搬回 Octopress 了,我們也提供了全站打包下載功能,會把所有的文章打包匯出,郵寄到你的 email 裡面。

目前的打包功能只有 Octopres Zip 匯出。我們預計在接下來的幾個禮拜測試與開發 Movable Type 的匯出。

更多 syntax ( Especially for Hacker and Scienist )

Octopress Style Code Block ...

是的,我們支援了 Octopress 特有的 code block 寫法,會有 Caption...

  ``` css common.css.scss
    @import "reset";

  ```

Octopress old syntax

我們目前 porting 了 codeblockimg ,預計還會再支援下一個更重要的 gist 功能,敬請期待

Latex Support

是的,我們喪心病狂的支援了 Latex 語法。你可以透過加入 mathjax 來顯示 Latex 語法。而且直接可以在預覽裡面看到結果!!!

後續計畫:Beta & Preinum Plan

這兩週我們收到不少朋友的鼓勵與支持,所以我們很認真嚴肅的決定將繼續維護這個產品,而不只是一個 Hackathon 的 pet project。我本人的 blog 部落格也會在近期之內就搬到 Logdown 上。

Logdown 之後將會有 Preinum 收費的計畫。我們預計的收費計畫將會是 49 USD / year。為了感謝這段期間參與測試的朋友,在八月底前升級 Beta Membership 在轉換為 Preinum 時,我們將只會收取 24.95 USD 的費用。

以上宣布的這些 Advanced Feature,你可以在後台中找到升級頁面,Upgrade 成 Beta 後進行使用。

追蹤我們

你可以透過這兩個管道取得 Logdown 的最新消息。我們也會在重大 Feature 推出時,寫信通知大家。

 
almost 6 years ago

TL; DR: Rails 4.0.0 有地雷,建議修完所有 depcrapted warning 再從 rc1, rc2 升級,不然會有大災難。

上個禮拜跟同事做了個 Markdown Blog Service Provider : Logdown。介紹請看這裡。Logdown 是用 Rails 3.2.13 寫的。適逢昨日 Rails 4.0.0 釋出,於是手癢癢就想幫 Logdown 升級…

上個月我曾經寫過兩篇文章:

該踩的雷我都中過了,也知道怎麼 patch 常見的地雷,閃過去….

不過我膝蓋還是中了好大一箭…orz

地雷一:強制 raise error

Rails 4 改變最大的有幾個重點:

  1. 拿掉 attr_protected,改用 strong parameters
  2. scope 改用 -> {}
  3. routes 建議大家棄用 match ,而用更精確的 get , post

well, 在 4.0.0 版,如果你還在用 match 的話,Rails 除了 warning message 還會直接 raise error。網站會直接跑不起來,而不是像 beta 的向下相容。而且一些行為也會強制禁掉,如 Logdown 其實有兩個 root :to,其中一個跑 contraint 偵測是否有 user 而導到後台。

Rails 4 是直接禁掉這樣的 syntax 讓你跑不起來。

不過這個還算好的警告手段。直接爛掉雖然有點 annoying,但是你知道 patch 掉就沒有後遺症了....

地雷二:改變行為

這件事我真的覺得最扯....。但也可以預見未來可能有一些災難發生。

Rails 4 beta 建議大家 scope 改用 -> {}。並且有警告 Message 通知你必須改變,但撈出來的 query 還是向下相容,也就是執行結果是正確的。

Rails 4.0.0 版 建議大家 scope 改用 -> {}。並且有警告 Message 通知你必須改變,但撈出來的 query 行為改變,也就是執行結果是錯誤的。

這件事讓到底有多嚴重,我的 post.rb 是這樣設計的:

class Post < AR
  scope :recent, order("id DESC")
end

而在 Logdown 的 Dashboard 裡面,我的後台 index action 是這樣設計的

class Account::PostController < AC
  def index
    @posts = current_users.posts.recent
  end
end

正常的行為,生出來的 query 是這樣的(撈出我本人的所有文章):

Post Load (11.3ms)  SELECT `posts`.* FROM `posts` WHERE `posts`.`user_id` = 3 ORDER BY id DESC LIMIT 50 OFFSET 0

到這邊都沒什麼問題。

本來我改好程式,在 local 測一測看起來沒什麼問題,( Rails 4 最大的改動通常是 update_attributes 會需要修,query 通常不太需要修)…也沒 raise error。還好我今晚是先 deploy 到 staging 去測。deploy 上去差一點噴茶....

我個人的 Dashboard 竟然出現了(全站文章) ……orz…..WTF…

在 local 重新測試才發現:

如果你沒把 scope 改成

class Post < AR
  scope :recent, -> { order("id DESC") }
end

那麼…在後台

class Account::PostController < AC
  def index
    @posts = current_users.posts.recent
  end
end

生出來的 query 會長這樣

Post Load (1.2ms)  SELECT `posts`.* FROM `posts` ORDER BY id DESC LIMIT 50 OFFSET 0

齁齁,所有條件失效,撈全站文章給你。簡單的 query 都這樣,複雜的 query 我不敢想像。( -> { } 的新預設寫法席卷了一大堆設計,而且一堆 plugin 還在用 舊 query … )我已經可以預見這會產生多大的災難了....

重點是,你還不能回報這是 bug,畢竟人家都已經叫你換成 -> {},誰叫你不換勒?

地雷三:管太多…

我在 deploy 的時候,遇到 Asset compile 不過的狀況。sprockets 一直報錯:

Asset logical path has no extension: README

WTF,我從沒在之前的版本看過這個錯誤。在網路上搜尋了一下發現是這個 issue..:

https://github.com/sstephenson/sprockets/issues/347

意思就是 sprockets 連你的 README 有沒有加 .txt 都要管啦 -_-。然後維護者不想修,叫大家自己去找 workround…

所以如果你的 app/assets/javascripts app/assets/stylesheets 下如果有沒有副檔名的檔案,compile 就不會過。你會想說 not big deal,自己改成多加 .txt 或 .md 就好了…

沒這麼簡單。一堆 3rd party 的 css / js ..不僅有 …..README…還有 LICENSE…還有 CHANGELOG….XDD

齁齁齁,感覺很精彩了吧。沒關係,這都可以加 .txt。頂多是 CSS / JS 界的 repo 這陣子會被 Rails developer 群騷擾而已。更精彩的是 Makefile….這到底是要怎麼閃 XD

( 剛剛網路上找 solution 看到一堆慘案 …)

Bower 已經身亡,這裡是解法

Summary

如果你是從 Rails 4.0.0beta1 或者是 Rails 4.0.0rc1 升級,務必停看聽…

Rails 4.0.0 跟你想得很不一樣 …orz