Skip to content

Instantly share code, notes, and snippets.

@samleb
Created November 22, 2012 13:51
Show Gist options
  • Select an option

  • Save samleb/4131271 to your computer and use it in GitHub Desktop.

Select an option

Save samleb/4131271 to your computer and use it in GitHub Desktop.
Ruby snippet to get Facebook Like in batches
class Film < ActiveRecord::Base
class << self
def compute_facebook_likes
fb = FacebookLike.new(AppConfig.facebook.access_token)
find_in_batches(:select => 'id, permalink', :batch_size => fb.batch_size) do |group|
urls = group.map { |f| film_url(f) }
likes = fb.request_likes_for_urls(urls)
update_facebook_likes(group, likes)
sleep 0.2
end
end
end
# …
end
require 'uri'
class FacebookLike
autoload :Net, 'net/https'
autoload :CGI, 'cgi'
GRAPH_URL = URI.parse("https://graph.facebook.com/").freeze
FQL_QUERY_URL = "method/fql.query?query=".freeze
FQL_QUERY_FORMAT = %{SELECT total_count FROM link_stat WHERE url="%s"}.freeze
BATCH_SIZE = 50
class GraphException < RuntimeError; end
def self.request_likes_for_urls(access_token, urls)
new(access_token).request_likes_for_urls(urls)
end
def initialize(access_token)
@token = access_token
@http = create_http
end
def batch_size
BATCH_SIZE
end
def request_likes_for_urls(urls)
urls = Array(urls)
check_batch_size!(urls.size)
urls.map! { |url| fql_query_url(url) }
response = @http.request(create_request(urls))
response = parse_json(response.body)
check_batch_response!(response)
parse_batch_response(response)
end
protected
def create_http
http = Net::HTTP.new(GRAPH_URL.host, GRAPH_URL.port)
http.use_ssl = true
# FIXME: try removing this as we _should_ be verifying TLS certificate
# and the default behavior is not VERIFY_NONE anymore since 1.9
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
http
end
def create_request(urls)
request = Net::HTTP::Post.new(GRAPH_URL.request_uri)
request.form_data = {
:access_token => @token,
:batch => json_batch(urls)
}
request
end
def fql_query_url(url)
fql_query = FQL_QUERY_FORMAT % url
FQL_QUERY_URL + CGI.escape(fql_query)
end
def json_batch(urls)
urls.map do |url|
{"method" => "GET", "relative_url" => url}
end.to_json
end
def check_batch_size!(size)
if size > batch_size
raise ArgumentError, "Too many URLs for batch request: #{size} (limit #{batch_size})"
end
end
def check_batch_response!(response)
unless Array === response
error = response["error"]
raise GraphException, "#{error["message"]} (#{error["type"]})"
end
end
def parse_batch_response(batch)
batch.map do |response|
next unless response["code"] == 200
body = parse_json(response["body"])
next unless Array === body # body := {"error_msg": "Service temporarly unavailable"}
body[0]["total_count"] # body := [{"total_count": 1234}]
end
end
def parse_json(string)
ActiveSupport::JSON.decode(string)
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment