搬家了!
從即日起,本站將不再作筆記的更新喔!
雖然一直以來都是隨手記記學習上的小筆記,但這次搬家後,除了原本的攻城獅日誌外,會開始寫一些旅遊、生活和資訊的分享!畢竟除了程式語言外,本人也非常喜歡人類語言,哈哈哈!
新網站是以 HEXO 搭配 Github Page 的部落格,我會在新網站補上如何實作,歡迎來街口駐足!
嘿!我在這呢!
新網站「新樂街口的三角窗」: https://oawan.me
p.s. 這邊(舊站)資訊將會保留,不會移除。
目的
在 Devise 下,使用 Facebook 註冊與登入。
前言
相信大家都很熟練 Devise 這個 Gem 的使用者機制,當然除了一般的註冊申請帳號外,最方便是要能與各大社交平台有所連結;而 Devise 中透過 OmniAuth 快速地串接 Facebook、google、github... 等,以下就筆記一下如何使用 Facebook 註冊登入!
開發版本與環境
Ruby : v2.3.0
Rails : v4.2.5
IDE : Cloud 9
筆記
1. 什麼是 OmniAuth ?
OmniAuth 是一個提供多方認證,且不被限定於特定框架的認證方案,主要架構如下:
Provider
OmniAuth 將所有的認證方視為不同的 Provider,而每種 Provider 都有各自的 Strategy。
Strategy
每個 Strategy 分為兩個 phase,對應 OmniAuth 提供的 url:
- equest phase =>
/auth/:provider
- callback phase =>
/auth/:provider/callback
而它的流程是,透過 /auth/:provider
重導去認證,認證成功後 redirect 到 /auth/:provider/callback
作 session create 動作 ( 透過拿回來的資料 find_or_create user )
註: :provider 就是 facebook、github,所以 url 看起來會是 /auth/facebook、/auth/facebook/callback。
2. 一起來實作
步驟零、 Install gem
gem 'omniauth'
gem 'omniauth-facebook'
gem 'koala', "~-> 2.2" # 為了讓授權失敗時,刪除 permission session 使用
步驟一、 建立 Facebook Application
使用 Facebook 應用服務前,需先到 Facebook developer 建立應用程式,只要按照步驟就可以順利建立完成。
步驟二、 於 devise.rb 中設定 config.omniauth
config.omniauth :facebook, ENB['FB_KEY'], ENV['FB_SECRET'],
scope: 'email',
info_fields: 'email, name, link',
secure_image_url: true,
image_size: 'large'
這邊使用 Rails_ENV 確保我們的資料隱密性,可參考 這篇的 Rails_ENV 小筆記
- FB_KEY:Facebook 應用程式編號
- FB_SECRET:Facebook 應用程式密鑰
- scope:表示將取得使用者的什麼權限,email 為預設,即取得使用者公開的資訊 ( public_profile ) 權限
- info_fields:表示在擁有權限下,取得使用者的什麼資訊,這邊我們取得使用者的 Email、名稱和 FB 連結
- secure_image_url:為 true,表示我們透過 https 取得使用者大頭貼
-
image_size:此為取得大頭貼的 size,
square
(50x50)、small
(50 px width, ariable height)、normal
(100 px width, variable height)、large
(約 200 px wide, variable height)
以上設定,我們可以從 omniauth-facebook 清楚的了解。
若是想取得其他的權限與資訊,可以先到 Facebook developer permissions 查看。
步驟三、 於 user.rb 中設定 omniauth
devise :omniauthable, :omniauth_providers => [:facebook]
定義認證後的創建行為,會在取得使用者 Facebook 權限與資訊後執行:
def self.from_omniauth(auth)
where(provider: auth.provider, uid: auth.uid).first_or_create do |user|
user.provider = auth.provider
user.uid = auth.uid
user.email = auth.info.email
user.name = auth.info.name
user.facebook = auth.info.urls.Facebook
user.password = Devise.friendly_token[0,20]
user.remote_avatar_url = auth.info.image
user.skip_confirmation! # 如果 devise 有使用 confirmable,記得 skip!
end
end
授權失敗時,透過 koala
刪除使用者授權的 session,以便重新授權。
def delete_access_token(auth)
@graph ||= Koala::Facebook::API.new(auth.credentials.token)
@graph.delete_connections(auth.uid, "permissions")
end
步驟四、 定義 omniauth callback controller
新增一個 Users::OmniauthCallBacksController
,我們在這個地方定義兩個 action:facebook 和 failure。
- facebook method 作的三件事:
1. 使用者授權後,依取得的資訊創建新的 user。
2. 如果此使用者已經存在網站中,直接登入。
3. 授權後,未取得 email 者,重新要求授權。(這是因為我的網站使用者 email 為必填項目,且為登入憑據)
- failure:重新導向註冊頁,並告知使用者授權錯誤。
class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController
def facebook
@user = User.from_omniauth(request.env["omniauth.auth"]) # 這邊會呼叫我們在 user 中定義的創建行為
if @user.persisted?
sign_in_and_redirect @user, :event => :authentication
set_flash_message(:notice, :success, :kind => "Facebook") if is_navigational_format?
else
if @user.email.nil?
# 如果 User 沒有提供 email 刪除 User 的 app 讓 User 重新授權
@user.delete_access_token(request.env["omniauth.auth"])
redirect_to new_user_registration_url, alert: "需要您同意 Email 授權唷!"
else
session["devise.facebook_data"] = request.env["omniauth.auth"]
redirect_to new_user_registration_url
end
end
end
def failure
redirect_to new_user_session_path, alert: "無法獲得驗證!"
end
end
步驟五、 到 routes.rb 設定 devise omniauth callback 該用哪個 controller
我們要讓 omniauth callback 時使用我們定義的 controller:
devise_for :users, controllers: {omniauth_callbacks: "users/omniauth_callbacks"}
Devise 使用 OmniAuth 時,會自動幫你在 registrations#new
產生 provider 登入的 link,所以不必自行添加,或是你也可以在想添加的地方加入:
<%= link_to "Sign in with Facebook", user_omniauth_authorize_path(:facebook) %>
後記
授權失敗時,需要重新授權 (Permissions revoke),這個問題看似很簡單,卻花了我不少時間;原因是不想為了解決這個小問題,而多使用一個 gem,但最終我還是選擇用 koala 解決了,如果有不多加使用 gem 的解法請來信或留言,感激不盡!
That's it, DONE!
【參考資料】
- XDITE OmniAuth 系列文章:http://blog.xdite.net/posts/2011/11/19/omniauth-clean-auth-provider-1
- devise OmniAuth document:https://github.com/plataformatec/devise/wiki/OmniAuth:-Overview
- Auth Hash Schema:https://github.com/intridea/omniauth/wiki/Auth-Hash-Schema
- OmniAuth Facebook:https://github.com/mkdynamic/omniauth-facebook
- FB Revoking Permissions: http://azhen.logdown.com/posts/301101-rails-fb-revoking-permissions
- Rails 4 OmniAuth using Devise: 有 Facebook, Twitter, Linkedin 的教學文章
目的
有鑒於一些好朋友想知道怎麼管理 ROR 的開發環境,所以重新整理了一下在 Ubuntu 上使用 RVM 管理 Ruby 和 Rails 的小筆記!希望能幫助到需要的你唷!
開發版本與環境
VMware Workstation 12
Ubuntu: 15.04(64-bit)
筆記
1. 什麼是 Gem ?
不是鄧紫棋!不是鄧紫棋!不是鄧紫棋!
不知道大家是不是和我一樣,在什麼都還不了解的情況下,迫切的想知道 Gem 在 ROR 世界裡究竟扮演著什麼角色,一估狗 Gem,卻跑出一堆鄧紫棋XDD
在 Ruby 的世界裡,Gem 如其名,就是一顆一顆的寶石,而 Ruby 會由很多的 Gem 點綴成你要的樣子,好比如果你想要你的 Ruby 有黃色光芒,你就得裝上會散發黃色光芒的 Gem;我把 Gem 看作是 Ruby 的套件,就像是 npm 中的 module,需要什麼樣的功能,我們就掛上什麼樣的套件。
2. 什麼是 RVM ?
Ruby Version Manager ( RVM ),顧名思義就是一個管理 Ruby 版本的工具,這是一個 command-line 的工具,也就是說只要下下指令,就能簡單的切換和管理 Ruby 版本;而每個 Ruby 版本都會有自己的 Gemset (就是一堆的 Gem),所以透過 RVM 也可以管理每個 Ruby 版本下,該用哪一套 Gemset ( 由於 Rails 就是一個 Gem,所以我們可以由安裝的 Rails 版本來分類 Gemset)。
3. 安裝 RVM
步驟一、 在安裝 RVM 之前,你應該先裝好 curl。
sudo apt-get update
sudo apt-get install -y curl build-essential
步驟二、 參考 RVM 官方網站,下這兩道神奇咒語,就安裝好了!
gpg --keyserver hkp://keys.gnupg.net --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3
curl -sSL https://get.rvm.io | bash -s stable
安裝完後記得重開或 reload Terminal。
4. 安裝 Ruby 及 RVM 指令
透過 RVM 安裝 Ruby 很簡單:
rvm install 2.3.0 # 安裝 Ruby 2.3.0 ( 版本號可自選 )
下面筆記一些 RVM 的指令:
rvm system # 切回系統安裝的 Ruby ( 不建議使用 )
rvm list # 列出已經安裝的 Ruby 版本 (* 預設,=> 正在使用,=* 正在使用且為預設,)
rvm list known # 列出 RVM 目前所有可安裝的 Ruby 版本
rvm use 2.3.0 # 切換至輸入的版本
rvm use 2.3.0 --default # 切換至輸入的版本,並設為預設
rvm reinstall 2.3.0 # 重新安裝該版本
rvm info # 目前使用的 Ruby 相關資訊
由於,每個 Ruby 版本下,都各自有不同的 Gem,這時我們就可以透過 RVM 的 Gemset 來作管理和切換:
rvm gemset # 查看指令說明
rvm gemset list # 列出目前使用 Ruby 的 Gemset
rvm gemset list_all # 列出所有安裝 Ruby 的 Gemset
rvm gemset create xxx # 建立名為 xxx 的 gemset
rvm gemset use xxx # 使用 gemset xxx
rvm gemset empty xxx # 清空 gemset xxx
rvm gemset delete xxx # 刪除 gemset xxx
rvm gemset copy xxx yyy # 將 xxx 的內容 copy 到 yyy (兩者需都要存在)
rvm gemset rename xxx zzz# 將 xxx 更名為 zzz
5. 安裝 Rails
只要選定好要使用的 Gemset 後,下 gem install rails
安裝 rails 即可。
這邊稍微提一下,我們可以也利用安裝的 Rails 版本來區分 Gemset,例如:
rvm gemset create rails_4.2.6 # 建立一個 rails_4.2.6 Gemset
rvm gemset use rails_4.2.6 # 使用 rails_4.2.6
gem install rails 4.2.6 # 在此 Gemset 下安裝 Rails 4.2.6
這樣我們就很清楚的知道,這個 Gemset 的 Rails 開發環境是版本 4.2.6。
註:其實 Ruby 版控上,除了 RVM 外,也很多人使用 rbenv,教學請參考 Ruby China 這篇,由於沒用過,就不多提了!
而我會選擇 RVM,除了簡單易學易用外,還有一點就是,目前我在使用的 Cloud IDE Cloud 9 上預設的就是 RVM,有興趣也可以使用 Cloud 9 作開發喔!
That's it, DONE!
【參考資料】
- RailsFun:http://railsfun.tw/t/rvm/28
- RVM:https://rvm.io/
- Passenger Library:ruby install language runtime
目的
在很多情況下都需要透過 E-mail 的功能,而我目前是需要寄送註冊認證信給使用者,我們使用 ActionMailer 來整合 E-mail!
開發版本與環境
Ruby :v2.3.0
Rails:v4.2.5
IDE :Cloud 9
筆記
1. Devise 設定
這邊我們只講寄信時,devise 需注意的設定,最簡單的方式,就是開啟 Devise::Mailer
config.mailer_sender = 'yourname <whateveryouwant@domain.com>'
# 設定 mailer_sender 會顯示在寄件人 (任何格式都可,但這種格式較不會被當作垃圾信件處理)
config.mailer = 'Devise::Mailer'
# 將註解拿掉後,就會由 devise 預設的 Mailer 寄信 (從 Devise::Mailer 作 deliver 調用 ActionMailer)
2. ActionMailer 設定
config.action_mailer.raise_delivery_errors = false
# rails_delivery_errors 設定為 false 可讓寄信時的錯誤被忽略,如果要 debug 就設 true
config.action_mailer.default_url_options = { host: 'http://localhost:3000' }
# 這邊填入的網址須要注意一下,他必須是絕對網址,且會被預設為 mail 中的 resource link
# 像我是用 devise 寄發驗證信,所以 confirmation_url(@resource, confirmation_token: @token)
# 中的 @resource 就會是 http://localhost:3000
config.action_mailer.delivery_method = :smtp
# delivery_method 有三種寄信方式 :test、:sendmail 和 :smtp
# sendmail 須搭配 server 的 /user/bin/sendmail application
# 而這邊我是透過 mailgun(and gmail) 的 smtp 協定作寄信
config.action_mailer.smtp_settings = {
:address => "smtp.gmail.com",
:port => "587",
:domain => "yourdomain.com",
:authentication => "plain",
:user_name => "yourgmail@gmail.com",
:password => "yourpassword",
:enable_starttls_auto => true
}
其實一般來說,我們不會將 smtp_settings 寫在程式碼裡,而是拆成另一個設定檔,便於管理在不同狀態下的設定:
development:
address: "smtp.gmail.com"
port: "587"
domain: <%=ENV['DOMAIN']%>
authentication: "plain"
user_name: <%=ENV['GMAIL_USERNAME']%>
password: <%=ENV['GMAIL_PASSWORD']%>
enable_starttls_auto: true
production:
address: "smtp.mailgun.org"
port: "587"
domain: <%=ENV['DOMAIN']%>
authentication: "plain"
user_name: <%=ENV['MAILGUN_USERNAME']%>
password: <%=ENV['MAILGUN_PASSWORD']%>
enable_starttls_auto: true
註:cloud 9 中,多數 port 預設是 blocked,但依我自己的測試, mailgun 可透過 2525、587 來寄出信件,而 gmail 只能由 587 寄信。
smtp_settings 的部分就可以修改成:
config.action_mailer.smtp_settings = config_for(:email).symbolize_keys
# config_for 會讀取 config 目錄下的 YAML 設定檔,由於 smtp_settings 需帶入 Symbol key
# 所以透過 .symbolize_keys 將 Hash 中的 String key 轉成 Symbol key
3. 關於 email.yml
這邊來聊聊上面的 email.yml。
ROR 環境預設有三個,development
、production
和test
,一般 rails server
開啟環境預設是 development,我們可以透過 -e
來變更啟動環境,例如 rails s -e test
。
範例 email.yml 中,則表示:
development 時,使用 gmail 寄信。
production 時,使用 mailgun 寄信。
在帳號(user_name)及密碼(password)這邊需要注意的是,如果你是將密碼寫死在設定中,記得一定要將 email.yml 加到 .gitignore 中,避免上傳到 github 自曝帳密;比較好的方法是使用 RAILS_ENV 來取得環境設的變數,由於是寫在 yaml 中,所以我們寫成 <%=ENV['GMAIL_USERNAME']%>
,如果是寫在 .rb 中,則使用 ENV['GMAIL_USERNAME']
即可。這樣我們就可以透過環境設的值作設定。
4. 設定 RAILS_ENV 變數
-
在 Ubuntu 下,可以編輯 ~/.bashrc 並加入以下作環境變數的設定 (在 Mac 下,則編輯 ~/.profile):
export GMAIL_USERNAME="yourgmail@gmail.com"
以此類推,自行添加。
-
Heroku 的話,可直接在
Settings > Config Variables
中添加,或用以下指令作設定:heroku config:add GMAIL_USERNAME="yourgmail@gmail.com"
Cloud 9 的話,在 Runner 中有 ENV 可直接添加,或用 Ubuntu 的方式添加亦可 (因為 c9 的 ROR 環境是 Ubuntu )
5. Gmail 密碼問題
其實上述四個步驟後,就可以成功的寄出信件,但還是補充一下關於 gmail 有可能寄不出信的設定問題。
請先到 gmail 中作安全性設定,並取得密碼: 設定安全性
→ 二階段驗證
→ 應用程式密碼
而取得的應用程式密碼就是要填入的密碼囉!
後記
一開始我是想用 sendgrid 來作 smtp 送信,但真的試不出來也不知道什麼問題,有興趣的人可看這篇文章,雖然是阿本仔寫的,但也是很清楚明瞭!
That's it, DONE!
【參考資料】
- Ruby on Rails 實戰聖經:https://ihower.tw/rails4/actionmailer.html
- 安全地設定 Rails 郵件密碼:http://tsaith.github.io/an-quan-di-she-ding-rails-you-jian-mi-ma.html
- Rails Environment Variables:http://railsapps.github.io/rails-environment-variables.html
- 官方討論:https://community.c9.io/t/how-can-i-send-email-from-my-app/1262
目的
在之前我有筆記一篇透過 friendly_id 讓 url 不顯示 id,除了美化 url 外,我們也可以透過設定 meta data 讓網站達到 SEO 的目的!
前言
meta tag 及 data 的設定很重要,通常網站要能快速得被找到,或是透過分享時顯示重要(正確)的資訊,我們都得在這個部分下點功夫,本篇筆記一下在專案中所學到的相關知識和方法。
筆記
1. 什麼是 Meta Tags 及 Meta Data
Meta Data,在全球資訊網上,是指讓機器看得懂的、描述資訊內容的所有相關資訊。
-
Title Tag:該頁標題,英文長度最好是 70 字元內,中文大約 40 字內,關鍵字盡量往前放,而每一頁的
Title Tag
不要重覆為佳。如:XXX美食部落格 :: 痞○幫
、XXX | Facebook
、徵傳單小弟 | oPartTime 讓打工變得更美好!
等。 -
Description Tag:該頁的敘述,包含標點符號英文約 150 字內,中文 12 字內為佳,此
Description Tag
會出現在 Google 搜尋結果中,所以關鍵字的使用很重要,盡量往前擺。
- Canonical Url:告訴搜尋引擎關於這個頁面的標準網址。
- Facebook OG:此標籤中的資訊是專門給 Facebook 的,可透過設定 OG (Open Graph) 的內容敘述,調整分享時的縮圖、標題、敘述等。
-
Twitter Cards:此標籤中的資訊則是專門給 Twitter 的,透過設定 Cards 的內容敘述,調整分享的資訊顯示。
2. Gem
在 rails 中,除了直接 code html 外,我們可以透過 meta-tags 這個 gem 來對 Meta Data 作設定。
gem 'meta-tags'
then, bundle
it.
3. 設定 Meta Data
簡單的設定來說,可以透過 set_meta_tags
作設定,如下:
= set_meta_tags title: '此頁的抬頭'
-# <title>此頁的抬頭</title>
= set_meta_tags site: 'GeorgioWan's Note', title: '此頁的抬頭'
-# <title>GeorgioWan's Note | 此頁的抬頭</title>
= set_meta_tags site: 'GeorgioWan's Note', title: '此頁的抬頭', reverse: true
-# <title>此頁的抬頭 | GeorgioWan's Note</title> <= 較佳的作法
= set_meta_tags description: '此頁的敘述喔!'
-# <meta name="description" content="此頁的敘述喔!" />
-# 而這句"此頁的敘述喔!"會在 Google 搜尋找到網頁時,顯時於搜尋結果中。
-# 如下,搜尋 Facebook 時所出現的資訊範例。
在 Facebook OG 的簡單設定如下:
= set_meta_tags og: {
title: '此頁的抬頭',
site_name: 'GeorgioWan's Note'
type: 'website',
url: 'http://georgiowan-note.logdown.com/',
image: 'https://test.jpg',
}
-# <meta property="og:title" content="教你怎麼在Rails裡做好基本的SEO"/>
-# <meta property="og:type" content="website"/>
-# <meta property="og:site_name" content="好麻煩部落格"/>
-# <meta property="og:url" content="http://georgiowan-note.logdown.com/"/>
-# <meta property="og:image" content="https://test.jpg"/>
由於目前沒有用到 Twitter Cards 所以也不方便多加敘述,詳情請至 Twitter dev 欣賞 XDD
4. Rails 設定 meta tags 小技巧
如果每一頁都要手刻 meta tag 的話,就違背了 DRY 的原則了!為了符合此原則,我們可以透過定義一個設定動作的 Action,而後,在需要設定 meta data 的 Controller 中作 before_action
即可,好像在繞口令,詳情見下文。
(1) 先在 Application Controller 中定義一個 Action:
class ApplicationController < ActionController::Base
before_action :prepare_meta_tags, if: "request.get?"
protected
def prepare_meta_tags(options={})
site_name = "GeorgioWan's Note"
title = "此頁的抬頭"
description = "此頁的敘述"
image = options[:image] || "your-default-image-url"
current_url = request.url
defaults = {
site: site_name,
title: title,
image: image,
description: description,
canonical: current_url,
keywords: %w[這邊可以打些關鍵字],
og: {url: current_url, # 設定 Facebook OG 預設資訊內容
site_name: site_name,
title: title,
image: image,
description: description,
type: 'website'}
} # 此為預設資訊內容
options.reverse_merge!(defaults)
# 透過 options.reverse_merge! 讓其他 controller 中可作設定(若沒有額外設定就是預設)
set_meta_tags options
# 最後透過 set_meta_tags 設定 meta data 資訊
end
end
(2) 接著,在 layout 的 head 中使用 display_meta_tags
設定每頁的 meta data:
%head
= display_meta_tags
%meta(http-equiv="X-UA-Compatible" content="IE=edge,chrome=1")
-# 上面此段 meta 是設定 IE 的兼容性。
(3) 現在每一頁都會有 meta data 了,但內容都是預設的資訊,我們可以在 Controller 中作設定:
class TestsController < ApplicationController
def index
prepare_meta_tags title: "HERE IS TEST INDEX", description: "TEST INDEX DESCRIPTION."
# 透過 prepare_meta_tags 傳入想變更的 options
@page_title = "HERE IS TEST INDEX"
@page_description = "TEST INDEX DESCRIPTION."
# or 我們可以透過 @page_* 作 meta data 設定
end
def show
@page_title = "HERE IS TEST SHOW"
@page_description = "TEST SHOW DESCRIPTION."
prepare_meta_tags( og: { title: @page_title,
description: @page_description})
# 也可以對 og 作設定
end
end
以上,就簡單的 SEO meta data 設定就完成了。
That's it, DONE!
【參考資料】
- 給 Rails Developer 的基本 SEO:http://gogojimmy.net/2013/09/26/basic-seo-for-rails-developer/
- Easy SEO meta data with meta-tags:http://cookieshq.co.uk/posts/easy-seo-metatags-with-rails-4/
- meta-tags:https://github.com/kpumuk/meta-tags
- Open Graph:http://ogp.me/
- 讓 Facebook OG 取得正確縮圖:網址太長,請點這邊
- reverse_merge API:http://apidock.com/rails/Hash/reverse_merge
目的
在開發的作品中,每篇貼文都希望能透過 fb share 的功能,達到分享該文資訊和宣傳本作品的作用,所以決定在貼文中加入此一功能,讓使用者在宣傳自己的貼文時,也能夠替我們宣傳!
前言
凡事與社群網站接軌,有好無壞!
筆記
1. FB plugin
其實要使用這個功能非常簡單,只要到 facebook developer 按部就班的作,就可以完成此功能。
2. Turbolinks + FB plugin
在開發 rails 中常遇到 turbolinks 導致 header 中 js 沒有 reload 的問題,我們可以透過一些方法解決:
- 使用 jquery-turbolinks gem 解決 jquery 部份
- 而 FB plugin 的解決方法則如下:
fb_plugin.coffee $ -> # 讀取 FB sdk.js loadFacebookSDK() # 檢查是否 bind 過 fb-root,若否則執行 bindFacebookEvents() unless window.fbEventsBound
bindFacebookEvents = ->
$(document)
# 將 fb-root detach 起來
.on('page:fetch', saveFacebookRoot)
# 放回 fb-root
.on('page:change', restoreFacebookRoot)
# 用 FB.XFBML.parse() re-parse all of the XFBML on a page
.on('page:load', -> FB?.XFBML.parse())
@fbEventsBound = truesaveFacebookRoot = ->
if $('#fb-root').length
@fbRoot = $('#fb-root').detach()restoreFacebookRoot = ->
if @fbRoot?
if $('#fb-root').length
$('#fb-root').replaceWith @fbRoot
else
$('body').append @fbRootloadFacebookSDK = ->
window.fbAsyncInit = initializeFacebookSDK
$.getScript("//connect.facebook.net/zh_TW/all.js#xfbml=1&version=v2.5")initializeFacebookSDK = ->
FB.init
appId : 'YOUR_APP_ID'
status : true
cookie : true
xfbml : true
3. Modal(popup) + FB plugin
然而,我遇到的問題是,當我使用 Bootstrap modal 作文章 preview 時,FB share button 只有在第一次 modal show 會出現,而檢視其他 modal 時並沒有觸發更新,導致 FB plugin 失效了!目前我的解決辦法就是在 modal show 時,利用 FB.XFBML.parse() 刷新,以以上的程式碼為範例,於
$ ->
中加入:fb_plugin.coffee $ -> loadFacebookSDK() bindFacebookEvents() unless window.fbEventsBound $('#myModal').on 'show.bs.modal', -> FB.XFBML.parse() ...
4. 偷吃步?
當然,如果想快速的達到這個目的,也不用額外寫一支 script,可以在需要用到此 plugin 的頁面直接嵌入 script 就好。
<script> // 官方 plugin (function(d, s, id) { var js, fjs = d.getElementsByTagName(s)[0]; if (d.getElementById(id)) return; js = d.createElement(s); js.id = id; js.src = "//connect.facebook.net/zh_TW/sdk.js#xfbml=1&version=v2.5"; fjs.parentNode.insertBefore(js, fjs); }(document, 'script', 'facebook-jssdk')); // 讀取此頁時直接利用 FB.XFBML.parse() 刷新 $(FB.XFBML.parse()); </script>
That's it, DONE!
【參考資料】
- Facebook for developers(share button): https://developers.facebook.com/docs/plugins/share-button
- Facebook web sdk: https://developers.facebook.com/docs/reference/javascript/FB.XFBML.parse
- FB plugin with turbolinks solution: http://reed.github.io/turbolinks-compatibility/facebook.html
- FB plugin with turblinks (ADZ blog): http://adz.cool/posts/181188-rails-notes-turbolinks-facebook-sdk
- Google, FB, twitter turbolinks: http://www.workabroad.jp/posts/2083
目的
很多地方都會需要用到 render 的技巧,在這邊由於要實作 endless page(或稱infinite scrolling),所以需要動態的透過 ender ujs 來新增頁面中的資料。
前言
使用 RoR 開發即將步入第四個月,對於 ujs 懵懵懂懂,所以在這邊小筆記一下專案中所學習的!
筆記
在 controller 中,我們可以透過撰寫 respond_to 指定要 render 的內容,如:
class ExamplesController < ApplicationController
def example
respond_to do |format|
format.js # 如果 client ask for js -> 就 return |format|.js
end
end
end
Controller method(action) 透過 Default Rails mime-types 回傳相對格式作 render,上面的範例中,就會找到 /app/views/examples/example.js.erb
作 render。我們也可以透過block {}
來作動作或檔案的 render,如下:
respond_to do |format|
format.js {
# 在 client 端執行 alert (javascript)
"alert('Hello Rails');",
# page not fount
status: 404,
# render /app/views/your-controller/test_action.js.erb
action: "test_action",
# 將 test_item 以 json 格式 render
json: @test_item,
# 找到指定的檔案作 render
file: filename,
# 直接 render text: Hello
text: "Hello"
}
end
That's it, DONE!
【參考資料】
- Rails respond to format.js api: http://stackoverflow.com/questions/13545148/rails-respond-to-format-js-api
- Rails Guides: http://guides.rubyonrails.org/layouts_and_rendering.html
目的
為了讓自己寫的網站擁有編輯器的功能,可以使用一些現成的編輯器來實現,如 ckeditor、ckeditor-rails、pagedown 諸如此類,由於已經喜歡上寫 markdown 的感覺,所以選了 pagedown-bootstrap-rails 來實現我的功能。
前言
了解 Markdown 怎麼寫之後,就習慣使用支援 markdown 的編輯器了嗎?
筆記
1. Gem
在使用 pagedown-bootstrap-rails 這個 gem 時,我們也得裝 Bootstrap3(Sass) 和 Font Awesome:
gem 'bootstrap-sass'
gem 'font-awesome-rails'
gem 'pagedown-bootstrap-rails'
2. scss、js 設定
scss 的設定為:
@import "bootstrap-sprockets";
@import "bootstrap";
@import "font-awesome";
@import "pagedown_bootstrap";
js 中加入已下:
//= require bootstrap-sprockets
//= require pagedown_bootstrap
//= require pagedown_init
NOTE: bootstrap-sprockets 加在 //= require jquery 後,pagedown_init 加在 pagedown_bootstrap 後
3. SimpleForm 中使用 pagedown
先在 app 中加入 input 與 output 設定:
class PagedownInput < SimpleForm::Inputs::TextInput
def input
out = "<div id=\"wmd-button-bar-#{attribute_name}\"></div>#{wmd_input}"
if input_html_options[:preview]
out << "<div id=\"wmd-preview-#{attribute_name}\" class=\"wmd-preview\"></div>"
end
out.html_safe
end
private
def wmd_input
@builder.text_area(
attribute_name,
input_html_options.merge(
class: 'wmd-input form-control', id: "wmd-input-#{attribute_name}"
)
)
end
end
如此一來,在 simple form 中就可以透過 as: :pagedown
調用 pagedown editor
= f.input :description, as: :pagedown, input_html: { preview: true, rows: 10 }
以上,就可以使用 Pagedown Editor 了!精美如下圖:
4. 顯示 markdown 型態資料
在使用 pagedown editor 輸入完文章或內容後,我們呈現時需要把內容由 Markdown 轉成 HTML,我們利用 javascript 將內容透過 Mardown.Converter
轉成 html 即可!主要有兩個步驟:
(1) 於 js 中撰寫 .wmd-output
設定
- 如果你使用 javascript:
app/javascripts/examples.js $(function() { $('.wmd-output').each(function(i) { var converter = new Markdown.Converter(); var content = $(this).html(); $(this).html(converter.makeHtml(content)); }); });
- 如果你使用 coffeescript:
app/javascripts/examples.coffee $ -> $('.wmd-output').each (i) -> converter = new Markdown.Converter content = $(this).html() $(this).html converter.makeHtml(content)
注意!以上程式碼縮排請自行重新縮排,以免有全形半形錯誤。
(2) 於 view 中調用 .wmd-output
這樣我們就可以在 view 中調用 .wmd-output
來呈現囉!
.wmd-output
:preserve
#{@example.description}
為使輸出為安全性之 html,我們使用 sanitize 作逸出(更新 2015.12.16)
.wmd-output
:preserve
#{sanitize(@example.description)}
以上,就完成了在 rails 中使用 pagedown editor 和顯示 Markdown 內容囉!
That's it, DONE!
【參考資料】
- Pagedown-bootstrap-rails: https://github.com/hughevans/pagedown-bootstrap-rails
- Font-awesome-rails: https://github.com/bokmann/font-awesome-rails
- Rails 導入 Markdown 介紹: http://doruby.kbmj.com/nakanishi/20150729/rails_Markdown_
- Render Markdown in Rails4: http://stackoverflow.com/questions/21536816/rendering-pagedown-markdown-in-rails-4
- Haml Preserve: http://haml.info/docs/yardoc/Haml/Filters/Preserve.html
目的
一個網站在許多地方都需要上傳圖片或照片的功能,例如大頭貼(Avatar)或是商品照片等,而在 rails 中我們有現成的 gem可以使用,你可以使用 paperclip 或 CarrierWave 來實作這個功能,這邊就筆記一下怎麼使用 CarrierWave。
前言
從完全沒寫過 web app 直接學習 Ruby on Rails,說實在真有點勉強...但接觸 RoR 後我發現這真的是我喜歡的東西,希望能保持這個初衷和熱情!也期待自己能有更多的作品 ccc
筆記
1. Gem
先添加 gem 到 Gemfile 中
gem 'carrierwave', '~> 0.10.0'
gem 'rmagick' , '~> 2.15' # 使用 rmagick 作縮放圖片功能
then,
bundle install
【提醒】安裝 rmagick 前得先安裝 libmagickwand-dev。
由於我的環境是 Ubuntu 15.04,所以透過sudo apt-get install libmagickwand-dev
安裝
2. 生成 Uploader
bundle install 後,可以在 rails g -h
看到新增了 uploader,接著
rails g uploader Iamge # 會生成 app/uploaders/image_uploader.rb
3. 添加欄位
在想要上傳圖片的資料表中添加對應的欄位
rails g migration add_image_to_users image:string # 此例為添加一欄位(image)至 User 中
then, 記得 migrate
rake db:migrate
4. 實作上傳及顯示功能
首先在 model 中掛載 uploader
mount_uploader :image, ImageUploader
接著 view 即可作上傳跟顯示,以下為上傳、快取、刪除跟顯示的作法
<%= simple_form_for @user do |f| %>
<%= f.input :image %> <!-- 上傳 -->
<%= f.check_box :remove_image %> <!-- 刪除 -->
<%= f.hidden_field :image_cache %> <!-- 快取 _cache (讓填表時若有誤,不用重新選擇圖片) -->
<%= image_tag @user.image if @user.image? %> <!-- 如果 user 已有圖片的話,就顯示 -->
<% end %>
最後,controller 中記得加入 strong params
params.require(:user).permit( :image, :image_cache, :remove_image)
以上,就完成用 CarrierWave 上傳圖片及顯示的功能囉!但,上傳後圖片大小為原始大小,所以我們可以透過 rmagick 來作 resize。
5. 使用 rmagick
首先在 image_uploader.rb
中取消註解:
include CarrierWave::RMagick # 取消註解
version :thumb do
process :resize_to_fit => [200, 200]
end
上面透過 thumb
,讓上傳時保存原圖,並且產生一個 resize version,這樣想用原圖或縮放後的版本都很方便!
<!-- 原圖尺寸 -->
<%= image_tag @user.image %>
<!-- 縮放後尺寸 -->
<%= image_tag @user.image_url(:thumb) %>
從上面可看到,從 _url(:thumb)
即可取得縮放後的圖片了!
That's it, DONE!
【參考資料】
- CarrierWave: https://github.com/carrierwaveuploader/carrierwave
- RMagick: https://github.com/rmagick/rmagick
目的
本篇來記錄一下怎麼使用 Friendly_id 以及使用 Babosa 這兩個 gem 來達到美化 URL 的效果。
前言
目前學習 Ruby on Rails 大約一個月半了,從學習的開始,打了一篇安裝文後,就被別的有趣的事情吸引去了,例如追韓劇、Running man、康熙、中國好聲音4、爸爸去哪兒3... 跑題了:P
總而言之!現在開始使用 Logdown 作筆記跟分享,希望能幫助到需要的人。
筆記
1. Gem :
先添加 gem 到 Gemfile 中
gem 'friendly_id', '~> 5.1.0'
gem 'babosa'
記得在 console bundle 一下
bundle install
2. 生成資料表
在 console 下
rails g friendly_id
rails g migration add_slug_to_users slug:string:uniq
rake db:migrate
上面的 add_slug_to_users
意思是,加入一個 slug 欄位到資料表 User 中。
3. 撰寫 Model
extend FriendlyId
friendly_id :name, use: :slugged
以上,就完成單純使用 name 來當作路徑,若想自訂路徑格式,就來覆寫 normalize_friendly_id
:
def normalize_friendly_id(input)
input.to_s.to_slug.normalize.to_s
end
如果有使用 babosa gem 的話,就可以透過覆寫
normalize_friendly_id
支援中文囉!
4. Friendly.find
這邊有兩個方法來讓 id 被 friendly 查找:
- 修改 controller 中的 find
app/controller/users_controller.rb
@user = User.friendly.find(params[:id]) # @user = User.find(params[:id])
- 或是,將 config 中的 finder 功能打開:
以上,就完成功能囉! 如果已經有資料了,想直接更新 slug,就直接在 rails console 中執行:config/initializers/friendly_id.rb config.use :finders # 把註解取消,啟動自動查找功能
這樣就會自動把 slug 填上了!User.find_each(&:save)
2015.12.31 新增
若想讓 slug 隨著資料變更時作 update,我們可以透過定義 should_generate_new_friendly_id?
達到目的
def should_generate_new_friendly_id?
slug.blank? || name_changed? # slug 為 nil 或 name column 變更時更新
end
5. 補充
如果想符合 SEO,可以在 normalize_friendly_id
裡定義路徑名稱,例如:
def normalize_friendly_id(input)
"#{id}-#{input.to_s.to_slug.normalize.to_s}" # what ever you want
end
以上面程式碼為例,路徑名稱就變成類似像 xxx/users/1-georgio
。
另外,除了透過 friendly_id 去改變 url path 外,其實 rails 本身的解法是覆寫 model to_params
method:
def to_params
"#{id}-#{name}"
end
就端看想用什麼方案解決囉 :D
That's it, DONE!
【參考資料】
- FriendlyId: https://github.com/norman/friendly_id
- Babosa: https://github.com/norman/babosa
- Friendly URLs: https://gist.github.com/cdmwebs/1209732
- Update slug automatically: http://stackoverflow.com/questions/19072432/friendly-id-slug-not-changing-on-update