├── .gitignore ├── Gemfile ├── LICENSE ├── README.markdown ├── Rakefile ├── acts_as_opengraph.gemspec ├── lib ├── acts_as_opengraph.rb └── acts_as_opengraph │ ├── active_record │ └── acts │ │ └── opengraph.rb │ ├── helper │ └── acts_as_opengraph_helper.rb │ ├── mongoid │ └── acts │ │ └── opengraph.rb │ └── version.rb └── test ├── opengraph_test.rb └── test_helper.rb /.gitignore: -------------------------------------------------------------------------------- 1 | pkg/* 2 | *.gem 3 | .bundle 4 | doc/* 5 | Gemfile.lock 6 | .yardoc 7 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source "http://rubygems.org" 2 | 3 | # Specify your gem's dependencies in acts_as_opengraph.gemspec 4 | gemspec 5 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2011 Ruben Ascencio 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. -------------------------------------------------------------------------------- /README.markdown: -------------------------------------------------------------------------------- 1 | # acts\_as\_opengraph 2 | 3 | **ActiveRecord** / **Mongoid** extension that turns your models into [facebook opengraph](http://developers.facebook.com/docs/opengraph/) objects. 4 | 5 | ## Installation 6 | 7 | gem install acts_as_opengraph 8 | 9 | Now just add the gem dependency in your projects configuration. 10 | 11 | ## Usage 12 | 13 | ### Adding acts\_as\_opengraph for ActiveRecord 14 | 15 | # app/models/movie.rb 16 | class Movie < ActiveRecord::Base 17 | acts_as_opengraph 18 | end 19 | 20 | ### Adding acts\_as\_opengraph for Mongoid 21 | 22 | # app/models/movie.rb 23 | class Movie 24 | include Mongoid::Acts::Opengraph 25 | 26 | acts_as_opengraph # This should be placed after model fields declaration 27 | end 28 | 29 | ### Generating the opengraph meta tags 30 | 31 | # app/views/layouts/application.html.erb 32 |
33 | <%= yield :opengraph_meta_tags %> 34 | 35 | 36 | # app/views/movies/show.html.erb 37 | <% content_for :opengraph_meta_tags, opengraph_meta_tags_for(@movie) %> 38 | 39 | ### Displaying the Like Button 40 | # app/views/movies/show.html.erb 41 | <%= like_button_for @movie %> 42 | 43 | \* Notice that the Like Button will retrieve the required `href` attribute by calling `@movie.opengraph_url`. Read below for more options. 44 | 45 | 46 | ## Options 47 | 48 | ### Database columns 49 | 50 | Even when the names of these columns can be changed with configuration, `acts_as_opengraph` tries to guess these names by checking for the existence of common names. Chances are that your model already has some of the opengraph defined properties. 51 | 52 | This is the list of supported opengraph protocol properties and their possible column names (in precedence order): 53 | 54 | * __title__ - og\_title, title, name 55 | * __type__ - og\_type, kind, category 56 | * __image__ - og\_image, image, photo, picture, thumb, thumbnail 57 | * __url__ - og\_url, url, uri, link 58 | * __description__ - og\_description, description, summary 59 | * __site\_name__ - og\_site, website, web 60 | * __latitude__ - og\_latitude, latitude 61 | * __longitude__ - og\_longitude, longitude 62 | * __street\_address__ - og\_street\_address, street_address, address, street 63 | * __locality__ - og\_locality, locality 64 | * __region__ - og\_region, region 65 | * __postal\_code__ - og\_postal\_code, postal\_code, zip\_code, zip 66 | * __country\_name__ - og\_country_name, country\_name, country 67 | * __email__ - og\_email, email, mail 68 | * __phone\_number__ - og\_phone\_number, phone\_number, phone 69 | * __fax\_number__ - og\_fax\_number, fax\_number, fax 70 | 71 | ### Using a different column name 72 | 73 | If you need to use a different column then use the __columns__ option. For example, if you store the url of your movies using the `imdb_url` column in your movies table, then do this: 74 | 75 | # app/models/movie.rb 76 | acts_as_opengraph :columns => { :url => :imdb_url } 77 | 78 | ### What about using a custom method? 79 | 80 | If you wish to use a custom method for some opengraph field, then all you need to do is to define a method with the prefix `opengraph_`. 81 | For example, if you are using [Paperclip](https://github.com/thoughtbot/paperclip) for your image attachments, you can do this: 82 | 83 | # app/models/movie.rb 84 | class Movie < ActiveRecord::Base 85 | 86 | has_attached_file :picture, :styles => { :small => "160x130>"} 87 | 88 | acts_as_opengraph 89 | 90 | def opengraph_image 91 | picture.url(:small) 92 | end 93 | 94 | end 95 | 96 | ### Default values 97 | 98 | Use the __values__ option for passing default opengraph values. For our Movie example we can specify that all of our records are movies by doing this: 99 | 100 | acts_as_opengraph :values => { :type => "movie" } 101 | 102 | \* Notice that `acts_as_opengraph` only accepts an options hash argument, so if you want to combine default values and column names you'd do this: 103 | 104 | acts_as_opengraph :columns => { :url => :imdb_url, :email => :contact }, 105 | :values => { :type => "movie", :site_name => "http://example.com" } 106 | 107 | ## Like Button options 108 | 109 | Along with the object for which you want to display the Like button, you can pass an options hash to configure its appearance: 110 | 111 | # app/views/layouts/application.html.erb 112 | <%= like_button_for @movie, :layout => :box_count, :show_faces => true %> 113 | 114 | ### Using url helpers 115 | 116 | By default, `acts_as_opengraph` will try to retrieve your object's url by calling `opengraph_url` on it. You could override it by defining a custom method, like this: 117 | 118 | # app/models/movie.rb 119 | def opengraph_url 120 | "http://example.com/movies/#{self.id}" 121 | end 122 | 123 | But that's not the Rails way, so instead of doing that, you can pass an `href` option from your views, which means you can easily take advantage of the url helpers, like this: 124 | 125 | # app/views/movies/show.html.erb 126 | <%= like_button_for @movie, :href => movie_path(@movie) %> 127 | 128 | See the complete list of allowed attributes and options [here](http://developers.facebook.com/docs/reference/plugins/like/). 129 | 130 | ### Using the XFBML version 131 | 132 | The XFBML version is more versatile, but requires use of the JavaScript SDK. 133 | 134 | # app/views/movies/show.html.erb 135 | 136 | # You can use the following helper method to load the JavaScript SDK 137 | <%= fb_javascript_include_tag YOUR_APP_ID %> 138 | 139 | # Now you can pass the :xfbml option to the like button helper 140 | <%= like_button_for @movie, :xfbml => true %> 141 | 142 | ## Note on Patches/Pull Requests 143 | 144 | * Fork the project. 145 | * Make your feature addition or bug fix. 146 | * Add tests for it. This is important so I don’t break it in a future version unintentionally. 147 | * Send me a pull request. Bonus points for topic branches. 148 | 149 | ## Contributors 150 | 151 | * [Eric Hill](https://github.com/rhizome) - Updated the meta attribute to reflect the current OG spec 152 | * [Timo Göllner](https://github.com/TeaMoe) - Integrated Like Button via facebook XFBML tag 153 | * [Alex Kravets](https://github.com/AlexKravets) - Mongoid Support 154 | 155 | ## Copyright 156 | 157 | Copyright © 2011 Ruben Ascencio, released under the MIT license 158 | 159 | 160 | 161 | 162 | 163 | 164 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | require 'bundler' 2 | Bundler::GemHelper.install_tasks 3 | 4 | require 'rake/testtask' 5 | Rake::TestTask.new do |t| 6 | t.libs << "test" 7 | t.test_files = FileList['test/**/*_test.rb'] 8 | t.verbose = true 9 | end -------------------------------------------------------------------------------- /acts_as_opengraph.gemspec: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | $:.push File.expand_path("../lib", __FILE__) 3 | require "acts_as_opengraph/version" 4 | 5 | Gem::Specification.new do |s| 6 | s.name = "acts_as_opengraph" 7 | s.version = ActsAsOpengraph::VERSION 8 | s.platform = Gem::Platform::RUBY 9 | s.authors = ["Ruben Ascencio"] 10 | s.email = ["galateaweb@gmail.com"] 11 | s.homepage = "https://github.com/rubenrails/acts_as_opengraph" 12 | s.summary = %q{ActiveRecord extension that turns your models into graph objects} 13 | s.description = %q{ActiveRecord extension that turns your models into graph objects. Includes helper methods for adding tags and the Like Button to your views.} 14 | 15 | s.rubyforge_project = "acts_as_opengraph" 16 | 17 | s.add_development_dependency('sqlite3') 18 | s.add_development_dependency('rails') 19 | 20 | s.files = `git ls-files`.split("\n") 21 | s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n") 22 | s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) } 23 | s.require_paths = ["lib"] 24 | end 25 | -------------------------------------------------------------------------------- /lib/acts_as_opengraph.rb: -------------------------------------------------------------------------------- 1 | if defined? Mongoid 2 | require 'acts_as_opengraph/mongoid/acts/opengraph' 3 | end 4 | 5 | if defined? ActiveRecord::Base 6 | require File.join(File.dirname(__FILE__), 'acts_as_opengraph', 'active_record', 'acts', 'opengraph') 7 | ActiveRecord::Base.send :include, ActiveRecord::Acts::Opengraph 8 | end 9 | 10 | if defined? ActionView::Base 11 | require File.join(File.dirname(__FILE__), 'acts_as_opengraph', 'helper', 'acts_as_opengraph_helper') 12 | ActionView::Base.send :include, ActsAsOpengraphHelper 13 | end 14 | 15 | -------------------------------------------------------------------------------- /lib/acts_as_opengraph/active_record/acts/opengraph.rb: -------------------------------------------------------------------------------- 1 | module ActiveRecord 2 | module Acts 3 | module Opengraph 4 | 5 | def self.included(base) 6 | base.extend ActMethods 7 | end 8 | 9 | module ActMethods 10 | def acts_as_opengraph(options = {}) 11 | # don't allow multiple calls 12 | return if included_modules.include? InstanceMethods 13 | return unless table_exists? 14 | 15 | extend ClassMethods 16 | 17 | opengraph_atts = %w(title type image url description site_name latitude longitude street_address locality region postal_code country_name email phone_number fax_number) 18 | 19 | options[:columns] ||= {} 20 | options[:values] ||= {} 21 | 22 | opengraph_atts.each do |att_name| 23 | options[:columns]["#{att_name}".to_sym] ||= alternative_column_name_for("og_#{att_name}".to_sym) 24 | end 25 | 26 | class_attribute :opengraph_atts 27 | self.opengraph_atts = opengraph_atts 28 | 29 | class_attribute :options 30 | self.options = options 31 | 32 | opengraph_atts.each do |att_name| 33 | define_method "opengraph_#{att_name}" do 34 | return_value_or_default att_name.to_sym 35 | end 36 | end 37 | 38 | include InstanceMethods 39 | 40 | end 41 | 42 | end 43 | 44 | module ClassMethods 45 | 46 | private 47 | 48 | # Returns a list of possible column names for a given attribute. 49 | # 50 | # @param [Symbol] att_name An opengraph attribute name prefixed with 'og_', i.e. :og_title, :og_type, etc 51 | # @return [Array] A list of possible names for the given opengraph attribute 52 | def alternative_names_for(att_name) 53 | case att_name 54 | when :og_title then [:title, :name] 55 | when :og_type then [:kind, :category] 56 | when :og_image then [:image, :photo, :picture, :thumb, :thumbnail] 57 | when :og_url then [:url, :uri, :link] 58 | when :og_description then [:description, :summary] 59 | when :og_site_name then [:site, :website, :web] 60 | when :og_latitude then [:latitude] 61 | when :og_longitude then [:longitude] 62 | when :og_street_address then [:street_address, :address, :street] 63 | when :og_locality then [:locality] 64 | when :og_region then [:region] 65 | when :og_postal_code then [:postal_code, :zip_code, :zip] 66 | when :og_country_name then [:country_name, :country] 67 | when :og_email then [:email, :mail] 68 | when :og_phone_number then [:phone_number, :phone] 69 | when :og_fax_number then [:fax_number, :fax] 70 | else [] 71 | end 72 | end 73 | 74 | # Tries to guess the column name for the given attribute. If it can't find any column (or similar) then it will create a virtual attribute 75 | # for the object called: ATT_NAME_placeholder, so the object responds to that column. 76 | # 77 | # @param [Symbol] att_name An opengraph attribute name prefixed with 'og_', i.e. :og_title, :og_type, etc 78 | # @return [String] The final name (found or created) for the opengraph attribute 79 | def alternative_column_name_for(att_name) 80 | alt_names = alternative_names_for(att_name) 81 | columns_to_check = [att_name] + alt_names 82 | columns_to_check.each do |column_name| 83 | return column_name.to_sym if column_names.include?(column_name.to_s) 84 | end 85 | 86 | # Define placeholder method 87 | ph_method_name = "#{alt_names.first}_placeholder" 88 | define_method(ph_method_name) { "" } 89 | ph_method_name 90 | end 91 | 92 | end 93 | 94 | module InstanceMethods 95 | # Returns an array of hashes representing the opengraph attribute/values for the Object. 96 | # 97 | # @return [Array] List of hashes representing opengraph attribute/values 98 | # @example 99 | # @movie.opengraph_data #=> {name=> "og:title", :value => "The Rock"}, {:name => "og:type", :value=> "movie"} 100 | def opengraph_data 101 | data_list = opengraph_atts.map do |att_name| 102 | {:name => "og:#{att_name}", :value => self.send("opengraph_#{att_name}")} 103 | end 104 | data_list.delete_if{ |el| el[:value].blank? } 105 | end 106 | 107 | 108 | private 109 | 110 | def return_value_or_default(att_name) 111 | if options[:values].has_key?(att_name.to_sym) 112 | options[:values][att_name] 113 | else 114 | self.send options[:columns]["#{att_name}".to_sym] 115 | end 116 | end 117 | 118 | end 119 | 120 | end 121 | end 122 | end 123 | -------------------------------------------------------------------------------- /lib/acts_as_opengraph/helper/acts_as_opengraph_helper.rb: -------------------------------------------------------------------------------- 1 | module ActsAsOpengraphHelper 2 | NON_ESCAPED_ATTRIBUTES = %w(og:image og:url) 3 | # Generates the opengraph meta tags for your views 4 | # 5 | # @param [Object, #opengraph_data] obj An instance of your ActiveRecord model that responds to opengraph_data 6 | # @return [String] A set of meta tags describing your graph object based on the {http://ogp.me/ opengraph protocol} 7 | # @raise [ArgumentError] When you pass an instance of an object that doesn't responds to opengraph_data (maybe you forgot to add acts_as_opengraph in your model) 8 | # @example 9 | # opengraph_meta_tags_for(@movie) 10 | def opengraph_meta_tags_for(obj) 11 | raise(ArgumentError.new, "You need to call acts_as_opengraph on your #{obj.class} model") unless obj.respond_to?(:opengraph_data) 12 | tags = obj.opengraph_data.map do |att| 13 | att_name = att[:name] == "og:site_name" ? att[:name] : att[:name].dasherize 14 | if NON_ESCAPED_ATTRIBUTES.include? att_name 15 | %() 16 | else 17 | %() 18 | end 19 | end 20 | tags = tags.join("\n") 21 | tags.respond_to?(:html_safe) ? tags.html_safe : tags 22 | end 23 | 24 | # Displays the Facebook Like Button in your views. 25 | # 26 | # @param [Object, #opengraph_data] obj An instance of your ActiveRecord model that responds to opengraph_data 27 | # @param [Hash] options A Hash of {http://developers.facebook.com/docs/reference/plugins/like/ supported attributes}. Defaults to { :layout => :standard, :show_faces => false, :width => 450, :action => :like, :colorscheme => :light } 28 | # @return [String] An iFrame version of the Facebook Like Button 29 | # @raise [ArgumentError] When you pass an instance of an object that doesn't responds to opengraph_data (maybe you forgot to add acts_as_opengraph in your model) 30 | # @example 31 | # like_button_for(@movie) 32 | # like_button_for(@movie, :layout => :button_count, :display_faces => true) 33 | # @example Specifying href using rails helpers 34 | # like_button_for(@movie, :href => movie_url(@movie)) 35 | def like_button_for(obj, options = {}) 36 | raise(ArgumentError.new, "You need to call acts_as_opengraph on your #{obj.class} model") unless obj.respond_to?(:opengraph_data) 37 | href = options[:href] ? options[:href] : obj.opengraph_url 38 | return unless href.present? 39 | 40 | config = { :layout => :standard, :show_faces => false, :width => 450, :action => :like, :colorscheme => :light } 41 | config.update(options) if options.is_a?(Hash) 42 | 43 | o_layout = config[:layout].to_sym 44 | if o_layout == :standard 45 | config[:height] = config[:show_faces].to_s.to_sym == :true ? 80 : 35 46 | elsif o_layout == :button_count 47 | config[:height] = 21 48 | elsif o_layout == :box_count 49 | config[:height] = 65 50 | end 51 | config[:locale] ||= 'en_US' 52 | 53 | if config[:xfbml] 54 | unless @fb_sdk_included 55 | content_for :javascripts, fb_javascript_include_tag( config[:locale], config[:appid] ) 56 | end 57 | %(