The Golden Middle Path - a blog by Amit K Mathur

How to create embeddable widgets with Rails

Sometime you have to allow embeddable widgets or badges with your application. Just like Youtube allows you to embed videos or many social networking sites allow embedding badges or buttons with some dynamic information on them.

Embeddable widgets can be constructed using Flash or Javascript. Here we will create an embeddable Javascript widget and demonstrate how to do so in Rails.

Let’s say we are developing a project which allows you to maintain a database of dinosaurs. You can create profiles for various dinosaurs with their name, description and other details. Now, it will be cool if you allowed your users to embed their favourite dinosaur on their blog. They could just add a small script like this in their blog where ever they want the widget to appear:

<script src="http://example.com/dianosaurs/346.js" type="text/javascript"></script>

We will show how to build just such a widget into your Rails project.

Firstly, let’s start a fresh rails project. It should have Dinosaurs with some profile data, images and whatever else you fancy:

$ rails new dino_app
$ cd dino_app
$ rake db:create
$ rails server
$ rails generate scaffold dianosaur name:string genus:string description:text period:string 
$ rake db:migrate

Open /dianosaurs in your browser and ddd a few of your favourite dianos.

Next, we will create a embed script so that users can embed any one dinosaur data on their site. There are two ways of implementing it. One is by injecting your HTML content directly into the site and the other is to use an iframe. You can use either one based on what suits your needs. We describe both techniques below:

Load html content inline

 # File: app/controller/dianosaurs_controller.rb
def show
  @dianosaur = Dianosaur.find(params[:id])
end
  1. File: show.js.erb
    document.write("<%= escape_javascript(render(:partial => “embed”, :locals => {:dianosaur => @dianosaur})).html_safe) %>");
  1. File: _embed.html.erb
  2. This file contains whatever CSS, JS and HTML you want embedded
  3. remember that there is no layout since you are embedding on a third party
  4. site and the CSS needs to be written carefully

<%= dianosaur.name %>

<%= dianosaur.genus %>

<%= dianosaur.description %>

The CSS needs to be written in such a way that the target site’s CSS does not interfere with it and changes the look. Common techniques for that are to heavily use !important tag or to write style for each and every element, since you cannot leave anything to be influenced by parent’s style (in this case, you don’t want the stylesheet to cascade).

Now you can embed the diano widget on a different site using the following script:

<script src="http://localhost:3000/dianosaurs/1.js" type="text/javascript"></script>

Here are some tips for more advanced uses:

  • If you want to include jQuery in the third-party page. You can add this to the top of show.js.erb
<%# optional step: include jQuery on the target page if its not included %>
if(typeof(jQuery) == 'undefined'){
  document.write("<script type='text/javascript' src='http://ajax.googleapis.com/ajax/libs/jquery/1.4/jquery.min.js'></script>");
}
  • Separate CSS and JS in a separate file instead of inlining them. Add the following at the top of _embed.html.erb
<link rel="stylesheet" type="text/css" href="<%= File.join(root_url, 'stylesheets', 'diano_widget.css') %>"/>
<script src="<%= File.join(root_url, 'javascripts', 'diano_widget.js') %>" type="text/javascript"></script>

Insert an iframe on the target site, which can load the contents automatically

# File: show.js.erb
document.write("<%= escape_javascript(content_tag(:iframe, '', :src => widget_dianosour_url(@dianosaur))).html_safe) %>");
  1. File: routes.rb
    resources :dianosaurs do
    member do
    get :widget
    end
    end
  1. File: dianosours_controller.rb
    def widget
    @dianosaur = Dianosaur.find(params[:id])
    end
  1. File: widget.html.erb

    <%= @dianosaur.name >


    <= @dianosaur.genus %>

<%= @dianosaur.description %>

There are certain advantage of using an iframe:

  • None of the javascript or css will interfere with the target website.
  • No javascript cross domain issue. You can make ajax calls to your application for periodically updating content.

Also, here are some disadvantages:

  • Width and height of the iframe has to be fixed. It cannot auto adjust based on the content in iframe.
  • To load the contents of the widget, browser should make atleast two requests to the application. One request to load show.js.erb with iframe tag and another request to load iframe content from the URL specified in the src atribute of the iframe.

References:

  • http://www.eduvoyage.com/2008/8/3/widget-with-rails
  • http://www.igvita.com/2007/06/05/creating-javascript-widgets-in-rails/
  • http://emphaticsolutions.com/2011/01/21/functional-widgets-with-rails-javascript-jsonp.html
  • http://drnicwilliams.com/2006/11/21/diy-widgets/
Share:

Post a comment


(Formatting help)