Tháng 2 năm 2009
Giới thiệu
"Ruby nằm ở đâu trong danh sách thư viện ứng dụng?"
Với mong muốn đáp ứng nhu cầu của các nhà phát triển và sự phổ biến lâu dài của Ruby on Rails (RoR), đồng nghiệp Jeff Fisher của tôi đã tạo ra một thư viện tiện ích Ruby từ sâu trong lòng Núi Doom. Xin lưu ý rằng đây không phải là một thư viện ứng dụng đầy đủ, nhưng nó xử lý các nguyên tắc cơ bản như xác thực và thao tác XML cơ bản. Bạn cũng cần làm việc trực tiếp với nguồn cấp dữ liệu Atom bằng cách sử dụng mô-đun REXML và XPath.
Đối tượng
Bài viết này dành cho những nhà phát triển muốn truy cập vào Google Data API bằng Ruby, cụ thể là Ruby on Rails. Hướng dẫn này giả định rằng người đọc đã quen thuộc với ngôn ngữ lập trình Ruby và khung phát triển web Rails. Tôi tập trung vào Documents List API cho hầu hết các mẫu, nhưng bạn có thể áp dụng các khái niệm tương tự cho bất kỳ Data API nào.
Bắt đầu
Yêu cầu
- Ruby 1.8.6, bản vá cấp 114 trở lên tải xuống
- RubyGems 1.3.1 trở lên tải xuống
- Tải Rails 2.2.2 trở lên
Cài đặt Thư viện tiện ích dữ liệu của Google cho Ruby
Để lấy thư viện này, bạn có thể tải trực tiếp nguồn thư viện xuống từ dịch vụ lưu trữ dự án hoặc cài đặt gem:
sudo gem install gdata
Lưu ý: Để chắc chắn, hãy chạy gem list --local
để xác minh rằng gem đã được cài đặt đúng cách.
Xác thực
ClientLogin
ClientLogin cho phép ứng dụng của bạn đăng nhập người dùng vào tài khoản Google hoặc G Suite của họ theo cách lập trình. Sau khi xác thực thông tin đăng nhập của người dùng, Google sẽ phát hành một mã thông báo Uỷ quyền để tham chiếu trong các yêu cầu API tiếp theo. Mã thông báo vẫn hợp lệ trong một khoảng thời gian nhất định, do dịch vụ Google mà bạn đang làm việc xác định. Vì lý do bảo mật và để mang lại trải nghiệm tốt nhất cho người dùng, bạn chỉ nên sử dụng ClientLogin khi phát triển các ứng dụng đã cài đặt trên máy tính. Đối với các ứng dụng web, bạn nên sử dụng AuthSub hoặc OAuth.
Thư viện Ruby có một lớp ứng dụng cho từng API. Ví dụ: sử dụng đoạn mã sau để đăng nhập user@gmail.com
vào Documents List Data API:
client = GData::Client::DocList.new client.clientlogin('user@gmail.com', 'pa$$word')
The YouTube Data API would be:
client = GData::Client::YouTube.new client.clientlogin('user@gmail.com', 'pa$$word')
Xem danh sách đầy đủ các lớp dịch vụ đã triển khai.
Nếu dịch vụ không có lớp ứng dụng, hãy sử dụng lớp GData::Client::Base
.
Ví dụ: mã sau đây buộc người dùng đăng nhập bằng tài khoản G Suite.
client_login_handler = GData::Auth::ClientLogin
.new('writely', :account_type => 'HOSTED')
token = client_login_handler.get_token('user@example.com', 'pa$$word', 'google-RailsArticleSample-v1')
client = GData::Client::Base.new(:auth_handler => client_login_handler)
Lưu ý: Theo mặc định, thư viện này sử dụng HOSTED_OR_GOOGLE
cho accountType
. Các giá trị có thể là HOSTED_OR_GOOGLE
, HOSTED
hoặc GOOGLE
.
Một trong những nhược điểm của việc sử dụng ClientLogin là ứng dụng của bạn có thể nhận được các thử thách CAPTCHA khi đăng nhập không thành công. Nếu điều đó xảy ra, bạn có thể xử lý lỗi bằng cách gọi phương thức clientlogin()
kèm theo các tham số bổ sung: client.clientlogin(username, password, captcha_token, captcha_answer)
. Hãy tham khảo tài liệu đầy đủ về Xác thực cho các ứng dụng đã cài đặt để biết thêm thông tin về cách xử lý CAPTCHA.
AuthSub
Tạo URL AuthSubRequest
scope = 'http://www.google.com/calendar/feeds/' next_url = 'http://example.com/change/to/your/app' secure = false # set secure = true for signed AuthSub requests sess = true authsub_link = GData::Auth::AuthSub.get_url(next_url, scope, secure, sess)
Khối mã trước đó sẽ tạo URL sau đây trong authsub_link
:
https://www.google.com/accounts/AuthSubRequest?next=http%3A%2F%2Fexample.com%2Fchange%2Fto%2Fyour%2Fapp&scope=http%3A%2F%2Fwww.google.com%2Fcalendar%2Ffeeds%2F&session=1&secure=0
Bạn cũng có thể sử dụng phương thức authsub_url
của đối tượng máy khách. Mỗi lớp dịch vụ đều đã đặt một thuộc tính authsub_scope
mặc định nên bạn không cần chỉ định thuộc tính của riêng mình.
client = GData::Client::DocList.new next_url = 'http://example.com/change/to/your/app' secure = false # set secure = true for signed AuthSub requests sess = true domain = 'example.com' # force users to login to a G Suite hosted domain authsub_link = client.authsub_url(next_url, secure, sess, domain)
Khối mã trước đó sẽ tạo URL sau:
https://www.google.com/accounts/AuthSubRequest?next=http%3A%2F%2Fexample.com%2Fchange%2Fto%2Fyour%2Fapp&scope=http%3A%2F%2Fdocs.google.com%2Ffeeds%2F&session=1&secure=0&hd=example.com
Nâng cấp mã thông báo dùng một lần thành mã thông báo phiên
AuthSub sẽ chuyển hướng người dùng trở lại http://example.com/change/to/your/app?token=SINGLE_USE_TOKEN
sau khi họ cấp quyền truy cập vào dữ liệu của mình. Xin lưu ý rằng URL này chỉ là next_url
của chúng tôi với mã thông báo dùng một lần được thêm vào dưới dạng tham số truy vấn.
Tiếp theo, hãy trao đổi mã thông báo dùng một lần để lấy mã thông báo phiên có thời hạn sử dụng lâu dài:
client.authsub_token = params[:token] # extract the single-use token from the URL query params session[:token] = client.auth_handler.upgrade() client.authsub_token = session[:token] if session[:token]
Secure AuthSub cũng tương tự như vậy. Bạn chỉ cần thêm khoá riêng tư trước khi nâng cấp mã thông báo:
PRIVATE_KEY = '/path/to/private_key.pem' client.authsub_token = params[:token] client.authsub_private_key = PRIVATE_KEY session[:token] = client.auth_handler.upgrade() client.authsub_token = session[:token] if session[:token]
Lưu ý: Để sử dụng mã thông báo bảo mật, hãy nhớ đặt secure=true
khi yêu cầu mã thông báo dùng một lần. Xem phần Tạo URL AuthSubRequest ở trên.
Quản lý mã thông báo
AuthSub cung cấp thêm 2 trình xử lý là AuthSubTokenInfo và AuthSubRevokeToken để quản lý mã thông báo. AuthSubTokenInfo
rất hữu ích khi kiểm tra tính hợp lệ của mã thông báo. AuthSubRevokeToken
cho phép người dùng ngừng truy cập vào dữ liệu của họ. Ứng dụng của bạn nên sử dụng AuthSubRevokeToken
làm phương pháp hay nhất. Cả hai phương thức đều được hỗ trợ trong thư viện Ruby.
Cách truy vấn siêu dữ liệu của mã thông báo:
client.auth_handler.info
Cách thu hồi mã thông báo phiên:
client.auth_handler.revoke
Hãy xem tài liệu đầy đủ về Xác thực AuthSub cho các ứng dụng web để biết toàn bộ thông tin về AuthSub.
OAuth
Tại thời điểm viết bài viết này, OAuth chưa được thêm vào mô-đun GData::Auth
.
Việc sử dụng OAuth trong thư viện tiện ích sẽ tương đối đơn giản khi bạn dùng oauth-plugin của Rails hoặc oauth gem của Ruby. Trong cả hai trường hợp, bạn đều muốn tạo một đối tượng GData::HTTP::Request
và truyền cho đối tượng đó tiêu đề Authorization
do mỗi thư viện tạo.
Truy cập vào nguồn cấp dữ liệu
GET (tìm nạp dữ liệu)
Sau khi thiết lập một đối tượng máy khách, hãy sử dụng phương thức get()
của đối tượng đó để truy vấn một nguồn cấp dữ liệu của Google. Bạn có thể dùng XPath để truy xuất các phần tử Atom cụ thể. Sau đây là ví dụ về cách truy xuất Tài liệu của người dùng trên Google:
feed = client.get('http://docs.google.com/feeds/documents/private/full').to_xml feed.elements.each('entry') do |entry| puts 'title: ' + entry.elements['title'].text puts 'type: ' + entry.elements['category'].attribute('label').value puts 'updated: ' + entry.elements['updated'].text puts 'id: ' + entry.elements['id'].text # Extract the href value from each <atom:link> links = {} entry.elements.each('link') do |link| links[link.attribute('rel').value] = link.attribute('href').value end puts links.to_s end
POST (tạo dữ liệu mới)
Sử dụng phương thức post()
của một ứng dụng để tạo dữ liệu mới trên máy chủ. Ví dụ sau đây sẽ thêm new_writer@example.com
làm cộng tác viên vào tài liệu có mã nhận dạng: doc_id
.
# Return documents the authenticated user owns feed = client.get('http://docs.google.com/feeds/documents/private/full/-/mine').to_xml entry = feed.elements['entry'] # first <atom:entry> acl_entry = <<-EOF <entry xmlns="http://www.w3.org/2005/Atom" xmlns:gAcl='http://schemas.google.com/acl/2007'> <category scheme='http://schemas.google.com/g/2005#kind' term='http://schemas.google.com/acl/2007#accessRule'/> <gAcl:role value='writer'/> <gAcl:scope type='user' value='new_writer@example.com'/> </entry> EOF # Regex the document id out from the full <atom:id>. # http://docs.google.com/feeds/documents/private/full/document%3Adfrk14g25fdsdwf -> document%3Adfrk14g25fdsdwf doc_id = entry.elements['id'].text[/full\/(.*%3[aA].*)$/, 1] response = client.post("http://docs.google.com/feeds/acl/private/full/#{doc_id}", acl_entry)
PUT (cập nhật dữ liệu)
Để cập nhật dữ liệu trên máy chủ, hãy sử dụng phương thức put()
của ứng dụng. Ví dụ sau đây sẽ cập nhật tiêu đề của một tài liệu.
Thao tác này giả định rằng bạn có một nguồn cấp dữ liệu từ một truy vấn trước đó.
entry = feed.elements['entry'] # first <atom:entry> # Update the document's title entry.elements['title'].text = 'Updated title' entry.add_namespace('http://www.w3.org/2005/Atom') entry.add_namespace('gd','http://schemas.google.com/g/2005') edit_uri = entry.elements["link[@rel='edit']"].attributes['href'] response = client.put(edit_uri, entry.to_s)
DELETE
Để xoá một <atom:entry> hoặc dữ liệu khác khỏi máy chủ, hãy sử dụng phương thức delete()
.
Ví dụ sau đây sẽ xoá một tài liệu. Đoạn mã này giả định rằng bạn có một mục nhập tài liệu từ một truy vấn trước đó.
entry = feed.elements['entry'] # first <atom:entry> edit_uri = entry.elements["link[@rel='edit']"].attributes['href'] client.headers['If-Match'] = entry.attribute('etag').value # make sure we don't nuke another client's updates client.delete(edit_uri)
Tạo ứng dụng Rails mới
Thông thường, bài tập đầu tiên trong việc tạo một ứng dụng Rails mới là chạy trình tạo giàn giáo để tạo các tệp MVC.
Sau đó, hãy chạy rake db:migrate
để thiết lập các bảng cơ sở dữ liệu. Tuy nhiên, vì ứng dụng của chúng ta sẽ truy vấn Google Documents List API để lấy dữ liệu, nên chúng ta không cần nhiều đến các cơ sở dữ liệu hoặc cấu trúc chung. Thay vào đó, hãy tạo một ứng dụng mới và bộ điều khiển đơn giản:
rails doclist cd doclist ruby script/generate controller doclist
và thực hiện các thay đổi sau đối với config/environment.rb
:
config.frameworks -= [ :active_record, :active_resource, :action_mailer ] config.gem 'gdata', :lib => 'gdata'
Dòng đầu tiên huỷ liên kết ActiveRecord
khỏi ứng dụng.
Dòng thứ hai tải gem gdata
khi khởi động.
Cuối cùng, tôi chọn kết nối tuyến đường mặc định ("/
") với thao tác documents
trong DoclistController
.
Thêm dòng này vào config/routes.rb
:
map.root :controller => 'doclist', :action => 'all'
Khởi động bộ điều khiển
Vì chúng ta không tạo giàn giáo, hãy thêm một thao tác có tên là "all
" vào DoclistController
trong app/controllers/doclist_controller.rb
theo cách thủ công.
class DoclistController < ApplicationController def all @foo = 'I pity the foo!' end end
và tạo all.html.erb
trong app/views/doclist/
:
<%= @foo %>
Khởi động máy chủ web và bắt đầu phát triển
Giờ đây, bạn có thể bắt đầu máy chủ web mặc định bằng cách gọi ruby script/server
.
Nếu mọi thứ đều ổn, việc trỏ trình duyệt đến http://localhost:3000/
sẽ hiển thị "I pity the foo!
".
Lưu ý: Đừng quên xoá hoặc đổi tên public/index.html
.
Sau khi mọi thứ hoạt động, hãy xem DoclistController
và ApplicationController
cuối cùng của tôi để biết nội dung chính của dự án Trình quản lý danh sách tài liệu. Bạn cũng nên xem ContactsController
. Lớp này xử lý các lệnh gọi đến API Danh bạ Google.
Kết luận
Phần khó nhất khi tạo ứng dụng Google Data Rails là định cấu hình Rails! Tuy nhiên, việc triển khai ứng dụng của bạn cũng quan trọng không kém. Vì vậy, bạn nên dùng mod_rails cho Apache. Bạn có thể dễ dàng thiết lập, cài đặt và chạy. Bạn sẽ có thể sử dụng ngay lập tức!
Tài nguyên
- Danh sách các API dữ liệu của Google
- Trang dự án Thư viện tiện ích Google Data Ruby
- Bài viết: Sử dụng Ruby với Google Data API
- Tải Ruby xuống
- Tải RubyGems và Rails xuống
Phụ lục
Ví dụ
DocList Manager là một mẫu Ruby on Rails đầy đủ minh hoạ các chủ đề được thảo luận trong bài viết này. Bạn có thể xem toàn bộ mã nguồn trên trang lưu trữ dự án.