SlideShare a Scribd company logo
1 of 151
Download to read offline
使⽤用 Sinatra 結合 Ruby on 
Rails 輕鬆打造完整 Full Stack 
網站加 API Service服務 
慕凡(@ryudoawaru) at MOPCON 2014 
http://5xruby.tw
⼤大家好
是說議程好像和營運沒 
有神⾺馬關係
⾃自我介紹
遊戲業 10 年 
1997 - 2007
1997 
http://goo.gl/m2Xga
2007
2007.03 開始全職創業
2007.03 開始全職創業遊⺠民
Tomlan.TW 
主業:網站開發與維運
FSC 福特⾞車友會 
http://www.focus-sport.club.tw
FREEBBS台灣免費論壇 
http://www.freebbs.tw
⾞車界 
http://www.carclub.tw
五倍紅寶⽯石 
http://5xRuby.tw
全端技術教育訓練 
包含但不限於 Ruby / Rails / iOS / Git
專案開發與技術顧問服務 
Ruby / Rails / iOS
Co-Working Space 
台北⾞車站旁,三鐵共構加⾼高速網路
⽀支援各式社群活動 
以 Ruby 為主但不限於 Ruby
Ruby Taiwan 社群 
http://ruby.tw
Ruby Tuesday 
已舉辦 31 次
Rails Girls Taipei 
已舉辦四屆,學員超過 200 ⼈人 
http://railsgirls.tw
RubyConf Taiwan 
2010 - 2014,2015 預定於 9⽉月
WebConf Taiwan 
下⼀一屆預定於 2015
Agenda 
• Sinatra 簡介 
• Sinatra on Rails 
• 撰寫 Mobile API Service 的⼼心得
Sinatra—歷史 
• 2007年開始 
• 主要作者Konstantin Haase(@rkh) 
• ⺫⽬目前版本1.4
Micro Framework 
2,000⾏行程式碼,只有Rails 的 1%
With Minimal Effort 
只負責路由與Controller,其它組件任選
Smaller Change 
Between Releases 
主要功能幾乎沒有變動,以新增功能為主
Easy to Bootstrap 
幾乎不需設定即可啟動
Let’s Try
Hello Sinatra 
require 'sinatra' 
get '/hello' do 
'Hello World!' 
end 
get '/hello/:name' do 
"Hello #{params[:name]}!" 
end
Request的⼀一⽣生 
1. 將 HTTP Request 抽象為 request 物件 
2. 依據 PATH 決定對應的路由(Route)們 
3. 依序執⾏行路由中的程式,以返回值為 Response
Route 
Code Block for Making Response
Route 
1. HTTP VERB 
2. PATH INFO 
get '/hello/:name' do 
# matches "GET /hello/foo" and "GET /hello/ 
bar" 
# params[:name] is 'foo' or 'bar' 
"Hello #{params[:name]}!" 
end 
3. RETURN RESPONSE
Route Type 
• Named Parameters 
• Splat(Wildcard) Parameters 
• Regular Expressions Parameters 
• Block Parameters
Wildcard Params 
get '/say/*/to/*' do 
# matches /say/hello/to/world 
params[:splat] # => ["hello", "world"] 
end
RegExp Params 
get %r{/hello/([w]+)} do 
"Hello, #{params[:captures].first}!" 
end
Block Params 
get '/hello/:name' do |n| 
# n stores params[:name] 
"Hello #{n}!" 
end 
get '/download/*.*' do |path, ext| 
[path, ext] # => ["path/to/file", "xml"] 
end 
get %r{/hello/([w]+)} do |c| 
"Hello, #{c}!" 
end
Post Form Params 
和 Rails ⼀一樣,被歸納在 params Hash 內
Render Response
Render View 
Default to ERB 
get '/' do 
@products = Product.all 
#render index view by default layout file 
erb :index 
end
Render View 
File Template 
#./vies/layout.erb 
<!DOCTYPE html> 
<html> 
<head><title>Page Title</title></head> 
<body><%=yield%></body> 
</html> 
#./view/products.erb 
<ul> 
<%@products.each do |product|%> 
<li><%=product.name%></li> 
<%end%> 
</ul>
和 Rails Render的差異 
• 沒有 Partial 
• 檔名強制 Symbol 
• 沒有 collection
Filter 
before do 
@member = Member.find(session[:member_id]) 
end 
! 
after do 
LOGGER.info "Request Finished!" 
end
和 Route ⼀一樣有 Params 
before "/products/:product_id" do 
@current_product = 
Product.find(params[:product_id]) 
end 
! 
before //products/(d+?).*" do |product_id| 
@current_product = Product.find(product_id) 
end
可執⾏行複數 Filter 
依照載⼊入順序 
before do 
@member = Member.find(session[:member_id]) 
end 
! 
#GET /products/1 
before "/products/:product_id" do 
@product = Product.find(params[:product_id]) 
end 
! 
get "/products/:id" do 
# @member / @product 都有值 
end
Filter 參數延續傳遞問題 
#GET /products/1 
before "/products/:product_id" do 
#params[:product_id] => 1 
end 
! 
get "/products/:id" do 
#params[:product_id] => nil 
#params[:id] => 1 
end
Request Object 
• 繼承⾃自 Rack::Request 
• 和 Rails ⼀一樣,request 物件具有 xhr? / path… 等⽅方 
法讓你存取 request 的資訊 
• 不具備部份 Rails的 request 物件的⽅方法例如 
subdomain 等 
• 預設 cookies 只能從這裡取
request.accept # 可接受Response Type 
request.body # request body 
request.scheme # "http" 
request.url # "http://example.com/ 
example/foo" 
request.host # "example.com" 
request.path # "/example/foo" 
request.script_name # "/example" 
request.path_info # "/foo" 
request.query_string# GET 查詢參數 
request.(get|post)? # 是否為指定 Method 
request.referrer # 參照⾴頁⾯面URL 
request.user_agent # user agent 
request.cookies # Cookie Hash 
request.xhr? # 是否為 Ajax 
request.ip # client IP address 
request.env # Rack ENV Hash
Error Block 
not_found do 
'This is nowhere to be found.' 
end 
error ActiveRecord::RecordNotFound do 
404, erb(:not_found) 
end
Helper 
helpers do 
def post_path(post) 
to "/posts/#{post.id}" 
end 
end
重要的 Helper們 
• session 
• cookies 
• to / url 
• redirect 
• halt 
• settings
Session 
和 Rails 相同,名為 session 的Hash 
get '/:value' do 
session[:value] = params[:value] 
end
Use Another Session Store 
require "rack/session/redis" 
use Rack::Session::Redis, { 
:url => "redis://localhost:6379/0", 
:namespace => "rack:session", 
:expire_after => 600 
}
Cookie 
預設其實沒有 cookie helper,要從 request 物件取得 Hash 
get '/:value' do 
request.cookies['cdb_sid'] 
end
to Helper 
注意相對路徑,別名url 
#mount in '/' 
to('/') #=> ‘/' 
! 
#mount in '/api/v1' 
to('/') #=> '/api/v1/'
Redirect 
等同 Rails 的 redirect_to 
get '/foo' do 
redirect to('/bar') 
end
Halt 
離開現有流程,停⽌止後續 Route 處理並 Render Response 
before "/products/:id" do 
begin 
@member = Member.find(session[:member_id]) 
rescue ActiveRecord::RecordNotFound 
halt 401, erb(:notfound) 
end 
end 
! 
delete "/products/:id" do 
#halt後,將不會執⾏行 
end
Setting Value 
configure do 
set :foo, 'bar' 
enable :session #set :session, true 
disable :logging 
set(:css_dir) { File.join(views, 'css') } 
end 
! 
get '/' do 
settings.foo? # => true 
settings.foo # => 'bar' 
... 
end
Configure Block 
在程式啟動時執⾏行⼀一次,開啟 DB 連接或執⾏行設定 
configure :development do 
#Only execute when development env 
enable :logging 
end 
! 
configure do 
enable :method_override 
set :view, "app/views" 
end
Variable Scope 
class MyApp < Sinatra::Base 
#此處為 Class Scope 
set :foo, 42 
foo # => 42 
get '/foo' do 
# 進⼊入 Request Scope 
end 
end 
Class Scope 
Instance Scope
Variable Scope 
• Application / Class Scope 
• 發⽣生於Class 宣告或 Configure 區塊 
• Instance / Request Scope 
• 發⽣生於Route / Filter 區塊
開始 
Class 宣告 
Request 發⽣生 
尋找 Route 
執⾏行 Code 
Block 
是否還有下⼀一個 
Code Block? 
最後⼀一個 Code Block結束 
返回 Response 
等待下⼀一個 
Request 
發⽣生 
否 
是 
class MyApp 
MyApp.new 
包含FIlter 
此時還會執⾏行 
After Filters
Variable Scope 
• Application / Class Scope 
• 只發⽣生在載⼊入程式時 
• Instance / Request Scope 
• 每次 Request 發⽣生,都會產⽣生⼀一個新的 Instance 
(實體)
變數傳遞持久性 
Named 
Params 
Form 
Params 
Instance 
Variables 
Request 
Object 
持久性僅限於 
Route Block 有有有
Modular App Style 
require 'sinatra/base' 
class MyApp < Sinatra::Base 
# OR Sinatra::Application 
set :sessions, true 
set :foo, 'bar' 
get '/' do 
'Hello world!' 
end 
end
Modular V.S. Classic 
Style
Rack
Rackup File 
config.ru
Rackup File 
# This file is used by Rack-based servers to 
start the application. 
! 
require ::File.expand_path('../config/ 
environment', __FILE__) 
run Rails.application
Rack Middlewares in Rails
Modular App in Rackup File 
#config.ru 
require 'sinatra/base' 
class MyApp < Sinatra::Base 
# OR Sinatra::Application 
set :sessions, true 
set :foo, 'bar' 
get '/' do 
'Hello world!' 
end 
end 
run MyApp
Why need Modular? 
• 在 Rackup 中被識別(middleware) 
• 在 Rails 中被識別 
• 做為⼀一個獨⽴立的模組
Ruby 
Web 
Framework 
Application 
Server 
Middlewares End Point
Run Multi App in 1 Rackup 
require 'sinatra/base' 
class App1 < Sinatra::Application 
get '/' do 
'app1' 
end 
end 
class App2 < Sinatra::Application 
get '/' do 
'app2' 
end 
end 
map('/app1'){run App1} 
map('/app2'){run App2}
Sinatra on Rails 
Mount Rack Middleware in your Rails App
Mount in Rails Route 
#routes.rb 
Rails.application.routes.draw do 
root 'hello#world' 
resources :customers 
mount Api::V1, at: '/api/v1' 
end 
#lib/api/v1.rb 
class Api::V1 < Sinatra::Application 
get '/' do 
'API' 
end 
end
Mount Outside Rails 
# This file is used by Rack-based servers to 
start the application. 
require ::File.expand_path('../config/ 
environment', __FILE__) 
require ::File.expand_path('../lib/api/v1', 
__FILE__) 
map '/api/v1' do 
run Api::V1 
end 
run Rails.application
哪種⽅方式⽐比較好?
Benchmark
Test Suite 
• MacPro Retina ’13 2012 
• DB:PostgreSQL 
• Rails:4.1,Sinatra:1.4.5 
• App Server:Thin
測試程式 
• https://github.com/ryudoawaru/rails-metal-test-example- 
mopcon2014 
• 從 DB 的 Customer 資料庫抓 頭 10筆資料 render 
JSON
測試⽅方式 
• ab -c 10 -n 10 <URL> 
• 反覆測試五次
Model Code 
class Customer < ActiveRecord::Base 
def self.fetch(idgt = nil) 
where("customerid > ?", 
idgt.to_i).limit(20).map(&:ser) 
end 
end
Rails Controller Code 
class CustomersController < 
ApplicationController 
def index 
respond_to do |f| 
f.json do 
render json: Customer.fetch.to_json 
end 
end 
end 
end
Sinatra Code 
module Api 
class V1 < Sinatra::Application 
get '/customers.json' do 
Customer.fetch.to_json 
end 
end 
end
config.ru 
# This file is used by Rack-based servers to 
start the application. 
require ::File.expand_path('../config/ 
environment', __FILE__) 
require ::File.expand_path('../lib/api/v1', 
__FILE__) 
map '/ext/api/v1' do 
run Api::V1 
end 
run Rails.application
routes.rb 
Rails.application.routes.draw do 
mount Api::V1, at: '/api/v1' 
root 'hello#world' 
resources :customers 
end
URL 對應表 
Rails http://localhost:3000/customers.json 
Mount in Rails 
Route 
http://localhost:3000/api/v1/customers.json 
Mount in 
Rackup 
http://localhost:3000/ext/api/v1/customers.json
測試結果 
Rails 
Mount in Rails 
Route 
Mount in Rackup 
(outside of Rails) 
RPQ平均150~ 200~ 300+
Why Rails Slow?
Middlewares Stack
Rack Middleware就是 
Application Server 
Middleware 
Middleware 
Endpoint APP
⼀一個⼀一直玩的概念
堆疊⽐比較 
Application Server 
Middleware 
Middleware 
Rails + Sinatra
Middleware 
Middleware 
Rails 
Application Server 
Middleware 
PATH 
Middleware 
Rails 
map ‘/’ 
map ‘/ext/api/v1’
其實 Rails 也有 rails-api 
Gem 
減少 Middleware Stack
Sinatra on Rails 
架構的好處
在同⼀一個專案下,實際 
分離前後台 
• 程式碼在同⼀一個專案 
• 維護性++
發揮各⾃自⻑⾧長處 
• ⽤用 Rails 寫後台—> 快速⽅方便 
• Sinatra 寫 API —> 簡潔有⼒力
共⽤用部份資源 
• Model 
• Library 
• 載⼊入的 Gem 
• Helper(不建議)
節省⾃自⾏行編寫 Bootstrap 
程序的時間與精⼒力
沒有 Rails 就要⾃自⼰己寫 
• Rubygem / Bundler 
• Require 
• Model / DB 連接 
• Library的前置作業或設定(例如 Uploader)
前後台⽤用 Hostname 分離 
• api.example.com -> API ⽤用 
• backend.example.com -> 管理介⾯面⽤用
可以只開啟Rails或只開啟 
Sinatra 
#config.ru 
if ENV['RUN_ONLY'] == 'rails' 
run Rails.application 
elsif ENV['RUN_ONLY'] == 'sinatra' 
run MySinatraApp 
else 
map '/api/v1' do 
run MySinatraApp 
end 
run Rails.application 
end
使⽤用 Sinatra 開發 
Mobile API的注意事項
注意 Content-Type 
Header
before '*.json' do 
headers "Content-Type" => "text/json" 
end
活⽤用 Status Code 
get '/events/:id.json' do 
begin 
event = Event.find(params[:id]) 
halt 404 
end 
end
活⽤用 Response 
Header
Response Page Information 
get '/events.json' do 
collection = Event.api_search(…) 
headers 'total_pages' => 
collection.total_pages.to_s 
headers 'total_count' => 
collection.total_count.to_s 
headers 'current_size' => collection.size.to_s 
render_collection(collection).to_json_with_encode 
end
Mobile API ⾝身份認證⽅方 
式 
以⾃自有服務為主
Request Header 
通常 APP 的 WEB Client 都不具備 Session 功能
Auth By Header 
#Helper 
def current_mobile_session 
token = request.env[‘HTTP_AUTHTOKEN'] || 
session[:authtoken] 
@current_mobile_session ||= 
MobileSession.auth_api_session(token) 
end 
! 
def current_user 
@current_user ||= current_mobile_session.user 
if current_mobile_session.present? 
end
Token的來源 
• 裝置的 UUID(裝置辨認) 
• 某種時間段戳記(例如 EPOCH / ⼀一週 or ⼀一天秒數) 
• User Table 的某個欄位(Access Token) 
• 以上三者 MD5 加密
WebView in APP問題 
• 有時會遇到需要辨認⾝身份的 WebView(如購物) 
• WebView 在啟動同時發出的 Request 可以包含⾃自訂 
Header,但是在 WebView 內的連結或表單不⾏行 
• 反過來,在 WebView 內可以⽤用 Cookie / Session
流程 
1. 開啟WebView,發出初始 HTML Request(有 
Header) 
2. Server 端接收 Request 時,設定 Session 
3. WebView 內由 User 點擊再發出的 Request 就會有 
Session
範例 
before do 
token = request.env['HTTP_AUTHTOKEN'] 
|| session[:authtoken] 
##接下來⽤用 token 進⾏行認證 
end
JSON Generation
#config/initializer/hash.rb 
[Array, Hash].each do |klass| 
klass.class_eval do 
def to_json_with_encode 
JSON.generate(self, ascii_only: true) 
end 
end 
end
對於從寫 Web 轉到寫 
Mobile API 的幾點⼩小建議
時間欄位請傳EPOCH 整數 
class Customer < ActiveRecord::Base 
def created_at_i 
created_at.to_i 
end 
end
使⽤用 before / after_id⽽而⾮非分⾴頁 
#in Controller 
# GET ‘/pms/before/12345’ 
get '/pms/before/:pmid' do 
Pm.before_pmid(params[:pmid]) 
.... 
end
減少 Request 數量 
顧及流暢性
N個願望⼀一次滿⾜足 
get '/all.json' do 
{unread_messages: current_user.pms.all, 
events: Event.recent(10) }.to_json 
end
論寫 Sinatra 的必要性 
藏在魔法後⾯面的東⻄西
標準的 Rails 程式碼 
# in app/controllers/customers_controller.rb 
class CustomersController < ApplicatoController 
... 
def index 
@customers = Customer.page(1) 
end 
end 
# in app/views/customers/index.html.erb 
<ul> 
<%=render @customers%> 
</ul> 
# in app/views/customers/_customer.html.erb 
<li><%=customer.id%>:<%=customer.name%></li>
它可以產⽣生的 HTML 
<ul> 
<li>1:很好填</li> 
<li>2:⾃自⼰己填</li> 
<li>3:不想填</li> 
<li>4:給你填</li> 
</ul>
你知道 render 那⾏行發⽣生了 
神⾺馬事嗎?
順序 
<%=render @customers%> 
1. 查看@customers 集合中的成員 Class -> Customer 
2. 以 Class Name 查詢是否有相對應的 Partial View 存在 
3. 以 @customers 為 collection 的值來 render Partial 
<%=render partial: 'customer', collection: @customers%>
另⼀一個常⾒見問題 
假設 @customer 是⼀一筆存在的 Customer 紀錄, id為 1 
# 
<%=form_for @customer do |f|%> 
.... 
<%end%> 
#將會產⽣生 
<form action="/customers/1" method="post"> 
<input name="_method" value="put"/> 
... 
</form>
Q:為何 @customer 
可以轉成 /customers/1
@customer.new_record? # false 
@customer.class.to_s # Customer 
@customer.class.to_s.underscore # customer 
@customer.class.to_s.underscore.pluralize 
# => customers
Q:請問 pluralize 是 Ruby 
預設的 String Instance 
Method嗎?
i[~] $ irb 
2.1.3 :001 > 'customer' 
=> "customer" 
2.1.3 :002 > 'customer'.pluralize 
NoMethodError: undefined method `pluralize' for 
"customer":String 
from (irb):2 
from /Users/ryudo/.rvm/rubies/ruby-2.1.3/bin/ 
irb:11:in `<main>' 
2.1.3 :003 >
Q:_method 是什麼?
_method Param 
• 瀏覽器不⽀支援 GET / POST 以外的 REQUEST 
METHOD 
• ⽤用 _method 代替 REQUEST METHOD 
• 簡稱 Method Override
寫 Sinatra ,預設你必 
需⾃自⾏行處理這些問題
http://shugo.net/tmp/rails-syndrome. 
pdf
“Difference between a master and 
a beginner? The master has failed 
more times than the beginner has 
even tried.” 
⼤大師與新⼿手之間的差別,就是⼤大師失敗過的次 
數,⽐比新⼿手嘗試過的次數還多
共勉之
Fin
Contact Me 
• 慕凡 
• http://ryudo.tw 
• ryudo@5xruby.tw 
• Github:ryudoawaru 
• Twitter:ryudoawaru
代客徵求 ROR Developer 
• 台北知名網站公司 
• ⽉月薪 45 - 60 K 
• 職缺:Junior ROR Developer 
• 詳情請洽 http://goo.gl/h2YOAU 或找我 
• 寄履歷到 hi@5xruby.tw

More Related Content

What's hot

View 與 Blade 樣板引擎
View 與 Blade 樣板引擎View 與 Blade 樣板引擎
View 與 Blade 樣板引擎Shengyou Fan
 
開發環境建置
開發環境建置開發環境建置
開發環境建置Shengyou Fan
 
開發環境建置
開發環境建置開發環境建置
開發環境建置Shengyou Fan
 
啟動 Laravel 與環境設定
啟動 Laravel 與環境設定啟動 Laravel 與環境設定
啟動 Laravel 與環境設定Shengyou Fan
 
Model 設定與 Seeding
Model 設定與 SeedingModel 設定與 Seeding
Model 設定與 SeedingShengyou Fan
 
COSCUP 2016 Laravel 部署工作坊 - 部署指南
COSCUP 2016 Laravel 部署工作坊 - 部署指南COSCUP 2016 Laravel 部署工作坊 - 部署指南
COSCUP 2016 Laravel 部署工作坊 - 部署指南Shengyou Fan
 
Model 設定與 Seeding
Model 設定與 SeedingModel 設定與 Seeding
Model 設定與 SeedingShengyou Fan
 
給你一個使用 Laravel 的理由
給你一個使用 Laravel 的理由給你一個使用 Laravel 的理由
給你一個使用 Laravel 的理由Shengyou Fan
 
Route 路由控制
Route 路由控制Route 路由控制
Route 路由控制Shengyou Fan
 
Schema & Migration操作
Schema & Migration操作Schema & Migration操作
Schema & Migration操作Shengyou Fan
 
成為全能 php 攻城獅
成為全能 php 攻城獅成為全能 php 攻城獅
成為全能 php 攻城獅Shengyou Fan
 
Migrations 與 Schema操作
Migrations 與 Schema操作Migrations 與 Schema操作
Migrations 與 Schema操作Shengyou Fan
 
Package 安裝與使用
Package 安裝與使用Package 安裝與使用
Package 安裝與使用Shengyou Fan
 
Laravel - 系統全攻略(續)
Laravel - 系統全攻略(續)Laravel - 系統全攻略(續)
Laravel - 系統全攻略(續)Vincent Chi
 
Laravel - 系統全攻略
Laravel - 系統全攻略Laravel - 系統全攻略
Laravel - 系統全攻略Vincent Chi
 
開發流程與工具介紹
開發流程與工具介紹開發流程與工具介紹
開發流程與工具介紹Shengyou Fan
 

What's hot (20)

View 與 Blade 樣板引擎
View 與 Blade 樣板引擎View 與 Blade 樣板引擎
View 與 Blade 樣板引擎
 
開發環境建置
開發環境建置開發環境建置
開發環境建置
 
開發環境建置
開發環境建置開發環境建置
開發環境建置
 
啟動 Laravel 與環境設定
啟動 Laravel 與環境設定啟動 Laravel 與環境設定
啟動 Laravel 與環境設定
 
Model 設定與 Seeding
Model 設定與 SeedingModel 設定與 Seeding
Model 設定與 Seeding
 
COSCUP 2016 Laravel 部署工作坊 - 部署指南
COSCUP 2016 Laravel 部署工作坊 - 部署指南COSCUP 2016 Laravel 部署工作坊 - 部署指南
COSCUP 2016 Laravel 部署工作坊 - 部署指南
 
Eloquent ORM
Eloquent ORMEloquent ORM
Eloquent ORM
 
Model 設定與 Seeding
Model 設定與 SeedingModel 設定與 Seeding
Model 設定與 Seeding
 
給你一個使用 Laravel 的理由
給你一個使用 Laravel 的理由給你一個使用 Laravel 的理由
給你一個使用 Laravel 的理由
 
Route 路由控制
Route 路由控制Route 路由控制
Route 路由控制
 
CRUD 綜合運用
CRUD 綜合運用CRUD 綜合運用
CRUD 綜合運用
 
HTML 語法教學
HTML 語法教學HTML 語法教學
HTML 語法教學
 
驗證與訊息
驗證與訊息驗證與訊息
驗證與訊息
 
Schema & Migration操作
Schema & Migration操作Schema & Migration操作
Schema & Migration操作
 
成為全能 php 攻城獅
成為全能 php 攻城獅成為全能 php 攻城獅
成為全能 php 攻城獅
 
Migrations 與 Schema操作
Migrations 與 Schema操作Migrations 與 Schema操作
Migrations 與 Schema操作
 
Package 安裝與使用
Package 安裝與使用Package 安裝與使用
Package 安裝與使用
 
Laravel - 系統全攻略(續)
Laravel - 系統全攻略(續)Laravel - 系統全攻略(續)
Laravel - 系統全攻略(續)
 
Laravel - 系統全攻略
Laravel - 系統全攻略Laravel - 系統全攻略
Laravel - 系統全攻略
 
開發流程與工具介紹
開發流程與工具介紹開發流程與工具介紹
開發流程與工具介紹
 

Similar to Mopcon2014 - 使用 Sinatra 結合 Ruby on Rails 輕鬆打造完整 Full Stack 網站加 API Service服務

HTML5概览
HTML5概览HTML5概览
HTML5概览Adam Lu
 
用JAX-RS和Jersey完成RESTful Web Services
用JAX-RS和Jersey完成RESTful Web Services用JAX-RS和Jersey完成RESTful Web Services
用JAX-RS和Jersey完成RESTful Web Servicesjavatwo2011
 
View 與 Blade 樣板引擎
View 與 Blade 樣板引擎View 與 Blade 樣板引擎
View 與 Blade 樣板引擎Shengyou Fan
 
Migrations 與 Schema 操作
Migrations 與 Schema 操作Migrations 與 Schema 操作
Migrations 與 Schema 操作Shengyou Fan
 
Erlang Practice
Erlang PracticeErlang Practice
Erlang Practicelitaocheng
 
Html5和css3入门
Html5和css3入门Html5和css3入门
Html5和css3入门Xiujun Ma
 
從 Web Site 到 Web Application,從 Web Services 到 Mobile Services
從 Web Site 到 Web Application,從 Web Services 到 Mobile Services從 Web Site 到 Web Application,從 Web Services 到 Mobile Services
從 Web Site 到 Web Application,從 Web Services 到 Mobile ServicesKuo-Chun Su
 
Openshift by mtchang
Openshift by mtchangOpenshift by mtchang
Openshift by mtchangChang Mt
 
Go语言web开发
Go语言web开发Go语言web开发
Go语言web开发Andy Shi
 
Node js实践
Node js实践Node js实践
Node js实践myzykj
 
twMVC#44 讓我們用 k6 來進行壓測吧
twMVC#44 讓我們用 k6 來進行壓測吧twMVC#44 讓我們用 k6 來進行壓測吧
twMVC#44 讓我們用 k6 來進行壓測吧twMVC
 
第三方内容开发最佳实践
第三方内容开发最佳实践第三方内容开发最佳实践
第三方内容开发最佳实践taobao.com
 
Exam 98-375 HTML5 Application Development Fundamentals
Exam 98-375 HTML5 Application Development FundamentalsExam 98-375 HTML5 Application Development Fundamentals
Exam 98-375 HTML5 Application Development FundamentalsChieh Lin
 
Rest Ruby On Rails
Rest Ruby On RailsRest Ruby On Rails
Rest Ruby On Railsshaokun
 
2021.laravelconf.tw.slides3
2021.laravelconf.tw.slides32021.laravelconf.tw.slides3
2021.laravelconf.tw.slides3LiviaLiaoFontech
 
X Fire开发指南
X Fire开发指南X Fire开发指南
X Fire开发指南yiditushe
 
基于 FRIDA 的全平台逆向分析
基于 FRIDA 的全平台逆向分析基于 FRIDA 的全平台逆向分析
基于 FRIDA 的全平台逆向分析CC
 
Real time web实时信息流推送
Real time web实时信息流推送Real time web实时信息流推送
Real time web实时信息流推送yongboy
 
Real-Time Web实时信息流推送
Real-Time Web实时信息流推送Real-Time Web实时信息流推送
Real-Time Web实时信息流推送yongboy
 

Similar to Mopcon2014 - 使用 Sinatra 結合 Ruby on Rails 輕鬆打造完整 Full Stack 網站加 API Service服務 (20)

HTML5概览
HTML5概览HTML5概览
HTML5概览
 
用JAX-RS和Jersey完成RESTful Web Services
用JAX-RS和Jersey完成RESTful Web Services用JAX-RS和Jersey完成RESTful Web Services
用JAX-RS和Jersey完成RESTful Web Services
 
View 與 Blade 樣板引擎
View 與 Blade 樣板引擎View 與 Blade 樣板引擎
View 與 Blade 樣板引擎
 
CRUD 綜合運用
CRUD 綜合運用CRUD 綜合運用
CRUD 綜合運用
 
Migrations 與 Schema 操作
Migrations 與 Schema 操作Migrations 與 Schema 操作
Migrations 與 Schema 操作
 
Erlang Practice
Erlang PracticeErlang Practice
Erlang Practice
 
Html5和css3入门
Html5和css3入门Html5和css3入门
Html5和css3入门
 
從 Web Site 到 Web Application,從 Web Services 到 Mobile Services
從 Web Site 到 Web Application,從 Web Services 到 Mobile Services從 Web Site 到 Web Application,從 Web Services 到 Mobile Services
從 Web Site 到 Web Application,從 Web Services 到 Mobile Services
 
Openshift by mtchang
Openshift by mtchangOpenshift by mtchang
Openshift by mtchang
 
Go语言web开发
Go语言web开发Go语言web开发
Go语言web开发
 
Node js实践
Node js实践Node js实践
Node js实践
 
twMVC#44 讓我們用 k6 來進行壓測吧
twMVC#44 讓我們用 k6 來進行壓測吧twMVC#44 讓我們用 k6 來進行壓測吧
twMVC#44 讓我們用 k6 來進行壓測吧
 
第三方内容开发最佳实践
第三方内容开发最佳实践第三方内容开发最佳实践
第三方内容开发最佳实践
 
Exam 98-375 HTML5 Application Development Fundamentals
Exam 98-375 HTML5 Application Development FundamentalsExam 98-375 HTML5 Application Development Fundamentals
Exam 98-375 HTML5 Application Development Fundamentals
 
Rest Ruby On Rails
Rest Ruby On RailsRest Ruby On Rails
Rest Ruby On Rails
 
2021.laravelconf.tw.slides3
2021.laravelconf.tw.slides32021.laravelconf.tw.slides3
2021.laravelconf.tw.slides3
 
X Fire开发指南
X Fire开发指南X Fire开发指南
X Fire开发指南
 
基于 FRIDA 的全平台逆向分析
基于 FRIDA 的全平台逆向分析基于 FRIDA 的全平台逆向分析
基于 FRIDA 的全平台逆向分析
 
Real time web实时信息流推送
Real time web实时信息流推送Real time web实时信息流推送
Real time web实时信息流推送
 
Real-Time Web实时信息流推送
Real-Time Web实时信息流推送Real-Time Web实时信息流推送
Real-Time Web实时信息流推送
 

More from Mu-Fan Teng

My experience of Ruby Education in Taiwan
My experience of Ruby Education in TaiwanMy experience of Ruby Education in Taiwan
My experience of Ruby Education in TaiwanMu-Fan Teng
 
WebSocket For Web Rubyists
WebSocket For Web RubyistsWebSocket For Web Rubyists
WebSocket For Web RubyistsMu-Fan Teng
 
20150118 學個 Sinatra 好過年
20150118 學個 Sinatra 好過年20150118 學個 Sinatra 好過年
20150118 學個 Sinatra 好過年Mu-Fan Teng
 
實踐大學教案20140329
實踐大學教案20140329實踐大學教案20140329
實踐大學教案20140329Mu-Fan Teng
 
Rails Girls Taiwan 2014 Intro
Rails Girls Taiwan 2014 IntroRails Girls Taiwan 2014 Intro
Rails Girls Taiwan 2014 IntroMu-Fan Teng
 
Introduce Ruby Taiwan@Rubykaigi2013
Introduce Ruby Taiwan@Rubykaigi2013Introduce Ruby Taiwan@Rubykaigi2013
Introduce Ruby Taiwan@Rubykaigi2013Mu-Fan Teng
 
Webconf2013-非典型貧窮網站維運經驗分享
Webconf2013-非典型貧窮網站維運經驗分享Webconf2013-非典型貧窮網站維運經驗分享
Webconf2013-非典型貧窮網站維運經驗分享Mu-Fan Teng
 
Concurrency model for mysql data processing@rubyconf.tw 2012
Concurrency model for mysql data processing@rubyconf.tw 2012Concurrency model for mysql data processing@rubyconf.tw 2012
Concurrency model for mysql data processing@rubyconf.tw 2012Mu-Fan Teng
 

More from Mu-Fan Teng (9)

My experience of Ruby Education in Taiwan
My experience of Ruby Education in TaiwanMy experience of Ruby Education in Taiwan
My experience of Ruby Education in Taiwan
 
WebSocket For Web Rubyists
WebSocket For Web RubyistsWebSocket For Web Rubyists
WebSocket For Web Rubyists
 
20150118 學個 Sinatra 好過年
20150118 學個 Sinatra 好過年20150118 學個 Sinatra 好過年
20150118 學個 Sinatra 好過年
 
實踐大學教案20140329
實踐大學教案20140329實踐大學教案20140329
實踐大學教案20140329
 
Rails Girls Taiwan 2014 Intro
Rails Girls Taiwan 2014 IntroRails Girls Taiwan 2014 Intro
Rails Girls Taiwan 2014 Intro
 
Introduce Ruby Taiwan@Rubykaigi2013
Introduce Ruby Taiwan@Rubykaigi2013Introduce Ruby Taiwan@Rubykaigi2013
Introduce Ruby Taiwan@Rubykaigi2013
 
Webconf2013-非典型貧窮網站維運經驗分享
Webconf2013-非典型貧窮網站維運經驗分享Webconf2013-非典型貧窮網站維運經驗分享
Webconf2013-非典型貧窮網站維運經驗分享
 
Concurrency model for mysql data processing@rubyconf.tw 2012
Concurrency model for mysql data processing@rubyconf.tw 2012Concurrency model for mysql data processing@rubyconf.tw 2012
Concurrency model for mysql data processing@rubyconf.tw 2012
 
Ruby on discuz
Ruby on discuzRuby on discuz
Ruby on discuz
 

Mopcon2014 - 使用 Sinatra 結合 Ruby on Rails 輕鬆打造完整 Full Stack 網站加 API Service服務