Google Data on Rails

إريك بيدلمان، فريق Google Data APIs
فبراير 2009

مقدمة

"أين يمكنني العثور على Ruby في قائمة مكتبات البرامج للعملاء؟"

بفضل الإقبال الشديد من المطوّرين على استخدام Ruby on Rails (RoR) وشعبيتها الدائمة، تمكّن زميلي "جيف فيشر" من إنشاء مكتبة أدوات Ruby من أعماق "جبل الهلاك". يُرجى العِلم أنّها ليست مكتبة عملاء كاملة، ولكنّها تتعامل مع الأساسيات، مثل المصادقة ومعالجة XML الأساسية. يتطلّب ذلك أيضًا العمل مباشرةً مع خلاصة Atom باستخدام وحدة REXML وXPath.

الجمهور

هذه المقالة مخصّصة للمطوّرين المهتمين بالوصول إلى Google Data APIs باستخدام Ruby، وتحديدًا Ruby on Rails. يفترض هذا الدليل أنّ القارئ على دراية ببعض أساسيات لغة البرمجة Ruby وإطار عمل Rails لتطوير الويب. أركّز في معظم الأمثلة على واجهة برمجة التطبيقات لقائمة المستندات، ولكن يمكن تطبيق المفاهيم نفسها على أي من واجهات برمجة التطبيقات للبيانات.

البدء

المتطلبات

تثبيت مكتبة الأدوات المساعدة للغة Ruby في Google Data

للحصول على المكتبة، يمكنك إما تنزيل مصدر المكتبة مباشرةً من خدمة استضافة المشاريع أو تثبيت Gem:

sudo gem install gdata

ملاحظة: من الأفضل تشغيل gem list --local للتأكّد من تثبيت Gem بشكل صحيح.

المصادقة

ClientLogin

تسمح ClientLogin لتطبيقك بتسجيل دخول المستخدمين آليًا إلى حساباتهم على Google أو G Suite. بعد التحقّق من صحة بيانات اعتماد المستخدم، تصدر Google رمز مصادقة يمكن الرجوع إليه في طلبات واجهة برمجة التطبيقات اللاحقة. يظل الرمز المميّز صالحًا لمدة زمنية محددة، يحدّدها أي خدمة من خدمات Google تستخدمها. لأسباب أمنية ولتوفير أفضل تجربة للمستخدمين، يجب استخدام ClientLogin فقط عند تطوير تطبيقات مثبَّتة على أجهزة الكمبيوتر. بالنسبة إلى تطبيقات الويب، يُفضّل استخدام AuthSub أو OAuth.

تحتوي مكتبة Ruby على فئة عميل لكل واجهة من واجهات برمجة التطبيقات. على سبيل المثال، استخدِم مقتطف الرمز البرمجي التالي لتسجيل الدخول إلى [email protected] Documents List Data API:

client = GData::Client::DocList.new
client.clientlogin('[email protected]', 'pa$$word')

The YouTube Data API would be:

client = GData::Client::YouTube.new
client.clientlogin('[email protected]', 'pa$$word')

القائمة الكاملة لفئات الخدمات التي تم تنفيذها إذا لم تكن الخدمة تتضمّن فئة عميل، استخدِم الفئة GData::Client::Base. على سبيل المثال، يفرض الرمز التالي على المستخدمين تسجيل الدخول باستخدام حساب 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)

ملاحظة: تستخدم المكتبة تلقائيًا HOSTED_OR_GOOGLE لـ accountType. القيم المحتمَلة هي HOSTED_OR_GOOGLE أو HOSTED أو GOOGLE.

من سلبيات استخدام ClientLogin أنّه يمكن إرسال اختبارات CAPTCHA إلى تطبيقك عند تعذُّر محاولات تسجيل الدخول. في حال حدوث ذلك، يمكنك التعامل مع الخطأ من خلال استدعاء الطريقة clientlogin() مع مَعلماتها الإضافية: client.clientlogin(username, password, captcha_token, captcha_answer). يُرجى الرجوع إلى مستندات المصادقة للتطبيقات المثبَّتة الكاملة للحصول على مزيد من المعلومات حول التعامل مع اختبارات CAPTCHA.

AuthSub

إنشاء عنوان 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)

تنشئ مجموعة الرموز السابقة عنوان URL التالي في authsub_link:

https://www.google.com/accounts/AuthSubRequest?next=https%3A%2F%2F2.zoppoz.workers.dev%3A443%2Fhttp%2Fexample.com%2Fchange%2Fto%2Fyour%2Fapp&scope=https%3A%2F%2F2.zoppoz.workers.dev%3A443%2Fhttp%2Fwww.google.com%2Fcalendar%2Ffeeds%2F&session=1&secure=0

يمكنك أيضًا استخدام طريقة authsub_url لكائن العميل. لقد تم ضبط سمة authsub_scope تلقائية لكل فئة خدمة، لذا ليس عليك تحديد سمة خاصة بك.

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)

ينشئ مقطع الرمز البرمجي السابق عنوان URL التالي:

https://www.google.com/accounts/AuthSubRequest?next=https%3A%2F%2F2.zoppoz.workers.dev%3A443%2Fhttp%2Fexample.com%2Fchange%2Fto%2Fyour%2Fapp&scope=https%3A%2F%2F2.zoppoz.workers.dev%3A443%2Fhttp%2Fdocs.google.com%2Ffeeds%2F&session=1&secure=0&hd=example.com

ترقية رمز مميّز للاستخدام لمرّة واحدة إلى رمز مميّز للجلسة

ستعيد خدمة AuthSub توجيه المستخدم إلى http://example.com/change/to/your/app?token=SINGLE_USE_TOKEN بعد أن يمنح الإذن بالوصول إلى بياناته. يُرجى العِلم أنّ عنوان URL هو next_url الخاص بنا مع إضافة الرمز المميّز الذي يُستخدَم مرة واحدة كمعلَمة طلب بحث.

بعد ذلك، استبدِل الرمز المميز للاستخدام لمرة واحدة برمز مميز للجلسة صالح لفترة طويلة:

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 معها إلى حد كبير. الإضافة الوحيدة هي ضبط مفتاحك الخاص قبل ترقية الرمز المميّز:

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]

ملاحظة: لاستخدام الرموز المميزة الآمنة، احرص على ضبط secure=true عند طلب رمز مميز صالح للاستخدام مرة واحدة. راجِع إنشاء عنوان URL لطلب AuthSub أعلاه.

إدارة الرموز المميزة

توفّر خدمة AuthSub معالجَين إضافيَّين، هما AuthSubTokenInfo وAuthSubRevokeToken، لإدارة الرموز المميزة. تكون السمة AuthSubTokenInfo مفيدة للتحقّق من صلاحية الرمز المميّز. يمنح AuthSubRevokeToken المستخدمين خيار إيقاف إمكانية الوصول إلى بياناتهم. يجب أن يستخدم تطبيقك AuthSubRevokeToken كأفضل ممارسة. تتوافق كلتا الطريقتين مع مكتبة Ruby.

للاستعلام عن البيانات الوصفية لرمز مميّز، اتّبِع الخطوات التالية:

client.auth_handler.info

لإبطال رمز مميّز لجلسة، اتّبِع الخطوات التالية:

client.auth_handler.revoke

اطّلِع على مستندات مصادقة AuthSub لتطبيقات الويب الكاملة للحصول على التفاصيل الكاملة حول AuthSub.

OAuth

في وقت كتابة هذه المقالة، لم تتم إضافة بروتوكول OAuth إلى الوحدة GData::Auth.

يجب أن يكون استخدام بروتوكول OAuth في مكتبة الأدوات المساعدة أمرًا بسيطًا نسبيًا عند استخدام oauth-plugin في Rails أو oauth gem في Ruby. في كلتا الحالتين، عليك إنشاء عنصر GData::HTTP::Request وتمرير عنوان Authorization الذي تم إنشاؤه بواسطة كل مكتبة.

الوصول إلى الخلاصات

GET (جلب البيانات)

بعد إعداد عنصر العميل، استخدِم الطريقة get() للاستعلام عن خلاصة Google Data. يمكن استخدام XPath لاسترداد عناصر Atom معيّنة. في ما يلي مثال على استرداد مستندات 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 (إنشاء بيانات جديدة)

استخدِم طريقة post() الخاصة بالعميل لإنشاء بيانات جديدة على الخادم. سيضيف المثال التالي [email protected] كمساهم إلى المستند الذي يحمل رقم التعريف: 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='[email protected]'/>
</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 (تعديل البيانات)

لتعديل البيانات على الخادم، استخدِم طريقة put() الخاصة بالعميل. سيعدّل المثال التالي عنوان مستند. يفترض هذا الإجراء أنّ لديك خلاصة من طلب بحث سابق.

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)

حذف

لحذف <atom:entry> أو بيانات أخرى من الخادم، استخدِم طريقة delete(). سيؤدي المثال التالي إلى حذف مستند. يفترض الرمز أنّه لديك إدخال مستند من طلب بحث سابق.

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)

إنشاء تطبيق Rails جديد

عادةً ما يتضمّن التمرين الأول في إنشاء تطبيق Rails جديد تشغيل مولّدات التعليمات البرمجية لإنشاء ملفات MVC. بعد ذلك، يتم تشغيل rake db:migrate لإعداد جداول قاعدة البيانات. ومع ذلك، بما أنّ تطبيقنا سيطلب البيانات من واجهة برمجة التطبيقات الخاصة بقائمة مستندات Google، لن نحتاج إلى الكثير من عمليات الإنشاء أو قواعد البيانات العامة. بدلاً من ذلك، أنشِئ تطبيقًا جديدًا ووحدة تحكّم بسيطة:

rails doclist
cd doclist
ruby script/generate controller doclist

وأجرِ التغييرات التالية على config/environment.rb:

config.frameworks -= [ :active_record, :active_resource, :action_mailer ]
config.gem 'gdata', :lib => 'gdata'

يزيل السطر الأول ActiveRecord من التطبيق. يحمّل السطر الثاني الجوهرة gdata عند بدء التشغيل.

أخيرًا، اخترت ربط المسار التلقائي (‎'/') بالإجراء documents في DoclistController. أضِف هذا السطر إلى config/routes.rb:

map.root :controller => 'doclist', :action => 'all'

بدء استخدام وحدة تحكّم

بما أنّنا لم ننشئ بنية أساسية، أضِف يدويًا إجراءً باسم "all" إلى DoclistController في app/controllers/doclist_controller.rb.

class DoclistController < ApplicationController
  def all
    @foo = 'I pity the foo!'
  end
end

وإنشاء all.html.erb ضمن app/views/doclist/:

<%= @foo %>

تشغيل خادم الويب وبدء التطوير

من المفترض أن تتمكّن الآن من بدء تشغيل خادم الويب التلقائي عن طريق استدعاء ruby script/server. إذا كان كل شيء على ما يرام، سيؤدي توجيه المتصفح إلى http://localhost:3000/ إلى عرض I pity the foo!.

ملاحظة: لا تنسَ إزالة public/index.html أو إعادة تسميته.

بعد أن يصبح كل شيء جاهزًا، ألقِ نظرة على DoclistController وApplicationController النهائيين للحصول على التفاصيل الكاملة حول مشروع DocList Manager. عليك أيضًا الاطّلاع على ContactsController، الذي يتعامل مع طلبات البيانات من واجهة برمجة التطبيقات Google Contacts API.

الخاتمة

إنّ الجزء الأصعب من إنشاء تطبيق Google Data Rails هو ضبط Rails. مع ذلك، فإنّ الخطوة التالية في الأهمية هي نشر تطبيقك. لهذا السبب، ننصحك بشدة باستخدام mod_rails لنظام Apache. عملية الإعداد والتثبيت والتشغيل سهلة للغاية. ستتمكّن من استخدامها في وقت قصير جدًا.

الموارد

الملحق

أمثلة

DocList Manager هو نموذج كامل من Ruby on Rails يوضّح المواضيع التي تمت مناقشتها في هذه المقالة. يتوفّر رمز المصدر الكامل من خدمة استضافة المشاريع.