ActiveResource and YouTube
This article is about consuming YouTube API in your Ruby/Rails project using ActiveResource. Moreover, this article is an example of how to extend ActiveResource to consume non rest-style API.
Benefits of using our extension to ActiveResource :
- ActiveResource provides a ActiveRecord style interface.
- You can modify our extension according to your interface requirement.
- No not need to use and rely on Ruby library for YouTube REST API.
YouTube references
http://code.google.com/apis/youtube/developers_guide_protocol.html
http://code.google.com/apis/youtube/reference.html
http://code.google.com/apis/youtube/reference.html
Note : The extension is using ActiveResource 2.0.2
ActiveResource extension
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 |
require 'rubygems' require 'activeresource' class ActiveYouTube < ActiveResource::Base class << self ## Remove format from the url. def element_path(id, prefix_options = {}, query_options = nil) prefix_options, query_options = split_options(prefix_options) if query_options.nil? "#{prefix(prefix_options)}#{collection_name}/#{id}#{query_string(query_options)}" end ## Remove format from the url. def collection_path(prefix_options = {}, query_options = nil) prefix_options, query_options = split_options(prefix_options) if query_options.nil? "#{prefix(prefix_options)}#{collection_name}#{query_string(query_options)}" end ## For a collection call, ActiveResource formatting is not ## compliant with YouTube's output. def instantiate_collection(collection, prefix_options = {}) unless collection.kind_of? Array [instantiate_record(collection, prefix_options)] else collection.collect! { |record| instantiate_record(record, prefix_options) } end end ## To convert output into proper standard. ## If single element is present in output then entry is not an array. ## So this method will ensure entry is always an array. alias :old_find :find def find(*args) output=old_find(*args) if output.respond_to?:entry and !(output.entry.kind_of? Array) output.entry=[output.entry] end output end ## When using ActiveResource::CustomMethods, ActiveResource first tries to retrieve the id using find() ## and then makes a get() call using that id. ## But, youtube returns the url of this item as id, which we don't want. This method overrides the behavior. ## Example: comments = Video.find_custom("ZTUVgYoeN_o").get(:comments) def find_custom(arg) object = self.new object.id = arg object end ## Following method from ActiveResource::CustomMethods extends the capabilities of activeresource for non-standard urls ;-) ## The objects returned from this method are not automatically converted into ActiveResource instances - they are ordinary Hashes. ## Modifications below ensures that you get ActiveResource instances. def get(method_name, options = {}) object_array = connection.get(custom_method_collection_url(method_name, options), headers) if object_array.class.to_s=="Array" object_array.collect! {|record| self.class.new.load(record)} else self.class.new.load(object_array) end end end ## Instance Methods: (modifying the ActiveRecord::CustomMethods). ## This modification is same as defined in above method def get(method_name, options = {}) self.class.new.load(connection.get(custom_method_element_url(method_name, options), self.class.headers)) end ## Modifying the url formation to make it Youtube API complaint def custom_method_element_url(method_name, options = {}) "#{self.class.prefix(prefix_options)}#{self.class.collection_name}/#{id}/" + "#{method_name}#{self.class.send!(:query_string, options)}" end end > |
Points to keep in mind
- When using the ActiveResource::CustomMethods (get/post) make sure you are using "find_custom" and not "find"
- Disable the logging of ActiveResource, since the following line leads to exception if logger is enabled.
1 2 3 |
## line 111, connection.rb logger.info "--> #{result.code} #{result.message} (#{result.body ? result.body : 0}b %.2fs)" % time if logger |
Example usage
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 |
#### Create classes for YouTube resources. class Video < ActiveYouTube self.site = "http://gdata.youtube.com/feeds/api" ## To search by categories and tags def self.search_by_tags (*options) from_urls = [] if options.last.is_a? Hash excludes = options.slice!(options.length-1) if excludes[:exclude].kind_of? Array from_urls << excludes[:exclude].map{|keyword| "-"+keyword}.join("/") else from_urls << "-"+excludes[:exclude] end end from_urls << options.find_all{|keyword| keyword =~ /^[a-z]/}.join("/") from_urls << options.find_all{|category| category =~ /^[A-Z]/}.join("%7C") from_urls.delete_if {|x| x.empty?} self.find(:all,:from=>"/feeds/api/videos/-/"+from_urls.reverse.join("/")) end end class User < ActiveYouTube self.site = "http://gdata.youtube.com/feeds/api" end class Standardfeed < ActiveYouTube self.site = "http://gdata.youtube.com/feeds/api" end class Playlist < ActiveYouTube self.site = "http://gdata.youtube.com/feeds/api" end ##### Examples ####### #### VIDEO ## search for videos search = Video.find(:first, :params => {:vq => 'ruby', :"max-results" => '5'}) puts search.entry.length ## video information of id = ZTUVgYoeN_o vid = Video.find("ZTUVgYoeN_o") puts vid.group.content[0].url ## video comments comments = Video.find_custom("ZTUVgYoeN_o").get(:comments) puts comments.entry[0].link[2].href ## searching with category/tags results = Video.search_by_tags("Comedy") puts results[0].entry[0].title # more examples: # Video.search_by_tags("Comedy", "dog") # Video.search_by_tags("News","Sports","football", :exclude=>["Comedy","soccer"]) # Video.search_by_tags("News","Sports","football", :exclude=>"soccer") #### STANDARDFEED ## retrieving standard feeds most_viewed = Standardfeed.find(:most_viewed, :params => {:time => 'today'}) puts most_viewed.entry[0].group.content[0].url #### USER ## user's profile - guthrie user_profile = User.find("guthrie") puts user_profile.link[1].href ## user's playlist - john user_playlist = User.find_custom("john").get(:playlists) puts user_playlist.link[1].href ## user's upload or favorites rick_video = User.find_custom("rick").get(:uploads) puts rick_video.entry[0].group.content[0].url ## user's subscription user_subscriptions = User.find_custom("guthrie").get(:subscriptions) puts user_subscriptions.to_yaml #### PLAYLIST ## get playlist - multiple elements in playlist playlist = Playlist.find("EBF5D6DC4589D7B7") puts playlist.entry[0].group.content[0].url ## get playlist - single element in playlist playlist = Playlist.find("45C563323B344971") puts playlist.entry[0].group.content[0].url >>>> |


Recent comments
1 year 23 weeks ago
1 year 23 weeks ago
1 year 25 weeks ago
1 year 27 weeks ago
1 year 42 weeks ago
1 year 45 weeks ago
1 year 45 weeks ago
1 year 45 weeks ago
1 year 46 weeks ago
1 year 48 weeks ago