6 days ago

臉書 og image 其實可以設定很多個,讓使用者在分享網站連結時可以有圖片的選擇:

<meta content="https://example.com/1.jpg" property="og:image" />
<meta content="https://example.com/2.jpg" property="og:image" />
<meta content="https://example.com/3.jpg" property="og:image" />
<meta content="https://example.com/4.jpg" property="og:image" />
<meta content="https://example.com/5.jpg" property="og:image" />

裡面有些規則在,判定標準的「順序」整理如下:

  1. 高解析度的 priority 較高!
  2. html meta 列的順序由下至上,如範例就會是 5.jpg -> 4 -> 3 -> 2 -> 1
  3. 不管列再多,最多只會出現5張給使用者選

若需要測試網頁 og meta 是否正確設定,可以用此連結測試:https://developers.facebook.com/tools/debug/og/object/

 
17 days ago

開始前簡單介紹一下什麼是 Eager Loading 什麼是 N+1 Query,Eager Loading 出現主要是為解決 N+1 Query。N+1 Query 像是這樣:

# controller

@posts = Post.publish.take(10)
# view
<table>
  <th>標題</th>
  <th>簡介</th>
  <th>作者</th>
  <% @posts.each do |post| %>
  <tr>
    <td><%= post.title %></td>
    <td><%= post.summary %></td>
    <td><%= post.author.name %></td>
  </tr>
  <% end %>
</table>
Read on →
 
21 days ago

前陣子在接觸 rails turbolinks 時想說 turbolinks 怎這麼 suck,光是 GA、Facebook Pixel 等 tracking script 無法正常運作就讓人十分頭痛(當時直接怒拔...),但在最近因為看了這篇文章 瞬間懂了。

Turbolinks 是在 Ruby on Rails 4.0 被默認的一個 gem,當時(2013年)很多人在分享時都搭上一句標題「Turbolinks for Rails (like pjax)」。那什麼是 pjax?turbolinks?更詳細解說可看上述提及的文章,這邊就針對一些所獲的重點摘錄做分享。
<!--more-->

講什麼是 pjax 跟 turbolinks 之前要先知道在 HTML5 的 History Interface及裡面的 pushState。這是文章內的解說

pushState允許Javascript在會話歷史中隨意儲存數據,並且綁定一個標題和可選的URL。back()和forward()方法允許我們瀏覽已存儲的會話歷史數據。通過這個方法,我們可以使用pushState保存當前頁的瀏覽歷史,並且動態的在不同狀態下,後退和前進,而不需要重新載入整個頁面。

PJAX & Turbolinks

簡單來說,這兩個東西的理念都是:當使用者點擊一個連結時,不需要重新載入整個頁面(平常使用網站會有突然閃爍、白一下的感覺),而是直接載入並替換需要更新的網站內容。

那有什麼不同?

1. 更新的範圍

PJAX 可以指定要更新哪個網頁元素,like this

$.pjax({url:'/authors',container:'#main'})

但 Turbolinks 是直接替換整個網頁的 <title> 和 <body>,而且預設所有網站內的超鏈結都屬於 turbolinks 範疇。所以不用特別指定哪些連結需要而去標記他們,Turbolinks 會自動處理(好像很夢幻,但若不懂會覺得網站很多雷...)。

只需要:

# Gemfile
gem "turbolinks"

# app/assets/javascripts/application.js
//= require turbolinks

2. 伺服器回應的內容

PJAX 也只需要伺服器回應元素的內容就好,像是

if request.headers['X-PJAX']
  render:layout
end

而 Turbolinks 不需要而外在 controller 做設定,照舊即可(有原生的 gem support 真好!)

Rails Turbolinks 注意事項

當使用 document.ready 或是 $(function(){}) 時,這些事件只會在 DOM 完成載入時被觸發,但不會在 Turbolinks 更改網頁內容時觸發,所以可利用 page:change 這個事件

$(function(){
  initPage();
});
$(window).bind('page:change', function(){
  initPage();
});

另外若有像是 GA 或是 Pixel 等的 tracking script 記得也需要加入 page:change 的事件處理,或是將這些 script 擺在 <body> 內。

小結

雖然 PJAX 看起來可以讓客戶端要處理的數據量較小(伺服器只回應需要的部份),但在開發與設定上也更加的麻煩,讓開發者需要額外設定的工作也變更多,更違反了 Rails 快速開發的哲學。既然用 Rails 了,就好好體會其中的設計,使用原生內建的 turbolinks 吧!

BTW, 會體會這麼深是因為有個專案在 themeforest 買了個版,裡面大量使用 pjax,整個頁面切換很 smooth 很夢幻(所以才挑它...),但在整理 assets 時發現 pjax theme 根本 rails 天敵,建議大家若有買版(例如 themeforest)的習慣,要留意裡面是否有用 pjax,不然光要整理裡面的 js 就很暈...

Read on →
 
24 days ago

參考源於此:http://blog.honeybadger.io/ruby-exception-vs-standarderror-whats-the-difference/

「Never rescue Exception in Ruby」
或許你可曾聽過這句話,但若不知道 Exception 與 Standard Error 的差別還真是讓人摸不著頭緒。

通常我們會在 Ruby 這樣 rescue exceptions

begin
  do_something()
rescue => e
  puts e # e is an exception object containing info about the error.
end

但在看到這張表後馬上明白為什麼不能這樣寫

Exception
 NoMemoryError
 ScriptError
   LoadError
   NotImplementedError
   SyntaxError
 SignalException
   Interrupt
 StandardError
   ArgumentError
   IOError
     EOFError
   IndexError
   LocalJumpError
   NameError
     NoMethodError
   RangeError
     FloatDomainError
   RegexpError
   RuntimeError
   SecurityError
   SystemCallError
   SystemStackError
   ThreadError
   TypeError
   ZeroDivisionError
 SystemExit
 fatal

可以看到 StandardError 只是 Exception 的一個子類別而已,所以當我們若 rescue 整個 exception 類別,會發現「ScriptError::SyntaxError」、「NoMemoryError」這種最常 typo 的錯誤就都跑進去 rescue 裡面了,開發時都不會發現,大概要功能上線後發現怎都沒資料才會注意到吧(笑

所以應該這樣寫:

begin
  do_something()
rescue StandardError => e
  # Only your app's exceptions are swallowed. Things like SyntaxErrror are left alone. 
end
 
2 months ago

Arrays: map & each_with_index

在跑陣列(array) for-each 每一個 interation 可以帶上相對應的 index,利用 each_with_index 這個方法:

['a', 'b', 'c'].each_with_index do { |item, index|
  puts "#{index}-#{item}"
}

當然,我們也可以利用 index 對應到的 element 組成一個新的 object:

['a', 'b', 'c'].each_with_index.map { |item, index|
  { :letter => item,
    :position => index }
}

View: cycle is no even odd

在網頁設計上,常為了讓表格內容更容易被閱讀,讓表格每行的顏色交錯,像是:
{}bootstrap-table
正常寫法:

<% an_array.each_with_index do |element, index| %>
  <tr class="<%= index.odd? ? 'odd' : 'even' %>">
    <td>...</td>
  </tr>
<% end %>

在 Rails 有提供一個很棒的 helper 函式 cycle:

<% an_array.each do |item| %>
  <tr class="<%= cycle('odd','even') %>">
<td>...</td>
  </tr>
<% end %>

更多 cycle 用法可參考文件

try

這是 Ruby 語法中最讓我驚艷不已的一個...省掉超級多行。原先為避免對 nil 呼叫產生錯誤,會這樣寫:

if @person.present? && @person.a_property == 'foo'
  ..
end

<% if @an_array.present? %>
  <% @an_array.each do |item| %>
    ...
  <% end %>
<% end %>

學會 try 之後可以這樣寫:

if @person.try(:a_property) == 'foo'
   ...
end

<% @an_array.try(:each) do |item| %>
  ...
<% end %>
 
5 months ago

Sidekiq 在 heroku 的 deployment 可以參照官方的這篇文章:https://github.com/mperham/sidekiq/wiki/Deployment#heroku

大概整理以下要點與步驟:

  • Sidekiq 版本 3.0 以前會自動設定 Redis-to-Go 的相關 Redis 伺服器位置。3.0 後就要自己設定嚕,目前最新版本是 2015/2/6 的 v3.3.2。
  • 新增 heroku add-on: https://addons.heroku.com/
  • 因上點之描述,手動設定 heroku 環境變數,指定 redis server address
    heroku config:set REDIS_PROVIDER=REDISTOGO_URL # Redis to Go add-on
    heroku config:set REDIS_PROVIDER=REGISCLOUD_URL # Redis Cloud add-on
    
  • 重新啟動 heroku 去套用新的環境變數: heroku restart
 
6 months ago

{}order1
點選 WIFI (AirPort) 圖示 -> 網路偏好設定(Open Network Preferences)

{}order2
進去偏好設定後(預設已選取 WIFI) -> 進階(Advanced)

{}order3
從過去連線過的列表中,直接拖曳 WIFI AP 的名稱即可,越上面代表優先權越高。

 
6 months ago

最近因要幫朋友下載連續劇與影片做了些 survey,分享一些成果給大家

一些 BT 種子下載的地方:

下載 youtube, dailymotion 等各大影音平台的 chrome 套件:

註:沒辦法自定義下載的影片檔名,是唯一美中不足的地方。

希望大家也能好好享受 :D

 
6 months ago

稍微分享一下最近一個 rails project hosting 的數據,站上同時有約6000人,有大量使用 view cache。

環境架設部分

  • nginx + unicorn (worker * 4)
  • memcached server 512 MB(同一台機器...)
  • Linode 2G

這是一個純新聞媒體的網站,觀察這樣架構下,面對同時 6000 人,機器 loading 大概約50%不到,粗估是可以到萬人以上水準。

若 memcached 搬出去,再把 worker 數量增加兩個,相信會再更好 :D

 
6 months ago

承上篇PHP5-FPM with Nginx 效能調教 (1)

PHP5-FPM

最近觀察到許多次 php5-fpm 突然不工作的狀況,即連上網站吃到 502 response status。最後於 nginx 的 error log 中找到這樣的錯誤訊息:

[14-Dec-2014 12:20:45] ERROR: failed to ptrace(PEEKDATA) pid 13305: Input/output error (5)
[14-Dec-2014 12:20:45] NOTICE: finished trace of 13305
[14-Dec-2014 12:20:45] NOTICE: child 14008 stopped for tracing
[14-Dec-2014 12:20:45] NOTICE: about to trace 14008
[14-Dec-2014 12:20:45] ERROR: failed to ptrace(PEEKDATA) pid 14008: Input/output error (5)
[14-Dec-2014 12:20:45] NOTICE: finished trace of 14008
[14-Dec-2014 12:20:45] NOTICE: child 20877 stopped for tracing
[14-Dec-2014 12:20:45] NOTICE: about to trace 20877
[14-Dec-2014 12:20:45] ERROR: failed to ptrace(PEEKDATA) pid 20877: Input/output error (5)

原因是由於檔案同時開啟數量的限制:

In your case, the stack trace (to determine what the script is doing) is failing. If you're running out of processes, it is because either:

After php-fpm stops the process to trace it, the process fails to resume because of the error tracing it
The process is resuming but continues to run forever.

唯一辦法即是關掉 slow_log 以及 request_slowlog_timeout,網站便恢復穩定正常!強烈建議實際上線 production 的伺服器不要開啟 php5-fpm 的 slowlog 功能。

PHP5-FPM 參數調教

另外,最近也透過htop觀察到,雖然我們 php5-fpm 的 child process 數量給到破百,但常常同時在執行的數量只有1~3個。

應是因為一般的網站只有在使用者連進來的那一瞬間需要做頁面呈現上的處理,處理完便沒事了,故當然不可能隨時都一直有破百人同時進來,需要這麼多的 php5-fpm process。

所以,除透過自身伺服器可用資源(RAM, # of CPU Core)去調整 child process 數量外,也可透過自身網站的需求去做評估。若網站執行效率不會一直卡著(正常有這狀況也不會讓網站上線吧XDDD),也沒有類似 socket / long polling 之類的需求(即使用者需一直跟伺服器發出 request),那其實 php5-fpm 預設的設定就很足夠惹~

Memcached

通常我們架設 php 網站,例如:wordpress,都會使用 memcached 來做快取,以加快整體網站速度,與降低伺服器與資料庫的承載(loading)。

建議可利用htop觀察 memcached 的使用量,並做適當的調整,如不夠則可以給予 memcached 更多的 memory 供使用。如:

5874 nobody 20 0 246M 121M 2256 S 0.0 1.5 0:00.00 /usr/bin/memcached -m 1536 -p 11211 -u nobody -l 127.0.0.1

可看到目前 memcached 使用了 121MB,而我們實際上給予 1536MB,還有相當充裕的使用空間。

Reference