I’m quite busy recently, and as result I write posts on my blogs with smaller frequency as I usually did… But there are few interesting topics I want to write about. First – RFacebook and photos upload.
I’m using RFacebook gem to handle calls to Facebook API. But recently I found out, that probably there is no way to upload photos to Facebook with RFacebook. The reason is that API call is special case and as far as I know, there is no code for that in RFacebook.
So we need to extend RFacebook by ourself. Problem with facebook.photos.upload
is that need to be multi-part encoded post, that means MIME encoding. Since this is one way post, we don’t need any specialized library to handle MIME thus we will prepare own code. To make HTTP request Net::HTTP Ruby library is obvious choice, however it does not support multiparts.
First – Google, and I found this post describing how to make multiparts with Net::HTTP.
Next we need to extend RFacebook::FacebookWebSession
providing photos_upload
method. RFacebook uses method_missing to handle calls to API, providing own method photos_upload
will skip default processing flow:
module RFacebook class FacebookWebSession def photos_upload(params = {}) params = (params || {}).dup params[:method] = "facebook.photos.upload" params[:api_key] = FACEBOOK["key"] params[:v] = API_VERSION params[:session_key] = session_key params[:call_id] = Time.now.to_f.to_s file = params.delete :file params[:sig] = signature(params) boundary = 'some_long_and_random_string_which_wont_show_in_data_stream' params_as_arr = [] params.each {|k,v| params_as_arr << text_to_multipart(k,v)} params_as_arr << file_to_multipart('filename', 'somefile', 'image/jpg', file) qry = params_as_arr.collect {|p| '--' + boundary + "\r\n" + p }.join('') + "--" + boundary + "--\r\n" handle_xml_response( Net::HTTP.start(API_HOST).post2( API_PATH_REST, qry, "Content-type" => "multipart/form-data; boundary=" + boundary).response.body.to_s ) end end private def text_to_multipart(key,value) return "Content-Disposition: form-data; name=\"#{key.to_s}\"\r\n" + "\r\n" + "#{value}\r\n" end def file_to_multipart(key,filename,mime_type,content) return "Content-Disposition: form-data; name=\"#{key.to_s}\"; filename=\"#{CGI::escape(filename)}\"\r\n" + "Content-Transfer-Encoding: binary\r\n" + "Content-Type: #{mime_type}\r\n" + "\r\n" + "#{content}\r\n" end end
Now assuming that fbsession
is valid Facebook session we use it providing :file
with raw data and :caption
for description to Facebook:
fbsession.photos_upload :file => File.read("SOME_PATH_TO_FILE.jpg"), :caption => 'some caption'
As You can see this is very ‘rough’ solution, just to give You idea where to head next (error checking, handle other MIME types than image/jpeg, etc).
Please give me You thoughts on that code – if there will be some response I will feel obligated to prepare some more quality code to submit it as patch to RFacebook :)))
Hi,
I am trying this code like this. but I am getting an error
“can’t dup Symbol
RAILS_ROOT: E:/Rails2.2/integrateSNS
Application Trace | Framework Trace | Full Trace
E:/ruby/lib/ruby/gems/1.8/gems/rfacebook-0.9.8/lib/facebook_session.rb:177:in `dup’
E:/ruby/lib/ruby/gems/1.8/gems/rfacebook-0.9.8/lib/facebook_session.rb:177:in `remote_call’
E:/ruby/lib/ruby/gems/1.8/gems/rfacebook-0.9.8/lib/facebook_session.rb:164:in `method_missing’
E:/ruby/lib/ruby/gems/1.8/gems/rfacebook-0.9.8/lib/facebook_web_session.rb:138:in `photos_upload’
E:/ruby/lib/ruby/gems/1.8/gems/rfacebook-0.9.8/lib/facebook_web_session.rb:135:in `each’
E:/ruby/lib/ruby/gems/1.8/gems/rfacebook-0.9.8/lib/facebook_web_session.rb:135:in `photos_uploa
”
My code is as follows:
require “facebook_session”
module RFacebook
class FacebookWebSession auth_token})
unless result.nil?
@session_user_id = result.at(“uid”).inner_html
@session_key = result.at(“session_key”).inner_html
@session_expires = result.at(“expires”).inner_html
end
end
# Sets the session key directly (for example, if you have an infinite session)
#
# key:: the session key to use
def activate_with_previous_session(key, uid=nil, expires=nil)
# set the expiration
@session_expires = expires
# set the session key
@session_key = key
# determine the current user’s id
if uid
@session_user_id = uid
else
result = remote_call(“users.getLoggedInUser”)
@session_user_id = result.at(“users_getLoggedInUser_response”).inner_html
end
end
# returns true if this session is completely ready to be used and make API calls
def ready?
return (@session_key != nil and !expired?)
end
# Used for signing a set of parameters in the way that Facebook
# specifies:
#
# params:: a Hash containing the parameters to sign
def signature(params)
# always sign the parameters with the API secret
return signature_helper(params, @api_secret)
end
def photos_upload(params = {})
params = (params || {}).dup
params[:method] = “facebook.photos.upload”
params[:api_key] = FACEBOOK[“key”]
params[:v] = API_VERSION
params[:session_key] = session_key
params[:call_id] = Time.now.to_f.to_s
file = params.delete :file
params[:sig] = signature(params)
boundary = ‘some_long_and_random_string_which_wont_show_in_data_stream’
params_as_arr = []
p “on 31 line”
p params
params.each {|k,v|
p “<<<<<<<<<<<<<<<<”
p “text_to_multipart(k,v)”
p text_to_multipart(k,v)
params_as_arr << text_to_multipart(k,v)}
params_as_arr < “multipart/form-data; boundary=” + boundary).response.body.to_s
)
end
end
def text_to_multipart(key,value)
p “I aM IN”
p key
p value
return “Content-Disposition: form-data; name=\”#{key.to_s}\”\r\n” +
“\r\n” +
“#{value}\r\n”
end
def file_to_multipart(key,filename,mime_type,content)
return “Content-Disposition: form-data; name=\”#{key.to_s}\”; filename=\”#{CGI::escape(filename)}\”\r\n” +
“Content-Transfer-Encoding: binary\r\n” +
“Content-Type: #{mime_type}\r\n” +
“\r\n” +
“#{content}\r\n”
end
end
I am not able to understand what is happening?
Can you please tell me what is wrong?
Hi
I used this code and its working for me.
Thanks a lot.
I tried same code with minor changes for video but getting stuck with RemoteStandardError.
can any one know how to upload video through RFacebook.
Hi!
I’m glad You found this useful. However I do not work with facebook aps anymore and I can not help You with uploading video using RFacebook.