<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/atom10full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><feed xmlns="http://www.w3.org/2005/Atom" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" xml:lang="en-US">
  <title>QuarkRuby - Home</title>
  <id>tag:www.quarkruby.com,2009:mephisto/</id>
  <generator version="0.8.0" uri="http://mephistoblog.com">Mephisto Drax</generator>
  
  <link href="http://www.quarkruby.com/" rel="alternate" type="text/html" />
  <updated>2008-03-11T11:22:14Z</updated>
  <link rel="self" href="http://feeds.feedburner.com/Quarkruby" type="application/atom+xml" /><entry xml:base="http://www.quarkruby.com/">
    <author>
      <name>admin</name>
    </author>
    <id>tag:www.quarkruby.com,2008-03-11:1960</id>
    <published>2008-03-11T11:17:00Z</published>
    <updated>2008-03-11T11:22:14Z</updated>
    <category term="ruby" />
    <category term="tutorials" />
    <category term="activeresource" />
    <category term="api" />
    <link href="http://feedproxy.google.com/~r/Quarkruby/~3/l0cQdfyGI5A/consume-non-rails-style-rest-apis" rel="alternate" type="text/html" />
    <title>Consume non rails-style REST API's</title>
<summary type="html">&lt;p&gt;
ActiveResource is a great concept which consumes rails-style REST API but unfortunately most of the REST API's are not rails-style. This means that very frequently you will end up modifying ActiveResource to consume non rails-style REST API's. This article is about understanding ActiveResource and how to tweak/extend it to consume non rails-style REST API's. We will mainly concentrate on reading data i.e. the GET method.
&lt;/p&gt;

&lt;h2&gt;Table of Contents &lt;/h2&gt;
&lt;ol&gt;
   &lt;li&gt;&lt;a href="#intro"&gt;Introduction&lt;/a&gt;
   &lt;li&gt;&lt;a href="#consumerest"&gt;Consume non rails-style REST API&lt;/a&gt;
      &lt;ol&gt;
          &lt;li&gt;&lt;a href="#urlremote"&gt;Create URL for remote resources&lt;/a&gt;
          &lt;li&gt;&lt;a href="#getrequest"&gt;Make a GET request&lt;/a&gt;
          &lt;li&gt;&lt;a href="#customresponse"&gt;Handling (Custom) Response&lt;/a&gt;
          &lt;li&gt;&lt;a href="#parseresponse"&gt;Parse Response&lt;/a&gt;
          &lt;li&gt;&lt;a href="#createobject"&gt;Create ActiveResource object from parsed response&lt;/a&gt;
          &lt;li&gt;&lt;a href="#otherthings"&gt;Other things to keep in mind&lt;/a&gt;
      &lt;/ol&gt;
   &lt;li&gt;&lt;a href="#gettweaks"&gt;Custom HTTP GET method tweaks&lt;/a&gt;
     &lt;ol&gt;
     &lt;/ol&gt;
   &lt;li&gt;&lt;a href="#format"&gt;Data Format&lt;/a&gt;
&lt;/ol&gt;</summary><content type="html">
            &lt;p&gt;
ActiveResource is a great concept which consumes rails-style REST API but unfortunately most of the REST API's are not rails-style. This means that very frequently you will end up modifying ActiveResource to consume non rails-style REST API's. This article is about understanding ActiveResource and how to tweak/extend it to consume non rails-style REST API's. We will mainly concentrate on reading data i.e. the GET method.
&lt;/p&gt;

&lt;h2&gt;Table of Contents &lt;/h2&gt;
&lt;ol&gt;
   &lt;li&gt;&lt;a href="#intro"&gt;Introduction&lt;/a&gt;
   &lt;li&gt;&lt;a href="#consumerest"&gt;Consume non rails-style REST API&lt;/a&gt;
      &lt;ol&gt;
          &lt;li&gt;&lt;a href="#urlremote"&gt;Create URL for remote resources&lt;/a&gt;
          &lt;li&gt;&lt;a href="#getrequest"&gt;Make a GET request&lt;/a&gt;
          &lt;li&gt;&lt;a href="#customresponse"&gt;Handling (Custom) Response&lt;/a&gt;
          &lt;li&gt;&lt;a href="#parseresponse"&gt;Parse Response&lt;/a&gt;
          &lt;li&gt;&lt;a href="#createobject"&gt;Create ActiveResource object from parsed response&lt;/a&gt;
          &lt;li&gt;&lt;a href="#otherthings"&gt;Other things to keep in mind&lt;/a&gt;
      &lt;/ol&gt;
   &lt;li&gt;&lt;a href="#gettweaks"&gt;Custom HTTP GET method tweaks&lt;/a&gt;
     &lt;ol&gt;
     &lt;/ol&gt;
   &lt;li&gt;&lt;a href="#format"&gt;Data Format&lt;/a&gt;
&lt;/ol&gt;

&lt;br /&gt;

&lt;a&gt;&lt;/a&gt;
&lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;Let me recall the purpose of ActiveResource as stated in ActiveResource README :

&lt;blockquote&gt;Active Resource attempts to provide a coherent wrapper object-relational mapping for REST web services. It follows the same philosophy as Active Record, in that one of its prime aims is to reduce the amount of code needed to map to these resources.  This is made possible by relying on a number of code- and protocol-based conventions that make it easy for Active Resource to infer complex relations and structures.
&lt;/blockquote&gt;
&lt;blockquote&gt;
Or, Model classes are mapped to remote REST resources by Active Resource much the same way Active Record maps model classes to database tables
&lt;/blockquote&gt;


The CRUD Mapping to REST (or ActiveRecord Mapping to ActiveResource) :
&lt;table&gt;
&lt;tr&gt;&lt;td&gt;Create&lt;/td&gt;&lt;td&gt; POST&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Read&lt;/td&gt;&lt;td&gt; GET -- &lt;b&gt;our target&lt;/b&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Update&lt;/td&gt;&lt;td&gt; PUT&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Delete&lt;/td&gt;&lt;td&gt; DELETE&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;

&lt;br /&gt;
A minimalistic ActiveResource Model class looks as follows:
&lt;table class="CodeRay"&gt;&lt;tr&gt;
  &lt;td title="click to toggle" class="line_numbers"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;6&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre&gt;&lt;span class="r"&gt;class&lt;/span&gt; &lt;span class="cl"&gt;Product&lt;/span&gt; &amp;lt; &lt;span class="co"&gt;ActiveResource&lt;/span&gt;::&lt;span class="co"&gt;Base&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="pc"&gt;self&lt;/span&gt;.site = &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;http://www.quarkrank.com/&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="c"&gt;# Now, one can query quarkrank.com's api to get all products, or complete details for a particular product by simply doing a find:&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="c"&gt;# Product.find(:all) =&amp;gt; http://www.quarkrank.com/products.xml&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="c"&gt;# Product.find(&amp;quot;canon-powershot-sd1000&amp;quot;) =&amp;gt; http://www.quarkrank.com/products/canon-powershot-sd1000.xml &lt;/span&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;

&lt;p&gt;&lt;b&gt;Nested Resources&lt;/b&gt;: Some resources depend on other resources for e.g. comments on a blog would always depend on of the blog post. The comments can't exist independently. So, url for comments would be something like: 
www.myblog.com/posts/a_post/comments. Which means that url for finding comments would require an blog_post id.&lt;/p&gt;
And if one is accessing nested resources, model class would look like:&lt;br /&gt;
&lt;table class="CodeRay"&gt;&lt;tr&gt;
  &lt;td title="click to toggle" class="line_numbers"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;6&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre&gt;&lt;span class="r"&gt;class&lt;/span&gt; &lt;span class="cl"&gt;Review&lt;/span&gt; &amp;lt; &lt;span class="co"&gt;ActiveResource&lt;/span&gt;::&lt;span class="co"&gt;Base&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="c"&gt;# here reviews exist for a given product only.&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="pc"&gt;self&lt;/span&gt;.site = &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;http://www.quarkrank.com/products/:product_id/&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="c"&gt;# Now, you can ask for reviews on canon-powershot-sd1000 by doing find:&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="c"&gt;# Review.find(:all, :params=&amp;gt;{:product_id=&amp;gt;'canon-powershot-sd1000'})&lt;/span&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;

For better understanding further, I would really appreciate if you could go through &lt;a href="http://ryandaigle.com/assets/2007/3/14/REST_ARes.pdf"&gt;Ryan's presentation on ActiveResource&lt;/a&gt; and &lt;a href="http://railscasts.com/episodes/94"&gt;Railscasts&lt;/a&gt; &lt;a href="http://railscasts.com/episodes/95"&gt;ActiveResource&lt;/a&gt; episodes for better understanding of ActiveResource basics.
&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;
&lt;b&gt;Method Call Flow in a Get Request&lt;/b&gt;&lt;br /&gt;
Lets say, we are doing a &lt;code&gt;find&lt;/code&gt; query on some ActiveResource Model.&lt;br /&gt;
&lt;em&gt;Note:&lt;/em&gt; (phrases in braces denote the actual method calls being made)&lt;br /&gt;

&lt;table class="CodeRay"&gt;&lt;tr&gt;
  &lt;td title="click to toggle" class="line_numbers"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;6&lt;tt&gt;
&lt;/tt&gt;7&lt;tt&gt;
&lt;/tt&gt;8&lt;tt&gt;
&lt;/tt&gt;9&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;11&lt;tt&gt;
&lt;/tt&gt;12&lt;tt&gt;
&lt;/tt&gt;13&lt;tt&gt;
&lt;/tt&gt;14&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;15&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;16&lt;tt&gt;
&lt;/tt&gt;17&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre&gt; find&lt;tt&gt;
&lt;/tt&gt;  |  &lt;tt&gt;
&lt;/tt&gt;  |-- find single or all items(find_single/find_every)&lt;tt&gt;
&lt;/tt&gt;        |&lt;tt&gt;
&lt;/tt&gt;        |-- create_url (element_path/collection_path)&lt;tt&gt;
&lt;/tt&gt;        |&lt;tt&gt;
&lt;/tt&gt;        |-- get_response_from_url (connection.get)&lt;tt&gt;
&lt;/tt&gt;               |&lt;tt&gt;
&lt;/tt&gt;               |-- make_http_request_to_url (http.get)&lt;tt&gt;
&lt;/tt&gt;               |&lt;tt&gt;
&lt;/tt&gt;               |-- handle_response(response) -&lt;span class="er"&gt;&amp;gt;&lt;/span&gt; exceptions are raised here if we get 4xx/5xx response codes.&lt;tt&gt;
&lt;/tt&gt;               |&lt;tt&gt;
&lt;/tt&gt;               |-- get_body(response.body)&lt;tt&gt;
&lt;/tt&gt;               |&lt;tt&gt;
&lt;/tt&gt;               |-- decode_output, from xml/json to ruby hash (format.decode)&lt;tt&gt;
&lt;/tt&gt;        |&lt;tt&gt;
&lt;/tt&gt;        |-- convert_hash_to_active_resource_object (instantiate_record/instantiate_collection)&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;

&lt;br /&gt;

&lt;a&gt;&lt;/a&gt;
&lt;h2&gt;Consume non rails-style REST API&lt;/h2&gt;
As we plan to talk about the GET operation, lets get deeper into the following steps :

&lt;a&gt;&lt;/a&gt;
&lt;h3 class="nomargin"&gt;Creating URL for remote resources&lt;/h3&gt;
Sometimes, we might need to change the REST style url generation. At time of writing this article, most of the popular API's do not follow the rails restful url generation. So, the first step is to create the URL before a third party resource call is made. The URL is constructed using &lt;code&gt;element_path&lt;/code&gt; or &lt;code&gt;collection_path&lt;/code&gt; methods, depending on whether the response has 1 element or a set of elements respectively.&lt;br /&gt;
So, here is the code and little explanation of element_path method.
&lt;table class="CodeRay"&gt;&lt;tr&gt;
  &lt;td title="click to toggle" class="line_numbers"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;6&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre&gt;&lt;span class="c"&gt;# code of element_path function&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="r"&gt;def&lt;/span&gt; &lt;span class="fu"&gt;element_path&lt;/span&gt;(id, prefix_options = {}, query_options = &lt;span class="pc"&gt;nil&lt;/span&gt;)&lt;tt&gt;
&lt;/tt&gt;  prefix_options, query_options = split_options(prefix_options) &lt;span class="r"&gt;if&lt;/span&gt; query_options.nil?&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="c"&gt;# path to the resource, which we want to access is evaluated in this statement: &lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="il"&gt;&lt;span class="dl"&gt;#{&lt;/span&gt;prefix(prefix_options)&lt;span class="dl"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="il"&gt;&lt;span class="dl"&gt;#{&lt;/span&gt;collection_name&lt;span class="dl"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="k"&gt;/&lt;/span&gt;&lt;span class="il"&gt;&lt;span class="dl"&gt;#{&lt;/span&gt;id&lt;span class="dl"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="k"&gt;.&lt;/span&gt;&lt;span class="il"&gt;&lt;span class="dl"&gt;#{&lt;/span&gt;format.extension&lt;span class="dl"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="il"&gt;&lt;span class="dl"&gt;#{&lt;/span&gt;query_string(query_options)&lt;span class="dl"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="r"&gt;end&lt;/span&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;

&lt;strong&gt;Explanation:&lt;/strong&gt; Lets look at each of the variable/method used in last statement above.
&lt;table class="CodeRay"&gt;&lt;tr&gt;
  &lt;td title="click to toggle" class="line_numbers"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;6&lt;tt&gt;
&lt;/tt&gt;7&lt;tt&gt;
&lt;/tt&gt;8&lt;tt&gt;
&lt;/tt&gt;9&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre&gt;prefix(prefix_options) depends on self.site variable and value(s) of nested resource variable.&lt;tt&gt;
&lt;/tt&gt;   =&amp;gt;Evaluates the &amp;quot;fixed&amp;quot; prefix path to the resource (if any, mentioned in self.site variable) and/or&lt;tt&gt;
&lt;/tt&gt;      in case you are using nested style queries, replaces variables with their values&lt;tt&gt;
&lt;/tt&gt;== Examples:&lt;tt&gt;
&lt;/tt&gt;1. self.site = &amp;quot;http://www.quarkrank.com/folders/api&amp;quot;&lt;tt&gt;
&lt;/tt&gt;prefix(prefix_options) =&amp;gt; &amp;quot;/folders/api/&amp;quot;&lt;tt&gt;
&lt;/tt&gt;2. self.site = &amp;quot;http://www.quarkrank.com/folders/:folder_id&amp;quot;&lt;tt&gt;
&lt;/tt&gt;find(1,:folder_id=&amp;gt;5)&lt;tt&gt;
&lt;/tt&gt;prefix(prefix_options) =&amp;gt; &amp;quot;/folders/5/&amp;quot;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;


&lt;table class="CodeRay"&gt;&lt;tr&gt;
  &lt;td title="click to toggle" class="line_numbers"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre&gt;collection_name =&amp;gt; evaluates to pluralize form of classname&lt;tt&gt;
&lt;/tt&gt;== Examples:&lt;tt&gt;
&lt;/tt&gt;1. class Comment &amp;lt; ActiveResource::Base;end&lt;tt&gt;
&lt;/tt&gt;collection_name =&amp;gt; &amp;quot;comments&amp;quot;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;

&lt;table class="CodeRay"&gt;&lt;tr&gt;
  &lt;td title="click to toggle" class="line_numbers"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre&gt;id =&amp;gt; id of the item we are querying, usually mentioned in find (example: User.find(5))&lt;tt&gt;
&lt;/tt&gt;format_extension =&amp;gt; what format request you are making request for (default is xml).&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;

&lt;table class="CodeRay"&gt;&lt;tr&gt;
  &lt;td title="click to toggle" class="line_numbers"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;6&lt;tt&gt;
&lt;/tt&gt;7&lt;tt&gt;
&lt;/tt&gt;8&lt;tt&gt;
&lt;/tt&gt;9&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre&gt;query_string(query_options) =&amp;gt; generates get styled query string from remaining params.&lt;tt&gt;
&lt;/tt&gt;== Examples:&lt;tt&gt;
&lt;/tt&gt;1. self.site = &amp;quot;http://www.quarkrank.com/folders/api&amp;quot;&lt;tt&gt;
&lt;/tt&gt;    find(1)&lt;tt&gt;
&lt;/tt&gt;    query_string(query_options) =&amp;gt; &amp;quot;&amp;quot;&lt;tt&gt;
&lt;/tt&gt;2. self.site = &amp;quot;http://www.quarkrank.com/folders/:folder_id&amp;quot;&lt;tt&gt;
&lt;/tt&gt;    find(1,:folder_id=&amp;gt;5, :filename=&amp;gt;&amp;quot;nakul&amp;quot;)&lt;tt&gt;
&lt;/tt&gt;    query_string(query_options) =&amp;gt; &amp;quot;?filename=nakul&amp;quot;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;## collection_path method is quite similar&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;


So, in case you want to modify the element_path, just redefine the method in your model class with custom definition. Please look into &lt;a href="http://www.quarkruby.com/2008/1/15/activeresource-and-youtube"&gt;ActiveYoutube class code as an example&lt;/a&gt;.

&lt;a&gt;&lt;/a&gt;
&lt;h3 class="nomargin"&gt;Make a GET request &lt;/h3&gt;
After creating url, request is send using Net::HTTP (ssl requests are supported). &lt;br /&gt;
Note that, private method "request" is called for making a Net::HTTP request, which logs the request being made and response from api server. This logging might lead to exception, because of the following line in the code.
&lt;table class="CodeRay"&gt;&lt;tr&gt;
  &lt;td title="click to toggle" class="line_numbers"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre&gt;&lt;span class="c"&gt;# in case, result.message contains some characters like &amp;quot;%A&amp;quot;, this leads to exception&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;logger.info &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;--&amp;gt; &lt;/span&gt;&lt;span class="il"&gt;&lt;span class="dl"&gt;#{&lt;/span&gt;result.code&lt;span class="dl"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="k"&gt; &lt;/span&gt;&lt;span class="il"&gt;&lt;span class="dl"&gt;#{&lt;/span&gt;result.message&lt;span class="dl"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="k"&gt; (&lt;/span&gt;&lt;span class="il"&gt;&lt;span class="dl"&gt;#{&lt;/span&gt;result.body ? result.body : &lt;span class="i"&gt;0&lt;/span&gt;&lt;span class="dl"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="k"&gt;b %.2fs)&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; % time &lt;span class="r"&gt;if&lt;/span&gt; logger&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;

So, in case you are getting exception try to switch off the logs.

&lt;a&gt;&lt;/a&gt;
&lt;h3 class="nomargin"&gt;Handling (Custom) Response&lt;/h3&gt;
&lt;p&gt;ActiveResource relies on response code to figure out errors/success/redirection but this might not always be true.  Most of the API's do not respect this. Its quite common to see possible errors like unauthorized access, forbidden access, server error etc in success response. &lt;br /&gt;
For example, on unauthorized access, Flickr's API returns 200 OK response code with xml response describing the failure. (Facebook API also belongs to this league)&lt;/p&gt;
&lt;b&gt;How to handle these errors? :&lt;/b&gt; ActiveResource currently doesn't supports callback hooks like after_find etc. So, one cannot hook the custom handlers for response handling. While, &lt;a href="http://weblog.techno-weenie.net/2008/1/21/random-rails-tidbits"&gt;work&lt;/a&gt; is in progress for having callbacks support in ActiveResource, but till then we need to handle them on our own. So, for Flickr API, one solution will look like:
&lt;table class="CodeRay"&gt;&lt;tr&gt;
  &lt;td title="click to toggle" class="line_numbers"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;6&lt;tt&gt;
&lt;/tt&gt;7&lt;tt&gt;
&lt;/tt&gt;8&lt;tt&gt;
&lt;/tt&gt;9&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;11&lt;tt&gt;
&lt;/tt&gt;12&lt;tt&gt;
&lt;/tt&gt;13&lt;tt&gt;
&lt;/tt&gt;14&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;15&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;16&lt;tt&gt;
&lt;/tt&gt;17&lt;tt&gt;
&lt;/tt&gt;18&lt;tt&gt;
&lt;/tt&gt;19&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;20&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre&gt;&lt;span class="c"&gt;## define a ActiveResource::Flickr  class, which raises exception if response is not OK.&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="r"&gt;class&lt;/span&gt; &lt;span class="cl"&gt;ActiveFlickr&lt;/span&gt;&amp;lt;&lt;span class="co"&gt;ActiveResource&lt;/span&gt;::&lt;span class="co"&gt;Base&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="r"&gt;class&lt;/span&gt; &amp;lt;&amp;lt; &lt;span class="cl"&gt;self&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;      &lt;span class="r"&gt;alias&lt;/span&gt; &lt;span class="sy"&gt;:old_find&lt;/span&gt; &lt;span class="sy"&gt;:find&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;      &lt;span class="r"&gt;def&lt;/span&gt; &lt;span class="fu"&gt;find&lt;/span&gt;(*arguments)&lt;tt&gt;
&lt;/tt&gt;        output = old_find(*arguments)&lt;tt&gt;
&lt;/tt&gt;        &lt;span class="r"&gt;if&lt;/span&gt; output.respond_to? &lt;span class="sy"&gt;:err&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;          &lt;span class="r"&gt;case&lt;/span&gt; output.err.code.to_i&lt;tt&gt;
&lt;/tt&gt;            &lt;span class="r"&gt;when&lt;/span&gt; &lt;span class="i"&gt;100&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;              raise(&lt;span class="co"&gt;ActiveResource&lt;/span&gt;::&lt;span class="co"&gt;UnauthorizedAccess&lt;/span&gt;.new(output.err, output.err.msg))&lt;tt&gt;
&lt;/tt&gt;            &lt;span class="r"&gt;when&lt;/span&gt; &lt;span class="i"&gt;112&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;              raise(&lt;span class="co"&gt;ActiveResource&lt;/span&gt;::&lt;span class="co"&gt;MethodNotAllowed&lt;/span&gt;.new(output.err, output.err.msg))&lt;tt&gt;
&lt;/tt&gt;            &lt;span class="r"&gt;else&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;              raise(&lt;span class="co"&gt;ConnectionError&lt;/span&gt;.new(output.err, &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;Unknown response code: &lt;/span&gt;&lt;span class="il"&gt;&lt;span class="dl"&gt;#{&lt;/span&gt;outout.err.code&lt;span class="dl"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;))&lt;tt&gt;
&lt;/tt&gt;          &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;        &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;      &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;   &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="c"&gt;# now other ActiveResource models would inherit from ActiveFlickr, rather ActiveResource::Base.&lt;/span&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;


&lt;table class="CodeRay"&gt;&lt;tr&gt;
  &lt;td title="click to toggle" class="line_numbers"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;6&lt;tt&gt;
&lt;/tt&gt;7&lt;tt&gt;
&lt;/tt&gt;8&lt;tt&gt;
&lt;/tt&gt;9&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;11&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre&gt;&lt;span class="c"&gt;## also ActiveResource Exceptions, currently doesn't logs/prints the &amp;quot;message&amp;quot;, which is passed as second argument. &lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="c"&gt;# You might want to modify the behavior to print error message also.&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="r"&gt;module&lt;/span&gt; &lt;span class="cl"&gt;ActiveResource&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="r"&gt;class&lt;/span&gt; &lt;span class="cl"&gt;ConnectionError&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="r"&gt;def&lt;/span&gt; &lt;span class="fu"&gt;to_s&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;      str = &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;Failed with &lt;/span&gt;&lt;span class="il"&gt;&lt;span class="dl"&gt;#{&lt;/span&gt;response.code&lt;span class="dl"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="k"&gt; &lt;/span&gt;&lt;span class="il"&gt;&lt;span class="dl"&gt;#{&lt;/span&gt;response.message &lt;span class="r"&gt;if&lt;/span&gt; response.respond_to?(&lt;span class="sy"&gt;:message&lt;/span&gt;)&lt;span class="dl"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="ch"&gt;\n&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;      str += &lt;span class="iv"&gt;@message&lt;/span&gt; &lt;span class="r"&gt;unless&lt;/span&gt; &lt;span class="iv"&gt;@message&lt;/span&gt;.nil?&lt;tt&gt;
&lt;/tt&gt;      str&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="r"&gt;end&lt;/span&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;


&lt;a&gt;&lt;/a&gt;
&lt;h3 class="nomargin"&gt;Parse Response&lt;/h3&gt;
Next step is to decode the XML/JSON response into ruby object. Decoding is done in get/post method call in connection.rb. XML to hash conversion is done using &lt;a href="http://xml-simple.rubyforge.org/"&gt;XmlSimple&lt;/a&gt; with some modifications.&lt;br /&gt;
There is not much documentation on this conversion but more enthusiastic people can look at &lt;code&gt;from_xml&lt;/code&gt; method in: &lt;code&gt;vendor/rails/activesupport/lib/active_support/core_ext/hash/conversions.rb&lt;/code&gt;

&lt;a&gt;&lt;/a&gt;
&lt;h3 class="nomargin"&gt;Create ActiveResource object from parsed response&lt;/h3&gt;
Convert appropriate elements into ActiveResource objects. Its done using 'load' method in ActiveResource::Base, which takes ruby object as input and maps it into ActiveResource object.

&lt;a&gt;&lt;/a&gt;
&lt;h3 class="nomargin"&gt;Other things to keep in mind&lt;/h3&gt;
In last step of &lt;code&gt;find(:all)&lt;/code&gt; method call, i.e. conversion of ruby object to ActiveResource Object, &lt;code&gt;instantiate_collection&lt;/code&gt; method is called on ruby object. Here, ActiveResource expects an array.  This may not be true for many of API's like Amazon, Youtube. So, you might need to rewrite this function:&lt;br /&gt;
&lt;table class="CodeRay"&gt;&lt;tr&gt;
  &lt;td title="click to toggle" class="line_numbers"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;6&lt;tt&gt;
&lt;/tt&gt;7&lt;tt&gt;
&lt;/tt&gt;8&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre&gt;&lt;span class="r"&gt;class&lt;/span&gt; &lt;span class="cl"&gt;ActiveResource::Base&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="r"&gt;def&lt;/span&gt; &lt;span class="pc"&gt;self&lt;/span&gt;.instantiate_collection(collection, prefix_options = {})&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="r"&gt;unless&lt;/span&gt; collection.kind_of? &lt;span class="co"&gt;Array&lt;/span&gt;      [instantiate_record(collection, prefix_options)]&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="r"&gt;else&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;      collection.collect! { |record| instantiate_record(record, prefix_options) }&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="r"&gt;end&lt;/span&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;


&lt;a&gt;&lt;/a&gt;
&lt;h2&gt;Custom HTTP GET method tweaks&lt;/h2&gt;
&lt;p&gt;Since simple CRUD/lifecycle methods cannot accomplish every task, ActiveResource supports defining your own &lt;em&gt;custom REST methods&lt;/em&gt;. Sometimes we will be using CustomHTTP requests for executing a custom action for a particular resource.&lt;/p&gt;
&lt;strong&gt;Example&lt;/strong&gt;: Getting comments for a particular blog post. A sample request could be: &lt;em&gt;www.myblog.com/post/active_resouce/coments.xml&lt;/em&gt;. Here, we find a particular blog post and then ask for comments on it. So, ActiveResouce code would be:
&lt;table class="CodeRay"&gt;&lt;tr&gt;
  &lt;td title="click to toggle" class="line_numbers"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre&gt;&lt;span class="c"&gt;# Type1: &lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="co"&gt;BlogPost&lt;/span&gt;.find(&lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;active_resouce&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;).get(&lt;span class="sy"&gt;:comments&lt;/span&gt;)&lt;tt&gt;
&lt;/tt&gt;&lt;span class="c"&gt;# More examples:&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="co"&gt;Person&lt;/span&gt;.find(&lt;span class="i"&gt;1&lt;/span&gt;).put(&lt;span class="sy"&gt;:promote&lt;/span&gt;, &lt;span class="sy"&gt;:position&lt;/span&gt; =&amp;gt; &lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;Manager&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;) &lt;span class="c"&gt;# PUT /people/1/promote.xml&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="co"&gt;Person&lt;/span&gt;.find(&lt;span class="i"&gt;1&lt;/span&gt;).delete(&lt;span class="sy"&gt;:deactivate&lt;/span&gt;) &lt;span class="c"&gt;# DELETE /people/1/deactivate.xml&lt;/span&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;

Or, sometimes, we might just want the list of active users on website right now.
&lt;table class="CodeRay"&gt;&lt;tr&gt;
  &lt;td title="click to toggle" class="line_numbers"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre&gt;&lt;span class="c"&gt;#Type2&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="co"&gt;Person&lt;/span&gt;.get(&lt;span class="sy"&gt;:active&lt;/span&gt;)  &lt;span class="c"&gt;# GET /people/active.xml&lt;/span&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;


&lt;h3 class="nomargin"&gt;find method makes a call to get "id"&lt;/h3&gt;
The "Type1" custom REST requests actually makes 2 remote requests:
&lt;ul&gt;
  &lt;li&gt;Find the resource for which we want to make a custom request: This is used to find the &lt;code&gt;id&lt;/code&gt; of the resource to be used in next step&lt;/li&gt;
  &lt;li&gt;The actual custom rest request&lt;/li&gt;
&lt;/ul&gt;
Here, sometimes we might want to skip step1 if we already know the "id" of the resource. So, one can define different find method which just sets the &lt;em&gt;id&lt;/em&gt; param to be used to custom rest request and call get method:
&lt;table class="CodeRay"&gt;&lt;tr&gt;
  &lt;td title="click to toggle" class="line_numbers"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;6&lt;tt&gt;
&lt;/tt&gt;7&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre&gt;  &lt;span class="r"&gt;def&lt;/span&gt; &lt;span class="fu"&gt;find_custom&lt;/span&gt;(arg)&lt;tt&gt;
&lt;/tt&gt;    object = &lt;span class="pc"&gt;self&lt;/span&gt;.new&lt;tt&gt;
&lt;/tt&gt;    object.id = arg&lt;tt&gt;
&lt;/tt&gt;    object&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="c"&gt;# Example: For youtube videos, if we want comments for a particular video, we would do &lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="c"&gt;# Video.find_custom(&amp;quot;ZTUVgYoeN_o&amp;quot;).get(:comments)&lt;/span&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;

&lt;h3 class="nomargin"&gt; "get" method doesn't converts hash into objects.&lt;/h3&gt;
ActiveResource::CustomMethods &lt;em&gt;get&lt;/em&gt; request sometimes does not converts the decoded ruby object (from xml) to activeresource objects. You can modify the behavior to get activeresource object
&lt;table class="CodeRay"&gt;&lt;tr&gt;
  &lt;td title="click to toggle" class="line_numbers"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;6&lt;tt&gt;
&lt;/tt&gt;7&lt;tt&gt;
&lt;/tt&gt;8&lt;tt&gt;
&lt;/tt&gt;9&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;11&lt;tt&gt;
&lt;/tt&gt;12&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre&gt;  &lt;span class="r"&gt;def&lt;/span&gt; &lt;span class="fu"&gt;get&lt;/span&gt;(method_name, options = {})&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="pc"&gt;self&lt;/span&gt;.class.new.load(connection.get(custom_method_element_url(method_name, options), &lt;span class="pc"&gt;self&lt;/span&gt;.class.headers))&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="r"&gt;def&lt;/span&gt; &lt;span class="pc"&gt;self&lt;/span&gt;.get(method_name, options = {})&lt;tt&gt;
&lt;/tt&gt;    object_array = connection.get(custom_method_collection_url(method_name, options), headers)&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="r"&gt;if&lt;/span&gt; object_array.class.to_s==&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;Array&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;      object_array.collect! {|record| &lt;span class="pc"&gt;self&lt;/span&gt;.class.new.load(record)}&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="r"&gt;else&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;      &lt;span class="pc"&gt;self&lt;/span&gt;.class.new.load(object_array)&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="r"&gt;end&lt;/span&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;


&lt;a&gt;&lt;/a&gt;
&lt;h2&gt;Data Format&lt;/h2&gt;
Currently 2 formats are supported by ActiveResource: JSON and XML
Do you want to use another format? Pretty easy, you need to define 4 methods: extension, mime_type, encode and decode. Encoding is for converting hash into required format and Decoding is for decoding the response in this format into a hash object.
Example of JSON format 
&lt;table class="CodeRay"&gt;&lt;tr&gt;
  &lt;td title="click to toggle" class="line_numbers"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;6&lt;tt&gt;
&lt;/tt&gt;7&lt;tt&gt;
&lt;/tt&gt;8&lt;tt&gt;
&lt;/tt&gt;9&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;11&lt;tt&gt;
&lt;/tt&gt;12&lt;tt&gt;
&lt;/tt&gt;13&lt;tt&gt;
&lt;/tt&gt;14&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;15&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;16&lt;tt&gt;
&lt;/tt&gt;17&lt;tt&gt;
&lt;/tt&gt;18&lt;tt&gt;
&lt;/tt&gt;19&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;20&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;21&lt;tt&gt;
&lt;/tt&gt;22&lt;tt&gt;
&lt;/tt&gt;23&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre&gt;&lt;span class="r"&gt;module&lt;/span&gt; &lt;span class="cl"&gt;ActiveResource&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="r"&gt;module&lt;/span&gt; &lt;span class="cl"&gt;Formats&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="r"&gt;module&lt;/span&gt; &lt;span class="cl"&gt;JsonFormat&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;      extend &lt;span class="pc"&gt;self&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;      &lt;tt&gt;
&lt;/tt&gt;      &lt;span class="r"&gt;def&lt;/span&gt; &lt;span class="fu"&gt;extension&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;        &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;json&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;      &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;      &lt;tt&gt;
&lt;/tt&gt;      &lt;span class="r"&gt;def&lt;/span&gt; &lt;span class="fu"&gt;mime_type&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;        &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;application/json&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;      &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;      &lt;tt&gt;
&lt;/tt&gt;      &lt;span class="r"&gt;def&lt;/span&gt; &lt;span class="fu"&gt;encode&lt;/span&gt;(hash)&lt;tt&gt;
&lt;/tt&gt;        hash.to_json&lt;tt&gt;
&lt;/tt&gt;      &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;      &lt;tt&gt;
&lt;/tt&gt;      &lt;span class="r"&gt;def&lt;/span&gt; &lt;span class="fu"&gt;decode&lt;/span&gt;(json)&lt;tt&gt;
&lt;/tt&gt;        &lt;span class="co"&gt;ActiveSupport&lt;/span&gt;::&lt;span class="co"&gt;JSON&lt;/span&gt;.decode(json)&lt;tt&gt;
&lt;/tt&gt;      &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="r"&gt;end&lt;/span&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;

&lt;br /&gt;

Thanks to Brian Nochugi for his frequent discussion/doubts on ActiveResource. It helped us to properly formulate the article.
          </content>  <feedburner:origLink>http://www.quarkruby.com/2008/3/11/consume-non-rails-style-rest-apis</feedburner:origLink></entry>
  <entry xml:base="http://www.quarkruby.com/">
    <author>
      <name>admin</name>
    </author>
    <id>tag:www.quarkruby.com,2008-02-12:2872</id>
    <published>2008-02-12T18:57:00Z</published>
    <updated>2008-02-12T18:58:28Z</updated>
    <category term="our tools" />
    <category term="ruby" />
    <category term="activeresource" />
    <category term="api" />
    <category term="plugin" />
    <link href="http://feedproxy.google.com/~r/Quarkruby/~3/nrk_ztps2rA/active-youtube" rel="alternate" type="text/html" />
    <title>Active Youtube</title>
<content type="html">
            ActiveYoutube is a gem to access YouTube API using ActiveResource. This gem wraps code from our &lt;a href="http://www.quarkruby.com/2008/1/15/activeresource-and-youtube"&gt;previous post&lt;/a&gt; on extending ActiveResource to access YouTube. There have been minor changes, which are :
&lt;ol&gt;
  &lt;li&gt;&lt;b&gt;Namespace in class names&lt;/b&gt;: Video, User, StandardFeed and Playlist classes have been moved to "Youtube" module, to prevent any conflicts with your ActiveRecord models.&lt;/li&gt;
  &lt;li&gt;&lt;b&gt;CustomMethods related change&lt;/b&gt;: In last version, only response from "find" was converting "entry" object to array of "entry" object. Now, the same behavior is implemented for custom http calls like Video.find().get(:comments)&lt;/li&gt;
  &lt;li&gt;&lt;b&gt;Small patch for better namespacing&lt;/b&gt;: Its basically some code from the rails trunk on ActiveResource, for better handling of namespaces while creating ActiveResource objects.
&lt;/ol&gt;

&lt;h3&gt;Gem Installation:&lt;/h3&gt;
&lt;table class="CodeRay"&gt;&lt;tr&gt;
  &lt;td title="click to toggle" class="line_numbers"&gt;&lt;pre&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre&gt;sudo gem install active_youtube&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;


&lt;h3&gt;Example Usage:&lt;/h3&gt;
&lt;table class="CodeRay"&gt;&lt;tr&gt;
  &lt;td title="click to toggle" class="line_numbers"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;6&lt;tt&gt;
&lt;/tt&gt;7&lt;tt&gt;
&lt;/tt&gt;8&lt;tt&gt;
&lt;/tt&gt;9&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;11&lt;tt&gt;
&lt;/tt&gt;12&lt;tt&gt;
&lt;/tt&gt;13&lt;tt&gt;
&lt;/tt&gt;14&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;15&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;16&lt;tt&gt;
&lt;/tt&gt;17&lt;tt&gt;
&lt;/tt&gt;18&lt;tt&gt;
&lt;/tt&gt;19&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;20&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;21&lt;tt&gt;
&lt;/tt&gt;22&lt;tt&gt;
&lt;/tt&gt;23&lt;tt&gt;
&lt;/tt&gt;24&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;25&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;26&lt;tt&gt;
&lt;/tt&gt;27&lt;tt&gt;
&lt;/tt&gt;28&lt;tt&gt;
&lt;/tt&gt;29&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;30&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;31&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre&gt;&lt;span class="c"&gt;#### Video&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="c"&gt;## search for videos on 'ruby'&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  search = &lt;span class="co"&gt;Youtube&lt;/span&gt;::&lt;span class="co"&gt;Video&lt;/span&gt;.find(&lt;span class="sy"&gt;:first&lt;/span&gt;, &lt;span class="sy"&gt;:params&lt;/span&gt; =&amp;gt; {&lt;span class="sy"&gt;:vq&lt;/span&gt; =&amp;gt; &lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;ruby&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;, &lt;span class="sy"&gt;&lt;span class="sy"&gt;:&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;max-results&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; =&amp;gt; &lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;5&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;})&lt;tt&gt;
&lt;/tt&gt;  puts search.entry.length&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="c"&gt;## video information of id = ZTUVgYoeN_o&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  vid = &lt;span class="co"&gt;Youtube&lt;/span&gt;::&lt;span class="co"&gt;Video&lt;/span&gt;.find(&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;ZTUVgYoeN_o&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;)&lt;tt&gt;
&lt;/tt&gt;  puts vid.group.content[&lt;span class="i"&gt;0&lt;/span&gt;].url&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="c"&gt;## video comments&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  comments = &lt;span class="co"&gt;Youtube&lt;/span&gt;::&lt;span class="co"&gt;Video&lt;/span&gt;.find_custom(&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;ZTUVgYoeN_o&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;).get(&lt;span class="sy"&gt;:comments&lt;/span&gt;)&lt;tt&gt;
&lt;/tt&gt;  puts comments.entry[&lt;span class="i"&gt;0&lt;/span&gt;].link[&lt;span class="i"&gt;2&lt;/span&gt;].href&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="c"&gt;## searching with category/tags&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  results = &lt;span class="co"&gt;Youtube&lt;/span&gt;::&lt;span class="co"&gt;Video&lt;/span&gt;.search_by_tags(&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;Comedy&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;)&lt;tt&gt;
&lt;/tt&gt;  puts results[&lt;span class="i"&gt;0&lt;/span&gt;].entry[&lt;span class="i"&gt;0&lt;/span&gt;].title&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="c"&gt;#### STANDARDFEED&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="c"&gt;## retrieving standard feeds&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  most_viewed = &lt;span class="co"&gt;Youtube&lt;/span&gt;::&lt;span class="co"&gt;Standardfeed&lt;/span&gt;.find(&lt;span class="sy"&gt;:most_viewed&lt;/span&gt;, &lt;span class="sy"&gt;:params&lt;/span&gt; =&amp;gt; {&lt;span class="sy"&gt;:time&lt;/span&gt; =&amp;gt; &lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;today&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;})&lt;tt&gt;
&lt;/tt&gt;  puts most_viewed.entry[&lt;span class="i"&gt;0&lt;/span&gt;].group.content[&lt;span class="i"&gt;0&lt;/span&gt;].url&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="c"&gt;#### USER&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="c"&gt;## user's profile - guthrie&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  user_profile = &lt;span class="co"&gt;Youtube&lt;/span&gt;::&lt;span class="co"&gt;User&lt;/span&gt;.find(&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;guthrie&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;)&lt;tt&gt;
&lt;/tt&gt;  puts user_profile.link[&lt;span class="i"&gt;1&lt;/span&gt;].href&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="c"&gt;#### PLAYLIST&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="c"&gt;## get playlist - multiple elements in playlist&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  playlist = &lt;span class="co"&gt;Youtube&lt;/span&gt;::&lt;span class="co"&gt;Playlist&lt;/span&gt;.find(&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;EBF5D6DC4589D7B7&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;)&lt;tt&gt;
&lt;/tt&gt;  puts playlist.entry[&lt;span class="i"&gt;0&lt;/span&gt;].group.content[&lt;span class="i"&gt;0&lt;/span&gt;].url&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
          </content>  <feedburner:origLink>http://www.quarkruby.com/2008/2/12/active-youtube</feedburner:origLink></entry>
  <entry xml:base="http://www.quarkruby.com/">
    <author>
      <name>admin</name>
    </author>
    <id>tag:www.quarkruby.com,2008-01-30:2037</id>
    <published>2008-01-30T14:11:00Z</published>
    <updated>2008-01-30T14:13:01Z</updated>
    <category term="ruby on rails" />
    <category term="html scraping" />
    <category term="scrapi" />
    <link href="http://feedproxy.google.com/~r/Quarkruby/~3/dWjo4mo6mzw/scrapi-enhancements" rel="alternate" type="text/html" />
    <title>Scrapi enhancements</title>
<summary type="html">&lt;p&gt;We have been using ruby library &lt;a href="http://blog.labnotes.org/2006/07/11/scraping-with-style-scrapi-toolkit-for-ruby/"&gt;Scrapi&lt;/a&gt; quite a lot for HTML Scraping in &lt;a href="http://www.quarkrank.com"&gt;QuarkRank&lt;/a&gt; and other projects. Most of the times, I want to extract/scrape specific information from a page and directly dump it into the database. There were a few processes which were regularly repeated in my code, so as to make my code more DRY, I have enhanced Scrapi so that manipulations of extracted information becomes easier.&lt;/p&gt;

&lt;p&gt;Lets consider an example, for each of the &lt;a href="http://www.imdb.com/chart/top"&gt;top 250 movies at IMDB&lt;/a&gt;, I want to extract and store in DB the following properties :
&lt;ol&gt;
  &lt;li&gt;imdb_id&lt;/li&gt;
  &lt;li&gt;name&lt;/li&gt;
  &lt;li&gt;release date&lt;/li&gt;
  &lt;li&gt;rating&lt;/li&gt;
  &lt;li&gt;tagline&lt;/li&gt;
  &lt;li&gt;runtime&lt;/li&gt;
  &lt;li&gt;director&lt;/li&gt;
&lt;/ol&gt;</summary><content type="html">
            &lt;p&gt;We have been using ruby library &lt;a href="http://blog.labnotes.org/2006/07/11/scraping-with-style-scrapi-toolkit-for-ruby/"&gt;Scrapi&lt;/a&gt; quite a lot for HTML Scraping in &lt;a href="http://www.quarkrank.com"&gt;QuarkRank&lt;/a&gt; and other projects. Most of the times, I want to extract/scrape specific information from a page and directly dump it into the database. There were a few processes which were regularly repeated in my code, so as to make my code more DRY, I have enhanced Scrapi so that manipulations of extracted information becomes easier.&lt;/p&gt;

&lt;p&gt;Lets consider an example, for each of the &lt;a href="http://www.imdb.com/chart/top"&gt;top 250 movies at IMDB&lt;/a&gt;, I want to extract and store in DB the following properties :
&lt;ol&gt;
  &lt;li&gt;imdb_id&lt;/li&gt;
  &lt;li&gt;name&lt;/li&gt;
  &lt;li&gt;release date&lt;/li&gt;
  &lt;li&gt;rating&lt;/li&gt;
  &lt;li&gt;tagline&lt;/li&gt;
  &lt;li&gt;runtime&lt;/li&gt;
  &lt;li&gt;director&lt;/li&gt;
&lt;/ol&gt;

So, the process would be :
&lt;ol&gt;
  &lt;li&gt;Get the list of top 250 movies and their URLs.&lt;/li&gt;
  &lt;li&gt;For each URL, scrape the corresponding properties.&lt;/li&gt;
  &lt;li&gt;For each property, do cleaning/formatting (like parse Release Date into Date object) if required.&lt;/li&gt;
  &lt;li&gt;Build a hash out of extracted information.&lt;/li&gt;
  &lt;li&gt;Create Movie object using hash in above step.&lt;/li&gt;
&lt;/ol&gt;
&lt;/p&gt;

The code for the above process would be something like :
&lt;table class="CodeRay"&gt;&lt;tr&gt;
  &lt;td title="click to toggle" class="line_numbers"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;6&lt;tt&gt;
&lt;/tt&gt;7&lt;tt&gt;
&lt;/tt&gt;8&lt;tt&gt;
&lt;/tt&gt;9&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;11&lt;tt&gt;
&lt;/tt&gt;12&lt;tt&gt;
&lt;/tt&gt;13&lt;tt&gt;
&lt;/tt&gt;14&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;15&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;16&lt;tt&gt;
&lt;/tt&gt;17&lt;tt&gt;
&lt;/tt&gt;18&lt;tt&gt;
&lt;/tt&gt;19&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;20&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;21&lt;tt&gt;
&lt;/tt&gt;22&lt;tt&gt;
&lt;/tt&gt;23&lt;tt&gt;
&lt;/tt&gt;24&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;25&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;26&lt;tt&gt;
&lt;/tt&gt;27&lt;tt&gt;
&lt;/tt&gt;28&lt;tt&gt;
&lt;/tt&gt;29&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;30&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;31&lt;tt&gt;
&lt;/tt&gt;32&lt;tt&gt;
&lt;/tt&gt;33&lt;tt&gt;
&lt;/tt&gt;34&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;35&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;36&lt;tt&gt;
&lt;/tt&gt;37&lt;tt&gt;
&lt;/tt&gt;38&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre&gt;require &lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;scrapi&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;require &lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;open-uri&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="c"&gt;# Step 1: Get list of top 250 movies and their URLs.&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="c"&gt;#  - Go to http://www.imdb.com/chart/top.&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="c"&gt;#  - Open up firebug, with firequark installed.&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="c"&gt;#  - Right click on any movie from the list and select &amp;quot;Inspect This&amp;quot; option from menu. In firebug you will see one selected element.&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="c"&gt;#  - Right click on this element in firebug, and select option &amp;quot;get css selector&amp;quot; (put 250 in popup input box).&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="c"&gt;#  - This returns &amp;quot;font&amp;gt;a&amp;quot;, which is css selector for getting all 250 movies from this page.&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;links = (&lt;span class="co"&gt;Scraper&lt;/span&gt;.define &lt;span class="r"&gt;do&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  array &lt;span class="sy"&gt;:urls&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  process &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;font&amp;gt;a&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class="sy"&gt;:urls&lt;/span&gt;=&amp;gt;&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;@href&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  result &lt;span class="sy"&gt;:urls&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="r"&gt;end&lt;/span&gt;).scrape(open(&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;http://www.imdb.com/chart/top&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;).read)&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="c"&gt;# Step 2: For each movie, get its properties&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;links.each &lt;span class="r"&gt;do&lt;/span&gt; |url|&lt;tt&gt;
&lt;/tt&gt;  nurl = &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;http://www.imdb.com&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; + url&lt;tt&gt;
&lt;/tt&gt;  hash = (&lt;span class="co"&gt;Scraper&lt;/span&gt;.define &lt;span class="r"&gt;do&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    process &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;h5:content('Release Date:')&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class="sy"&gt;:date&lt;/span&gt;=&amp;gt;&lt;span class="sy"&gt;:element&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    process &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;div.general&amp;gt;b:content('User Rating:')&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class="sy"&gt;:rating&lt;/span&gt;=&amp;gt;&lt;span class="sy"&gt;:element&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    process &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;h5:content('Tagline:')&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class="sy"&gt;:tagline&lt;/span&gt;=&amp;gt;&lt;span class="sy"&gt;:element&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    process &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;h1&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class="sy"&gt;:title&lt;/span&gt;=&amp;gt;&lt;span class="sy"&gt;:text&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    result &lt;span class="sy"&gt;:date&lt;/span&gt;, &lt;span class="sy"&gt;:rating&lt;/span&gt;, &lt;span class="sy"&gt;:title&lt;/span&gt;, &lt;span class="sy"&gt;:tagline&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="r"&gt;end&lt;/span&gt;).scrape(open(nurl).read)&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="c"&gt;# Step 3: Cleaning and hash building of properties.&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  object = {}&lt;tt&gt;
&lt;/tt&gt;  date_val = hash.date.next_sibling.text&lt;tt&gt;
&lt;/tt&gt;  object[&lt;span class="sy"&gt;:date&lt;/span&gt;] = &lt;span class="co"&gt;Date&lt;/span&gt;.parse(date_val[&lt;span class="i"&gt;0&lt;/span&gt;..date_val.rindex(&lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;)||&lt;span class="i"&gt;-1&lt;/span&gt;]).to_s&lt;tt&gt;
&lt;/tt&gt;  object[&lt;span class="sy"&gt;:rating&lt;/span&gt;] = hash.rating.next_element.text.gsub(&lt;span class="rx"&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;span class="ch"&gt;\/&lt;/span&gt;&lt;span class="k"&gt;.*&lt;/span&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;/span&gt;,&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;)&lt;tt&gt;
&lt;/tt&gt;  object[&lt;span class="sy"&gt;:title&lt;/span&gt;] = hash.title[&lt;span class="i"&gt;0&lt;/span&gt;..hash.title.rindex(&lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;)||&lt;span class="i"&gt;-1&lt;/span&gt;]&lt;tt&gt;
&lt;/tt&gt;  object[&lt;span class="sy"&gt;:tagline&lt;/span&gt;] = hash.tagline.next_sibling.text.strip &lt;span class="r"&gt;if&lt;/span&gt; hash.tagline&lt;tt&gt;
&lt;/tt&gt;  object[&lt;span class="sy"&gt;:imdb_id&lt;/span&gt;] = url.gsub(&lt;span class="rx"&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;span class="ch"&gt;\/&lt;/span&gt;&lt;span class="k"&gt;title&lt;/span&gt;&lt;span class="ch"&gt;\/&lt;/span&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;/span&gt;,&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;).gsub(&lt;span class="rx"&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;span class="ch"&gt;\/&lt;/span&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;/span&gt;,&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;)&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="c"&gt;# save the hash to database&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="co"&gt;Movie&lt;/span&gt;.create(object)&lt;tt&gt;
&lt;/tt&gt;&lt;span class="r"&gt;end&lt;/span&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;


Problems in the above code:&lt;br /&gt;
&lt;ol&gt;
&lt;li&gt;Inserting each struct member/value pair into hash explicitly&lt;/li&gt;
&lt;li&gt;I would love to do manipulations inline, i.e. when extracting an element. Particularly, in cases where I need to do small/minor modifications like, getting the text corresponding to next element of selected element or converting a string into date object&lt;/li&gt;
&lt;/ol&gt;

Following two enhancements in Scrapi allow me to get rid of problems and simplify my code + efforts :&lt;br /&gt;&lt;br /&gt;

&lt;b&gt;Fix1:&lt;/b&gt; Assign value of block manupilation to associated variable.&lt;br /&gt;So, I could write rules like:
&lt;table class="CodeRay"&gt;&lt;tr&gt;
  &lt;td title="click to toggle" class="line_numbers"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre&gt;&lt;span class="c"&gt;# get the text content of element next to &amp;quot;div#footer&amp;quot; into &amp;quot;footer_text&amp;quot; variable&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;process &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;div#footer&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class="sy"&gt;:footer_text&lt;/span&gt; &lt;span class="r"&gt;do&lt;/span&gt; |x|&lt;tt&gt;
&lt;/tt&gt;  x.next_element.text&lt;tt&gt;
&lt;/tt&gt;&lt;span class="r"&gt;end&lt;/span&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;

This is the patch which provides above functionality:
&lt;table class="CodeRay"&gt;&lt;tr&gt;
  &lt;td title="click to toggle" class="line_numbers"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;6&lt;tt&gt;
&lt;/tt&gt;7&lt;tt&gt;
&lt;/tt&gt;8&lt;tt&gt;
&lt;/tt&gt;9&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;11&lt;tt&gt;
&lt;/tt&gt;12&lt;tt&gt;
&lt;/tt&gt;13&lt;tt&gt;
&lt;/tt&gt;14&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;15&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;16&lt;tt&gt;
&lt;/tt&gt;17&lt;tt&gt;
&lt;/tt&gt;18&lt;tt&gt;
&lt;/tt&gt;19&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;20&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;21&lt;tt&gt;
&lt;/tt&gt;22&lt;tt&gt;
&lt;/tt&gt;23&lt;tt&gt;
&lt;/tt&gt;24&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;25&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;26&lt;tt&gt;
&lt;/tt&gt;27&lt;tt&gt;
&lt;/tt&gt;28&lt;tt&gt;
&lt;/tt&gt;29&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;30&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;31&lt;tt&gt;
&lt;/tt&gt;32&lt;tt&gt;
&lt;/tt&gt;33&lt;tt&gt;
&lt;/tt&gt;34&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;35&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;36&lt;tt&gt;
&lt;/tt&gt;37&lt;tt&gt;
&lt;/tt&gt;38&lt;tt&gt;
&lt;/tt&gt;39&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;40&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;41&lt;tt&gt;
&lt;/tt&gt;42&lt;tt&gt;
&lt;/tt&gt;43&lt;tt&gt;
&lt;/tt&gt;44&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;45&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;46&lt;tt&gt;
&lt;/tt&gt;47&lt;tt&gt;
&lt;/tt&gt;48&lt;tt&gt;
&lt;/tt&gt;49&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;50&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre&gt;&lt;span class="co"&gt;Index&lt;/span&gt;: lib/scraper/base.rb&lt;tt&gt;
&lt;/tt&gt;===================================================================&lt;tt&gt;
&lt;/tt&gt;--- lib/scraper/base.rb (revision &lt;span class="i"&gt;268&lt;/span&gt;)&lt;tt&gt;
&lt;/tt&gt;+++ lib/scraper/base.rb (working copy)&lt;tt&gt;
&lt;/tt&gt;&lt;span class="er"&gt;@&lt;/span&gt;&lt;span class="er"&gt;@&lt;/span&gt; &lt;span class="i"&gt;-296&lt;/span&gt;,&lt;span class="i"&gt;7&lt;/span&gt; &lt;span class="i"&gt;+296&lt;/span&gt;,&lt;span class="i"&gt;8&lt;/span&gt; &lt;span class="er"&gt;@&lt;/span&gt;&lt;span class="er"&gt;@&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;           extracts.each &lt;span class="r"&gt;do&lt;/span&gt; |extract|&lt;tt&gt;
&lt;/tt&gt;             extract.bind(&lt;span class="pc"&gt;self&lt;/span&gt;).call(element)&lt;tt&gt;
&lt;/tt&gt;           &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;-          &lt;span class="pc"&gt;true&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;+          &lt;span class="c"&gt;#true&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;+          map.keys[&lt;span class="i"&gt;0&lt;/span&gt;]&lt;tt&gt;
&lt;/tt&gt;         &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;       &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt; &lt;tt&gt;
&lt;/tt&gt;&lt;span class="er"&gt;@&lt;/span&gt;&lt;span class="er"&gt;@&lt;/span&gt; &lt;span class="i"&gt;-499&lt;/span&gt;,&lt;span class="i"&gt;6&lt;/span&gt; &lt;span class="i"&gt;+500&lt;/span&gt;,&lt;span class="i"&gt;9&lt;/span&gt; &lt;span class="er"&gt;@&lt;/span&gt;&lt;span class="er"&gt;@&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;           extractor = selector.pop&lt;tt&gt;
&lt;/tt&gt;         &lt;span class="r"&gt;elsif&lt;/span&gt; selector.last.is_a?(&lt;span class="co"&gt;Hash&lt;/span&gt;)&lt;tt&gt;
&lt;/tt&gt;           extractor = extractor(selector.pop)&lt;tt&gt;
&lt;/tt&gt;+        &lt;span class="r"&gt;elsif&lt;/span&gt; selector.last.is_a?(&lt;span class="co"&gt;Symbol&lt;/span&gt;)&lt;tt&gt;
&lt;/tt&gt;+          block_key = selector.pop&lt;tt&gt;
&lt;/tt&gt;+          attr_accessor block_key&lt;tt&gt;
&lt;/tt&gt;         &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;         &lt;span class="r"&gt;if&lt;/span&gt; block &amp;amp;&amp;amp; extractor&lt;tt&gt;
&lt;/tt&gt;           &lt;span class="c"&gt;# Ugly, but no other way to chain two calls bound to the&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="er"&gt;@&lt;/span&gt;&lt;span class="er"&gt;@&lt;/span&gt; &lt;span class="i"&gt;-509&lt;/span&gt;,&lt;span class="i"&gt;11&lt;/span&gt; &lt;span class="i"&gt;+513&lt;/span&gt;,&lt;span class="i"&gt;24&lt;/span&gt; &lt;span class="er"&gt;@&lt;/span&gt;&lt;span class="er"&gt;@&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;           extractor2 = instance_method(&lt;span class="sy"&gt;:__extractor&lt;/span&gt;)&lt;tt&gt;
&lt;/tt&gt;           remove_method &lt;span class="sy"&gt;:__extractor&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;           extractor = lambda &lt;span class="r"&gt;do&lt;/span&gt; |element|&lt;tt&gt;
&lt;/tt&gt;-            extractor1.bind(&lt;span class="pc"&gt;self&lt;/span&gt;).call(element)&lt;tt&gt;
&lt;/tt&gt;+            &lt;span class="c"&gt;#extractor1.bind(self).call(element)&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;+            key = extractor1.bind(&lt;span class="pc"&gt;self&lt;/span&gt;).call(element)&lt;tt&gt;
&lt;/tt&gt;             extractor2.bind(&lt;span class="pc"&gt;self&lt;/span&gt;).call(element)&lt;tt&gt;
&lt;/tt&gt;           &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;         &lt;span class="r"&gt;elsif&lt;/span&gt; block&lt;tt&gt;
&lt;/tt&gt;-          extractor = block&lt;tt&gt;
&lt;/tt&gt;+          &lt;span class="c"&gt;#extractor = block&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;+          operator = &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;+          &lt;span class="r"&gt;if&lt;/span&gt; !&lt;span class="iv"&gt;@arrays&lt;/span&gt;.nil? &lt;span class="r"&gt;and&lt;/span&gt; &lt;span class="iv"&gt;@arrays&lt;/span&gt;.include? block_key.to_sym&lt;tt&gt;
&lt;/tt&gt;+            extractor = lambda &lt;span class="r"&gt;do&lt;/span&gt; |element|&lt;tt&gt;
&lt;/tt&gt;+              send(block_key.to_s+&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;,[]) &lt;span class="r"&gt;if&lt;/span&gt; send(block_key.to_s).nil?&lt;tt&gt;
&lt;/tt&gt;+              send(block_key.to_s+&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, send(block_key.to_s) + [block.call(element)])&lt;tt&gt;
&lt;/tt&gt;+            &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;+          &lt;span class="r"&gt;else&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;+            extractor = lambda &lt;span class="r"&gt;do&lt;/span&gt; |element|&lt;tt&gt;
&lt;/tt&gt;+              send(block_key.to_s+&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, block.call(element))&lt;tt&gt;
&lt;/tt&gt;+            &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;+          &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;         &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;         raise &lt;span class="co"&gt;ArgumentError&lt;/span&gt;, &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;Missing extractor: the last argument tells us what to extract&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class="r"&gt;unless&lt;/span&gt; extractor&lt;tt&gt;
&lt;/tt&gt;         &lt;span class="c"&gt;# And if we think the extractor is the last argument,&lt;/span&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;

&lt;br /&gt;

&lt;b&gt;Fix2:&lt;/b&gt; Struct to Hash conversion
&lt;table class="CodeRay"&gt;&lt;tr&gt;
  &lt;td title="click to toggle" class="line_numbers"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;6&lt;tt&gt;
&lt;/tt&gt;7&lt;tt&gt;
&lt;/tt&gt;8&lt;tt&gt;
&lt;/tt&gt;9&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre&gt;&lt;span class="r"&gt;class&lt;/span&gt; &lt;span class="cl"&gt;Struct&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="r"&gt;def&lt;/span&gt; &lt;span class="fu"&gt;to_hash&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    hash = {}&lt;tt&gt;
&lt;/tt&gt;    members.each &lt;span class="r"&gt;do&lt;/span&gt; |key|&lt;tt&gt;
&lt;/tt&gt;      hash[key.to_sym] = &lt;span class="pc"&gt;self&lt;/span&gt;.send(key)&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    hash&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="r"&gt;end&lt;/span&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;

&lt;br /&gt;

Using above two fixes, my refactored code becomes cleaner and shorter:
&lt;table class="CodeRay"&gt;&lt;tr&gt;
  &lt;td title="click to toggle" class="line_numbers"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;6&lt;tt&gt;
&lt;/tt&gt;7&lt;tt&gt;
&lt;/tt&gt;8&lt;tt&gt;
&lt;/tt&gt;9&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;11&lt;tt&gt;
&lt;/tt&gt;12&lt;tt&gt;
&lt;/tt&gt;13&lt;tt&gt;
&lt;/tt&gt;14&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;15&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;16&lt;tt&gt;
&lt;/tt&gt;17&lt;tt&gt;
&lt;/tt&gt;18&lt;tt&gt;
&lt;/tt&gt;19&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;20&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;21&lt;tt&gt;
&lt;/tt&gt;22&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre&gt;links.each &lt;span class="r"&gt;do&lt;/span&gt; |url|&lt;tt&gt;
&lt;/tt&gt;  nurl = &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;http://www.imdb.com&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; + url&lt;tt&gt;
&lt;/tt&gt;  hash = (&lt;span class="co"&gt;Scraper&lt;/span&gt;.define &lt;span class="r"&gt;do&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    process &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;h5:content('Release Date:')&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class="sy"&gt;:date&lt;/span&gt; &lt;span class="r"&gt;do&lt;/span&gt; |elem|&lt;tt&gt;
&lt;/tt&gt;       date_val = elem.next_sibling.text&lt;tt&gt;
&lt;/tt&gt;       &lt;span class="co"&gt;Date&lt;/span&gt;.parse(date_val[&lt;span class="i"&gt;0&lt;/span&gt;..date_val.rindex(&lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;)||&lt;span class="i"&gt;-1&lt;/span&gt;])&lt;tt&gt;
&lt;/tt&gt;      &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    process &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;div.general&amp;gt;b:content('User Rating:')&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class="sy"&gt;:rating&lt;/span&gt; &lt;span class="r"&gt;do&lt;/span&gt; |elem|&lt;tt&gt;
&lt;/tt&gt;        elem.next_element.text.gsub(&lt;span class="rx"&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;span class="ch"&gt;\/&lt;/span&gt;&lt;span class="k"&gt;.*&lt;/span&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;/span&gt;,&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;)&lt;tt&gt;
&lt;/tt&gt;      &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    process &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;h5:content('Tagline:')&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class="sy"&gt;:tagline&lt;/span&gt; &lt;span class="r"&gt;do&lt;/span&gt; |elem|&lt;tt&gt;
&lt;/tt&gt;        elem.next_sibling.text&lt;tt&gt;
&lt;/tt&gt;      &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    process &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;h1&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class="sy"&gt;:title&lt;/span&gt; &lt;span class="r"&gt;do&lt;/span&gt; |elem|&lt;tt&gt;
&lt;/tt&gt;        elem.text[&lt;span class="i"&gt;0&lt;/span&gt;..(elem.text.rindex(&lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;)||&lt;span class="i"&gt;0&lt;/span&gt;)&lt;span class="i"&gt;-1&lt;/span&gt;].strip&lt;tt&gt;
&lt;/tt&gt;      &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    result &lt;span class="sy"&gt;:date&lt;/span&gt;, &lt;span class="sy"&gt;:rating&lt;/span&gt;, &lt;span class="sy"&gt;:title&lt;/span&gt;, &lt;span class="sy"&gt;:tagline&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="r"&gt;end&lt;/span&gt;).scrape(open(nurl).read)&lt;tt&gt;
&lt;/tt&gt;  object = hash.to_hash&lt;tt&gt;
&lt;/tt&gt;  object[&lt;span class="sy"&gt;:imdb_id&lt;/span&gt;] = url.gsub(&lt;span class="rx"&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;span class="ch"&gt;\/&lt;/span&gt;&lt;span class="k"&gt;title&lt;/span&gt;&lt;span class="ch"&gt;\/&lt;/span&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;/span&gt;,&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;).gsub(&lt;span class="rx"&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;span class="ch"&gt;\/&lt;/span&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;/span&gt;,&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;)&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="co"&gt;Movie&lt;/span&gt;.create(object)&lt;tt&gt;
&lt;/tt&gt;&lt;span class="r"&gt;end&lt;/span&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;

&lt;br /&gt;

&lt;strong&gt;NOTE&lt;/strong&gt;: When you run above code snippets, you will get error "text" not defined for HTML::Tag class. Copy this code in your file, which defines this function for HTML::Text and HTML::Tag class.
&lt;table class="CodeRay"&gt;&lt;tr&gt;
  &lt;td title="click to toggle" class="line_numbers"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;6&lt;tt&gt;
&lt;/tt&gt;7&lt;tt&gt;
&lt;/tt&gt;8&lt;tt&gt;
&lt;/tt&gt;9&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;11&lt;tt&gt;
&lt;/tt&gt;12&lt;tt&gt;
&lt;/tt&gt;13&lt;tt&gt;
&lt;/tt&gt;14&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;15&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;16&lt;tt&gt;
&lt;/tt&gt;17&lt;tt&gt;
&lt;/tt&gt;18&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre&gt;&lt;span class="r"&gt;module&lt;/span&gt; &lt;span class="cl"&gt;HTML&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="r"&gt;class&lt;/span&gt; &lt;span class="cl"&gt;Text&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="r"&gt;def&lt;/span&gt; &lt;span class="fu"&gt;text&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;      &lt;span class="iv"&gt;@content&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="r"&gt;class&lt;/span&gt; &lt;span class="cl"&gt;Tag&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="r"&gt;def&lt;/span&gt; &lt;span class="fu"&gt;text&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;      &lt;span class="r"&gt;return&lt;/span&gt; &lt;span class="iv"&gt;@content&lt;/span&gt; &lt;span class="r"&gt;if&lt;/span&gt; respond_to? &lt;span class="sy"&gt;:content&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;      data=&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;      children.each &lt;span class="r"&gt;do&lt;/span&gt; |child|&lt;tt&gt;
&lt;/tt&gt;        &lt;span class="r"&gt;next&lt;/span&gt; &lt;span class="r"&gt;if&lt;/span&gt; child.respond_to?&lt;span class="sy"&gt;:name&lt;/span&gt; &lt;span class="r"&gt;and&lt;/span&gt; child.name==&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;script&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;        data += child.text&lt;tt&gt;
&lt;/tt&gt;      &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;      data&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="r"&gt;end&lt;/span&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;

&lt;br /&gt;
I wish this is helpful to the Scrapi community.
          </content>  <feedburner:origLink>http://www.quarkruby.com/2008/1/30/scrapi-enhancements</feedburner:origLink></entry>
  <entry xml:base="http://www.quarkruby.com/">
    <author>
      <name>admin</name>
    </author>
    <id>tag:www.quarkruby.com,2008-01-15:1654</id>
    <published>2008-01-15T12:49:00Z</published>
    <updated>2008-01-15T12:54:31Z</updated>
    <category term="ruby" />
    <category term="activeresource" />
    <category term="api" />
    <link href="http://feedproxy.google.com/~r/Quarkruby/~3/W82OtICfzfo/activeresource-and-youtube" rel="alternate" type="text/html" />
    <title>ActiveResource and YouTube</title>
<summary type="html">&lt;p&gt;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. &lt;/p&gt;

&lt;p&gt;Benefits of using our extension to ActiveResource :
&lt;ol&gt;
  &lt;li&gt;ActiveResource provides a ActiveRecord style interface. 
  &lt;li&gt;You can modify our extension according to your interface requirement.
  &lt;li&gt;No not need to use and rely on &lt;a href="http://rubyforge.org/projects/youtube"&gt;Ruby library for YouTube REST API&lt;/a&gt;. 
&lt;/ol&gt;
&lt;/p&gt;</summary><content type="html">
            &lt;p&gt;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. &lt;/p&gt;

&lt;p&gt;Benefits of using our extension to ActiveResource :
&lt;ol&gt;
  &lt;li&gt;ActiveResource provides a ActiveRecord style interface. 
  &lt;li&gt;You can modify our extension according to your interface requirement.
  &lt;li&gt;No not need to use and rely on &lt;a href="http://rubyforge.org/projects/youtube"&gt;Ruby library for YouTube REST API&lt;/a&gt;. 
&lt;/ol&gt;
&lt;/p&gt;

&lt;p&gt;YouTube references
&lt;div class="linkbox"&gt; 
  &lt;a href="http://code.google.com/apis/youtube/developers_guide_protocol.html"&gt;http://code.google.com/apis/youtube/developers_guide_protocol.html&lt;/a&gt;
  &lt;a href="http://code.google.com/apis/youtube/reference.html"&gt;http://code.google.com/apis/youtube/reference.html&lt;/a&gt;
&lt;/div&gt;
&lt;/p&gt;

&lt;b&gt;Note :&lt;/b&gt; The extension is using ActiveResource 2.0.2


&lt;h2&gt;ActiveResource extension&lt;/h2&gt;

&lt;table class="CodeRay"&gt;&lt;tr&gt;
  &lt;td title="click to toggle" class="line_numbers"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;6&lt;tt&gt;
&lt;/tt&gt;7&lt;tt&gt;
&lt;/tt&gt;8&lt;tt&gt;
&lt;/tt&gt;9&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;11&lt;tt&gt;
&lt;/tt&gt;12&lt;tt&gt;
&lt;/tt&gt;13&lt;tt&gt;
&lt;/tt&gt;14&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;15&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;16&lt;tt&gt;
&lt;/tt&gt;17&lt;tt&gt;
&lt;/tt&gt;18&lt;tt&gt;
&lt;/tt&gt;19&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;20&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;21&lt;tt&gt;
&lt;/tt&gt;22&lt;tt&gt;
&lt;/tt&gt;23&lt;tt&gt;
&lt;/tt&gt;24&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;25&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;26&lt;tt&gt;
&lt;/tt&gt;27&lt;tt&gt;
&lt;/tt&gt;28&lt;tt&gt;
&lt;/tt&gt;29&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;30&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;31&lt;tt&gt;
&lt;/tt&gt;32&lt;tt&gt;
&lt;/tt&gt;33&lt;tt&gt;
&lt;/tt&gt;34&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;35&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;36&lt;tt&gt;
&lt;/tt&gt;37&lt;tt&gt;
&lt;/tt&gt;38&lt;tt&gt;
&lt;/tt&gt;39&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;40&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;41&lt;tt&gt;
&lt;/tt&gt;42&lt;tt&gt;
&lt;/tt&gt;43&lt;tt&gt;
&lt;/tt&gt;44&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;45&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;46&lt;tt&gt;
&lt;/tt&gt;47&lt;tt&gt;
&lt;/tt&gt;48&lt;tt&gt;
&lt;/tt&gt;49&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;50&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;51&lt;tt&gt;
&lt;/tt&gt;52&lt;tt&gt;
&lt;/tt&gt;53&lt;tt&gt;
&lt;/tt&gt;54&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;55&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;56&lt;tt&gt;
&lt;/tt&gt;57&lt;tt&gt;
&lt;/tt&gt;58&lt;tt&gt;
&lt;/tt&gt;59&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;60&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;61&lt;tt&gt;
&lt;/tt&gt;62&lt;tt&gt;
&lt;/tt&gt;63&lt;tt&gt;
&lt;/tt&gt;64&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;65&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;66&lt;tt&gt;
&lt;/tt&gt;67&lt;tt&gt;
&lt;/tt&gt;68&lt;tt&gt;
&lt;/tt&gt;69&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;70&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;71&lt;tt&gt;
&lt;/tt&gt;72&lt;tt&gt;
&lt;/tt&gt;73&lt;tt&gt;
&lt;/tt&gt;74&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;75&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre&gt;require &lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;rubygems&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;require &lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;activeresource&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;tt&gt;
&lt;/tt&gt;&lt;span class="r"&gt;class&lt;/span&gt; &lt;span class="cl"&gt;ActiveYouTube&lt;/span&gt; &amp;lt; &lt;span class="co"&gt;ActiveResource&lt;/span&gt;::&lt;span class="co"&gt;Base&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="r"&gt;class&lt;/span&gt; &amp;lt;&amp;lt; &lt;span class="cl"&gt;self&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="c"&gt;## Remove format from the url.&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="r"&gt;def&lt;/span&gt; &lt;span class="fu"&gt;element_path&lt;/span&gt;(id, prefix_options = {}, query_options = &lt;span class="pc"&gt;nil&lt;/span&gt;)&lt;tt&gt;
&lt;/tt&gt;    prefix_options, query_options = split_options(prefix_options) &lt;span class="r"&gt;if&lt;/span&gt; query_options.nil?&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="il"&gt;&lt;span class="dl"&gt;#{&lt;/span&gt;prefix(prefix_options)&lt;span class="dl"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="il"&gt;&lt;span class="dl"&gt;#{&lt;/span&gt;collection_name&lt;span class="dl"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="k"&gt;/&lt;/span&gt;&lt;span class="il"&gt;&lt;span class="dl"&gt;#{&lt;/span&gt;id&lt;span class="dl"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="il"&gt;&lt;span class="dl"&gt;#{&lt;/span&gt;query_string(query_options)&lt;span class="dl"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;tt&gt;
&lt;/tt&gt;  &lt;span class="c"&gt;## Remove format from the url.&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="r"&gt;def&lt;/span&gt; &lt;span class="fu"&gt;collection_path&lt;/span&gt;(prefix_options = {}, query_options = &lt;span class="pc"&gt;nil&lt;/span&gt;)&lt;tt&gt;
&lt;/tt&gt;    prefix_options, query_options = split_options(prefix_options) &lt;span class="r"&gt;if&lt;/span&gt; query_options.nil?&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="il"&gt;&lt;span class="dl"&gt;#{&lt;/span&gt;prefix(prefix_options)&lt;span class="dl"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="il"&gt;&lt;span class="dl"&gt;#{&lt;/span&gt;collection_name&lt;span class="dl"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="il"&gt;&lt;span class="dl"&gt;#{&lt;/span&gt;query_string(query_options)&lt;span class="dl"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="c"&gt;## For a collection call, ActiveResource formatting is not &lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="c"&gt;## compliant with YouTube's output.&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="r"&gt;def&lt;/span&gt; &lt;span class="fu"&gt;instantiate_collection&lt;/span&gt;(collection, prefix_options = {})&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="r"&gt;unless&lt;/span&gt; collection.kind_of? &lt;span class="co"&gt;Array&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;      [instantiate_record(collection, prefix_options)]&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="r"&gt;else&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;      collection.collect! { |record| instantiate_record(record, prefix_options) }&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="c"&gt;## To convert output into proper standard.&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="c"&gt;## If single element is present in output then entry is not an array.&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="c"&gt;## So this method will ensure entry is always an array.&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="r"&gt;alias&lt;/span&gt; &lt;span class="sy"&gt;:old_find&lt;/span&gt; &lt;span class="sy"&gt;:find&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="r"&gt;def&lt;/span&gt; &lt;span class="fu"&gt;find&lt;/span&gt;(*args)&lt;tt&gt;
&lt;/tt&gt;    output=old_find(*args)&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="r"&gt;if&lt;/span&gt; output.respond_to?&lt;span class="sy"&gt;:entry&lt;/span&gt; &lt;span class="r"&gt;and&lt;/span&gt; !(output.entry.kind_of? &lt;span class="co"&gt;Array&lt;/span&gt;)&lt;tt&gt;
&lt;/tt&gt;      output.entry=[output.entry]&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    output&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="c"&gt;## When using ActiveResource::CustomMethods, ActiveResource first tries to retrieve the id using find() &lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="c"&gt;## and then makes a get() call using that id. &lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="c"&gt;## But, youtube returns the url of this item as id, which we don't want. This method overrides the behavior.&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="c"&gt;## Example: comments = Video.find_custom(&amp;quot;ZTUVgYoeN_o&amp;quot;).get(:comments)&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="r"&gt;def&lt;/span&gt; &lt;span class="fu"&gt;find_custom&lt;/span&gt;(arg)&lt;tt&gt;
&lt;/tt&gt;    object = &lt;span class="pc"&gt;self&lt;/span&gt;.new&lt;tt&gt;
&lt;/tt&gt;    object.id = arg&lt;tt&gt;
&lt;/tt&gt;    object&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="c"&gt;##  Following method from ActiveResource::CustomMethods extends the capabilities of activeresource for non-standard urls ;-)&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="c"&gt;##  The objects returned from this method are not automatically converted into ActiveResource instances - they are ordinary Hashes. &lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="c"&gt;##  Modifications below ensures that you get ActiveResource instances.&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="r"&gt;def&lt;/span&gt; &lt;span class="fu"&gt;get&lt;/span&gt;(method_name, options = {})&lt;tt&gt;
&lt;/tt&gt;    object_array = connection.get(custom_method_collection_url(method_name, options), headers)&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="r"&gt;if&lt;/span&gt; object_array.class.to_s==&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;Array&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;      object_array.collect! {|record| &lt;span class="pc"&gt;self&lt;/span&gt;.class.new.load(record)}&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="r"&gt;else&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;      &lt;span class="pc"&gt;self&lt;/span&gt;.class.new.load(object_array)&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="c"&gt;## Instance Methods: (modifying the ActiveRecord::CustomMethods).&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt; &lt;tt&gt;
&lt;/tt&gt;  &lt;span class="c"&gt;## This modification is same as defined in above method &lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="r"&gt;def&lt;/span&gt; &lt;span class="fu"&gt;get&lt;/span&gt;(method_name, options = {})&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="pc"&gt;self&lt;/span&gt;.class.new.load(connection.get(custom_method_element_url(method_name, options), &lt;span class="pc"&gt;self&lt;/span&gt;.class.headers))&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="c"&gt;## Modifying the url formation to make it Youtube API complaint&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="r"&gt;def&lt;/span&gt; &lt;span class="fu"&gt;custom_method_element_url&lt;/span&gt;(method_name, options = {})    &lt;tt&gt;
&lt;/tt&gt;    &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="il"&gt;&lt;span class="dl"&gt;#{&lt;/span&gt;&lt;span class="pc"&gt;self&lt;/span&gt;.class.prefix(prefix_options)&lt;span class="dl"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="il"&gt;&lt;span class="dl"&gt;#{&lt;/span&gt;&lt;span class="pc"&gt;self&lt;/span&gt;.class.collection_name&lt;span class="dl"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="k"&gt;/&lt;/span&gt;&lt;span class="il"&gt;&lt;span class="dl"&gt;#{&lt;/span&gt;id&lt;span class="dl"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="k"&gt;/&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; +&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="il"&gt;&lt;span class="dl"&gt;#{&lt;/span&gt;method_name&lt;span class="dl"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="il"&gt;&lt;span class="dl"&gt;#{&lt;/span&gt;&lt;span class="pc"&gt;self&lt;/span&gt;.class.send!(&lt;span class="sy"&gt;:query_string&lt;/span&gt;, options)&lt;span class="dl"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="r"&gt;end&lt;/span&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;


Points to keep in mind&lt;br /&gt;
 - When using the ActiveResource::CustomMethods (get/post) make sure you are using "find_custom" and not "find" &lt;br /&gt;
 - Disable the logging of ActiveResource, since the following line leads to exception if logger is enabled.
&lt;table class="CodeRay"&gt;&lt;tr&gt;
  &lt;td title="click to toggle" class="line_numbers"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre&gt;&lt;span class="c"&gt;## line 111, connection.rb&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;logger.info &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;--&amp;gt; &lt;/span&gt;&lt;span class="il"&gt;&lt;span class="dl"&gt;#{&lt;/span&gt;result.code&lt;span class="dl"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="k"&gt; &lt;/span&gt;&lt;span class="il"&gt;&lt;span class="dl"&gt;#{&lt;/span&gt;result.message&lt;span class="dl"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="k"&gt; (&lt;/span&gt;&lt;span class="il"&gt;&lt;span class="dl"&gt;#{&lt;/span&gt;result.body ? result.body : &lt;span class="i"&gt;0&lt;/span&gt;&lt;span class="dl"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="k"&gt;b %.2fs)&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; % time &lt;span class="r"&gt;if&lt;/span&gt; logger&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;


&lt;h2&gt;Example usage&lt;/h2&gt;
&lt;table class="CodeRay"&gt;&lt;tr&gt;
  &lt;td title="click to toggle" class="line_numbers"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;6&lt;tt&gt;
&lt;/tt&gt;7&lt;tt&gt;
&lt;/tt&gt;8&lt;tt&gt;
&lt;/tt&gt;9&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;11&lt;tt&gt;
&lt;/tt&gt;12&lt;tt&gt;
&lt;/tt&gt;13&lt;tt&gt;
&lt;/tt&gt;14&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;15&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;16&lt;tt&gt;
&lt;/tt&gt;17&lt;tt&gt;
&lt;/tt&gt;18&lt;tt&gt;
&lt;/tt&gt;19&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;20&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;21&lt;tt&gt;
&lt;/tt&gt;22&lt;tt&gt;
&lt;/tt&gt;23&lt;tt&gt;
&lt;/tt&gt;24&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;25&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;26&lt;tt&gt;
&lt;/tt&gt;27&lt;tt&gt;
&lt;/tt&gt;28&lt;tt&gt;
&lt;/tt&gt;29&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;30&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;31&lt;tt&gt;
&lt;/tt&gt;32&lt;tt&gt;
&lt;/tt&gt;33&lt;tt&gt;
&lt;/tt&gt;34&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;35&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;36&lt;tt&gt;
&lt;/tt&gt;37&lt;tt&gt;
&lt;/tt&gt;38&lt;tt&gt;
&lt;/tt&gt;39&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;40&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;41&lt;tt&gt;
&lt;/tt&gt;42&lt;tt&gt;
&lt;/tt&gt;43&lt;tt&gt;
&lt;/tt&gt;44&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;45&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;46&lt;tt&gt;
&lt;/tt&gt;47&lt;tt&gt;
&lt;/tt&gt;48&lt;tt&gt;
&lt;/tt&gt;49&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;50&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;51&lt;tt&gt;
&lt;/tt&gt;52&lt;tt&gt;
&lt;/tt&gt;53&lt;tt&gt;
&lt;/tt&gt;54&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;55&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;56&lt;tt&gt;
&lt;/tt&gt;57&lt;tt&gt;
&lt;/tt&gt;58&lt;tt&gt;
&lt;/tt&gt;59&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;60&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;61&lt;tt&gt;
&lt;/tt&gt;62&lt;tt&gt;
&lt;/tt&gt;63&lt;tt&gt;
&lt;/tt&gt;64&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;65&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;66&lt;tt&gt;
&lt;/tt&gt;67&lt;tt&gt;
&lt;/tt&gt;68&lt;tt&gt;
&lt;/tt&gt;69&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;70&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;71&lt;tt&gt;
&lt;/tt&gt;72&lt;tt&gt;
&lt;/tt&gt;73&lt;tt&gt;
&lt;/tt&gt;74&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;75&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;76&lt;tt&gt;
&lt;/tt&gt;77&lt;tt&gt;
&lt;/tt&gt;78&lt;tt&gt;
&lt;/tt&gt;79&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;80&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;81&lt;tt&gt;
&lt;/tt&gt;82&lt;tt&gt;
&lt;/tt&gt;83&lt;tt&gt;
&lt;/tt&gt;84&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;85&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;86&lt;tt&gt;
&lt;/tt&gt;87&lt;tt&gt;
&lt;/tt&gt;88&lt;tt&gt;
&lt;/tt&gt;89&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;90&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre&gt;&lt;span class="c"&gt;#### Create classes for YouTube resources.&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="r"&gt;class&lt;/span&gt; &lt;span class="cl"&gt;Video&lt;/span&gt; &amp;lt; &lt;span class="co"&gt;ActiveYouTube&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="pc"&gt;self&lt;/span&gt;.site = &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;http://gdata.youtube.com/feeds/api&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="c"&gt;## To search by categories and tags&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="r"&gt;def&lt;/span&gt; &lt;span class="pc"&gt;self&lt;/span&gt;.search_by_tags (*options)&lt;tt&gt;
&lt;/tt&gt;    from_urls = []&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="r"&gt;if&lt;/span&gt; options.last.is_a? &lt;span class="co"&gt;Hash&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;      excludes = options.slice!(options.length&lt;span class="i"&gt;-1&lt;/span&gt;)&lt;tt&gt;
&lt;/tt&gt;      &lt;span class="r"&gt;if&lt;/span&gt; excludes[&lt;span class="sy"&gt;:exclude&lt;/span&gt;].kind_of? &lt;span class="co"&gt;Array&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;        from_urls &amp;lt;&amp;lt; excludes[&lt;span class="sy"&gt;:exclude&lt;/span&gt;].map{|keyword| &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;-&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;+keyword}.join(&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;/&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;)&lt;tt&gt;
&lt;/tt&gt;      &lt;span class="r"&gt;else&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;        from_urls &amp;lt;&amp;lt; &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;-&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;+excludes[&lt;span class="sy"&gt;:exclude&lt;/span&gt;]&lt;tt&gt;
&lt;/tt&gt;      &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    from_urls &amp;lt;&amp;lt; options.find_all{|keyword| keyword =~ &lt;span class="rx"&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;span class="k"&gt;^[a-z]&lt;/span&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;/span&gt;}.join(&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;/&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;)&lt;tt&gt;
&lt;/tt&gt;    from_urls &amp;lt;&amp;lt; options.find_all{|category| category =~ &lt;span class="rx"&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;span class="k"&gt;^[A-Z]&lt;/span&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;/span&gt;}.join(&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;%7C&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;)&lt;tt&gt;
&lt;/tt&gt;    from_urls.delete_if {|x| x.empty?}&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="pc"&gt;self&lt;/span&gt;.find(&lt;span class="sy"&gt;:all&lt;/span&gt;,&lt;span class="sy"&gt;:from&lt;/span&gt;=&amp;gt;&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;/feeds/api/videos/-/&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;+from_urls.reverse.join(&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;/&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;))&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="r"&gt;class&lt;/span&gt; &lt;span class="cl"&gt;User&lt;/span&gt; &amp;lt; &lt;span class="co"&gt;ActiveYouTube&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="pc"&gt;self&lt;/span&gt;.site = &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;http://gdata.youtube.com/feeds/api&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="r"&gt;class&lt;/span&gt; &lt;span class="cl"&gt;Standardfeed&lt;/span&gt; &amp;lt; &lt;span class="co"&gt;ActiveYouTube&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="pc"&gt;self&lt;/span&gt;.site = &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;http://gdata.youtube.com/feeds/api&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="r"&gt;class&lt;/span&gt; &lt;span class="cl"&gt;Playlist&lt;/span&gt; &amp;lt; &lt;span class="co"&gt;ActiveYouTube&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="pc"&gt;self&lt;/span&gt;.site = &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;http://gdata.youtube.com/feeds/api&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="c"&gt;##### Examples #######&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="c"&gt;#### VIDEO&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="c"&gt;## search for videos&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  search = &lt;span class="co"&gt;Video&lt;/span&gt;.find(&lt;span class="sy"&gt;:first&lt;/span&gt;, &lt;span class="sy"&gt;:params&lt;/span&gt; =&amp;gt; {&lt;span class="sy"&gt;:vq&lt;/span&gt; =&amp;gt; &lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;ruby&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;, &lt;span class="sy"&gt;&lt;span class="sy"&gt;:&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;max-results&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; =&amp;gt; &lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;5&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;})&lt;tt&gt;
&lt;/tt&gt;  puts search.entry.length&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="c"&gt;## video information of id = ZTUVgYoeN_o&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  vid = &lt;span class="co"&gt;Video&lt;/span&gt;.find(&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;ZTUVgYoeN_o&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;)&lt;tt&gt;
&lt;/tt&gt;  puts vid.group.content[&lt;span class="i"&gt;0&lt;/span&gt;].url&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="c"&gt;## video comments&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  comments = &lt;span class="co"&gt;Video&lt;/span&gt;.find_custom(&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;ZTUVgYoeN_o&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;).get(&lt;span class="sy"&gt;:comments&lt;/span&gt;)&lt;tt&gt;
&lt;/tt&gt;  puts comments.entry[&lt;span class="i"&gt;0&lt;/span&gt;].link[&lt;span class="i"&gt;2&lt;/span&gt;].href&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="c"&gt;## searching with category/tags&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  results = &lt;span class="co"&gt;Video&lt;/span&gt;.search_by_tags(&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;Comedy&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;)&lt;tt&gt;
&lt;/tt&gt;  puts results[&lt;span class="i"&gt;0&lt;/span&gt;].entry[&lt;span class="i"&gt;0&lt;/span&gt;].title&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="c"&gt;# more examples:&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="c"&gt;# Video.search_by_tags(&amp;quot;Comedy&amp;quot;, &amp;quot;dog&amp;quot;)&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="c"&gt;# Video.search_by_tags(&amp;quot;News&amp;quot;,&amp;quot;Sports&amp;quot;,&amp;quot;football&amp;quot;, :exclude=&amp;gt;[&amp;quot;Comedy&amp;quot;,&amp;quot;soccer&amp;quot;])&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="c"&gt;# Video.search_by_tags(&amp;quot;News&amp;quot;,&amp;quot;Sports&amp;quot;,&amp;quot;football&amp;quot;, :exclude=&amp;gt;&amp;quot;soccer&amp;quot;)&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="c"&gt;#### STANDARDFEED&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="c"&gt;## retrieving standard feeds&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  most_viewed = &lt;span class="co"&gt;Standardfeed&lt;/span&gt;.find(&lt;span class="sy"&gt;:most_viewed&lt;/span&gt;, &lt;span class="sy"&gt;:params&lt;/span&gt; =&amp;gt; {&lt;span class="sy"&gt;:time&lt;/span&gt; =&amp;gt; &lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;today&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;})&lt;tt&gt;
&lt;/tt&gt;  puts most_viewed.entry[&lt;span class="i"&gt;0&lt;/span&gt;].group.content[&lt;span class="i"&gt;0&lt;/span&gt;].url&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="c"&gt;#### USER&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="c"&gt;## user's profile - guthrie&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  user_profile = &lt;span class="co"&gt;User&lt;/span&gt;.find(&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;guthrie&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;)&lt;tt&gt;
&lt;/tt&gt;  puts user_profile.link[&lt;span class="i"&gt;1&lt;/span&gt;].href&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="c"&gt;## user's playlist - john&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  user_playlist = &lt;span class="co"&gt;User&lt;/span&gt;.find_custom(&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;john&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;).get(&lt;span class="sy"&gt;:playlists&lt;/span&gt;)&lt;tt&gt;
&lt;/tt&gt;  puts user_playlist.link[&lt;span class="i"&gt;1&lt;/span&gt;].href&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="c"&gt;## user's upload or favorites&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  rick_video = &lt;span class="co"&gt;User&lt;/span&gt;.find_custom(&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;rick&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;).get(&lt;span class="sy"&gt;:uploads&lt;/span&gt;)&lt;tt&gt;
&lt;/tt&gt;  puts rick_video.entry[&lt;span class="i"&gt;0&lt;/span&gt;].group.content[&lt;span class="i"&gt;0&lt;/span&gt;].url&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="c"&gt;## user's subscription&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  user_subscriptions = &lt;span class="co"&gt;User&lt;/span&gt;.find_custom(&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;guthrie&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;).get(&lt;span class="sy"&gt;:subscriptions&lt;/span&gt;)&lt;tt&gt;
&lt;/tt&gt;  puts user_subscriptions.to_yaml&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="c"&gt;#### PLAYLIST&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="c"&gt;## get playlist - multiple elements in playlist&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  playlist = &lt;span class="co"&gt;Playlist&lt;/span&gt;.find(&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;EBF5D6DC4589D7B7&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;)&lt;tt&gt;
&lt;/tt&gt;  puts playlist.entry[&lt;span class="i"&gt;0&lt;/span&gt;].group.content[&lt;span class="i"&gt;0&lt;/span&gt;].url&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="c"&gt;## get playlist - single element in playlist&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  playlist = &lt;span class="co"&gt;Playlist&lt;/span&gt;.find(&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;45C563323B344971&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;)&lt;tt&gt;
&lt;/tt&gt;  puts playlist.entry[&lt;span class="i"&gt;0&lt;/span&gt;].group.content[&lt;span class="i"&gt;0&lt;/span&gt;].url&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
          </content>  <feedburner:origLink>http://www.quarkruby.com/2008/1/15/activeresource-and-youtube</feedburner:origLink></entry>
  <entry xml:base="http://www.quarkruby.com/">
    <author>
      <name>admin</name>
    </author>
    <id>tag:www.quarkruby.com,2008-01-07:1337</id>
    <published>2008-01-07T17:25:00Z</published>
    <updated>2008-01-07T17:26:42Z</updated>
    <category term="tutorials" />
    <category term="javascript" />
    <category term="widget" />
    <link href="http://feedproxy.google.com/~r/Quarkruby/~3/_t-CDvF-dUQ/widget" rel="alternate" type="text/html" />
    <title>Writing a web widget</title>
<summary type="html">&lt;p&gt;Web widgets are widely used across the Internet but still lacks good documentation. From online advertisement to videos to blogs, widgets are highly used. Some of the popular widgets being Google Adsense, Youtube, MyBlogLog widgets and Twitter badges.&lt;/p&gt;

&lt;p&gt;&lt;i&gt;Note:&lt;/i&gt; This page will be slow to load because of many widget examples.&lt;/p&gt;

&lt;h2&gt;Table of Contents &lt;/h2&gt;
&lt;ol&gt;
   &lt;li&gt;&lt;a href="#before"&gt;Before you start&lt;/a&gt;
   &lt;li&gt;&lt;a href="#flash"&gt;Flash widget&lt;/a&gt;
   &lt;li&gt;&lt;a href="#htmlwidget"&gt;HTML widget&lt;/a&gt;
   &lt;li&gt;&lt;a href="#javascriptwidget"&gt;JavaScript widget&lt;/a&gt;
      &lt;ol&gt;
        &lt;li&gt;&lt;a href="#passivewidget"&gt;Passive widgets&lt;/a&gt;
        &lt;li&gt;&lt;a href="#activewidget"&gt;Active widgets&lt;/a&gt;
      &lt;/ol&gt;
   &lt;li&gt;&lt;a href="#examples"&gt;Examples&lt;/a&gt;
   &lt;li&gt;&lt;a href="#keyissues"&gt;Key issues&lt;/a&gt;
&lt;/ol&gt;

&lt;br /&gt;
&lt;p&gt;To formally define : &lt;i&gt;The web widget is a portable chunk of code that can be installed and executed within any separate HTML-based web page by an end user without requiring additional compilation. A widget adds some content to that page that is (mostly) not static. Generally widgets are third party originated, though they can be home made. Widgets are also known as modules, snippets, and plug-ins.&lt;/i&gt;&lt;/p&gt;

&lt;p&gt;This article is my journey of understanding and making a widget myself. I have tried to make things look simple and insightful by taking a lot of examples.&lt;/p&gt;</summary><content type="html">
            &lt;p&gt;Web widgets are widely used across the Internet but still lacks good documentation. From online advertisement to videos to blogs, widgets are highly used. Some of the popular widgets being Google Adsense, Youtube, MyBlogLog widgets and Twitter badges.&lt;/p&gt;

&lt;p&gt;&lt;i&gt;Note:&lt;/i&gt; This page will be slow to load because of many widget examples.&lt;/p&gt;

&lt;h2&gt;Table of Contents &lt;/h2&gt;
&lt;ol&gt;
   &lt;li&gt;&lt;a href="#before"&gt;Before you start&lt;/a&gt;
   &lt;li&gt;&lt;a href="#flash"&gt;Flash widget&lt;/a&gt;
   &lt;li&gt;&lt;a href="#htmlwidget"&gt;HTML widget&lt;/a&gt;
   &lt;li&gt;&lt;a href="#javascriptwidget"&gt;JavaScript widget&lt;/a&gt;
      &lt;ol&gt;
        &lt;li&gt;&lt;a href="#passivewidget"&gt;Passive widgets&lt;/a&gt;
        &lt;li&gt;&lt;a href="#activewidget"&gt;Active widgets&lt;/a&gt;
      &lt;/ol&gt;
   &lt;li&gt;&lt;a href="#examples"&gt;Examples&lt;/a&gt;
   &lt;li&gt;&lt;a href="#keyissues"&gt;Key issues&lt;/a&gt;
&lt;/ol&gt;

&lt;br /&gt;
&lt;p&gt;To formally define : &lt;i&gt;The web widget is a portable chunk of code that can be installed and executed within any separate HTML-based web page by an end user without requiring additional compilation. A widget adds some content to that page that is (mostly) not static. Generally widgets are third party originated, though they can be home made. Widgets are also known as modules, snippets, and plug-ins.&lt;/i&gt;&lt;/p&gt;

&lt;p&gt;This article is my journey of understanding and making a widget myself. I have tried to make things look simple and insightful by taking a lot of examples.&lt;/p&gt;

&lt;a&gt;&lt;/a&gt;
&lt;h2&gt;Before you start&lt;/h2&gt;
&lt;p&gt;Clearly identify the information which will be distributed by your widget or the information you would like your client to embed in their webpage. Then find the most suitable mechanism to send this information. Mechanism can be one of the following :
&lt;ul&gt;
&lt;li&gt;Flash (need not be static i.e. it can take parameters) as a widget.&lt;/li&gt;
&lt;li&gt;Simple HTML page&lt;/li&gt;
&lt;li&gt;JavaScript&lt;/li&gt;
&lt;li&gt;JSON API&lt;/li&gt;
&lt;/ul&gt;
&lt;/p&gt;


&lt;a&gt;&lt;/a&gt;
&lt;h2&gt;Flash widget&lt;/h2&gt;
&lt;p&gt;This is a highly used method for making widgets. Most of the flashy irritating advertisements seen on many websites are flash widgets. A good usage being &lt;a href="#youtube"&gt;youtube&lt;/a&gt; videos and &lt;a href="#twitter-badge-1"&gt;twitter badge type-1&lt;/a&gt;. Flash widget code includes an "embed" or "object" HTML tag with the source to flash file. Extra parameters may be passed to flash file to customize flash content. And remember, ActionScript is always there for more magic :-)&lt;/p&gt;


&lt;a&gt;&lt;/a&gt;
&lt;h2&gt;HTML widget&lt;/h2&gt;
Instead of flash embed an HTML page or HTML code at client's webpage using iframe.&lt;br /&gt;
&lt;span class="widget-code-header"&gt;This can be as simple as:&lt;/span&gt;&lt;br /&gt;
&lt;table class="CodeRay"&gt;&lt;tr&gt;
  &lt;td title="click to toggle" class="line_numbers"&gt;&lt;pre&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre&gt;&lt;span class="ta"&gt;&amp;lt;iframe&lt;/span&gt; &lt;span class="an"&gt;src&lt;/span&gt;=&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;http://www.google.com&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;  &lt;span class="an"&gt;height&lt;/span&gt;=&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;100px&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class="an"&gt;width&lt;/span&gt;=&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;90%&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class="an"&gt;frameborder&lt;/span&gt;=&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;0&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class="ta"&gt;&amp;gt;&lt;/span&gt;&lt;span class="ta"&gt;&amp;lt;/iframe&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;

Mostly used when content is static for all users (like brand advertisements). Flash and HTML widgets are the most simplest to develop but can be of limited use in many cases.


&lt;a&gt;&lt;/a&gt;
&lt;h2&gt;JavaScript widget&lt;/h2&gt;
JavaScript is the most powerful tool to make widgets. Top examples being, &lt;a href="#googleadsense"&gt;Google Adsense&lt;/a&gt; and &lt;a href="#mybloglog"&gt;MyBlogLog recent visitors&lt;/a&gt; widget. There are two ways to develop widgets via scripting:&lt;br /&gt;
&lt;ol&gt;
&lt;a&gt;&lt;/a&gt;
 &lt;li&gt;&lt;b&gt;Passive widget&lt;/b&gt; : The widget code is a script tag which links to external JavaScript file and this file has the code to directly print the HTML markup on client's webpage. &lt;a href="#aiderss"&gt;AideRSS&lt;/a&gt; provides a passive widget.&lt;br /&gt;
&lt;span class="widget-code-header"&gt;For example::&lt;/span&gt;
&lt;table class="CodeRay"&gt;&lt;tr&gt;
  &lt;td title="click to toggle" class="line_numbers"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre&gt;&lt;span class="c"&gt;// widget code&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&amp;lt;script src=&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;http://www.quarkruby.com/assets/script-raw-dump.js&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;


&lt;table class="CodeRay"&gt;&lt;tr&gt;
  &lt;td title="click to toggle" class="line_numbers"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;6&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre&gt;&lt;span class="c"&gt;// script-raw-dump.js contains the following code&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="pt"&gt;document&lt;/span&gt;.write(&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;&amp;lt;ul&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;);&lt;tt&gt;
&lt;/tt&gt;&lt;span class="pt"&gt;document&lt;/span&gt;.write(&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;&amp;lt;li&amp;gt;Hello world&amp;lt;/li&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;);&lt;tt&gt;
&lt;/tt&gt;&lt;span class="pt"&gt;document&lt;/span&gt;.write(&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;&amp;lt;li&amp;gt;Hello world2&amp;lt;/li&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;);&lt;tt&gt;
&lt;/tt&gt;&lt;span class="pt"&gt;document&lt;/span&gt;.write(&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;&amp;lt;/ul&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;);&lt;tt&gt;
&lt;/tt&gt;&lt;span class="pt"&gt;document&lt;/span&gt;.write(&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;Powered by &amp;lt;img src='quarkruby' alt='quarkruby'/&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;);&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;

Output seen on webpage will be:
&lt;div class="widget-output"&gt;
&lt;/div&gt;
&lt;/li&gt;

&lt;br /&gt;
&lt;a&gt;&lt;/a&gt;
&lt;li&gt;&lt;b&gt;Active widget&lt;/b&gt; : As the name says, they do work/processing/calculations before just printing HTML code. The widget  code contains a script tag to download one or more external JavaScript files, which does work &lt;i&gt;(getting client information, passing information around, etc.)&lt;/i&gt; and then HTML is dumped at client side. Google adsense, Mybloglog's widget all fall in this category.&lt;br /&gt;&lt;br /&gt;

&lt;p&gt;Active widgets can be very powerful if, each client is given a unique identifier by the widget source for user identification. This allows widget providing site to send/collect user-related data. Active widget's can be made in two ways :
&lt;/p&gt;
  &lt;ol&gt;
    &lt;li&gt;&lt;b&gt;Using simple JavaScript&lt;/b&gt;&lt;br /&gt;
&lt;span class="widget-code-header"&gt;Sample widget code:&lt;/span&gt;
&lt;table class="CodeRay"&gt;&lt;tr&gt;
  &lt;td title="click to toggle" class="line_numbers"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre&gt;&lt;span class="ta"&gt;&amp;lt;script&lt;/span&gt; &lt;span class="an"&gt;type&lt;/span&gt;=&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;text/javascript&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class="ta"&gt;&amp;gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;unique_key_each_host = &amp;quot;quarkruby_123&amp;quot;;&lt;tt&gt;
&lt;/tt&gt;// some other variables ..&lt;tt&gt;
&lt;/tt&gt;&lt;span class="ta"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="ta"&gt;&amp;lt;script&lt;/span&gt; &lt;span class="an"&gt;src&lt;/span&gt;=&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;http://www.quarkruby.com/assets/static-javascript-variable.js&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class="ta"&gt;&amp;gt;&lt;/span&gt;&lt;span class="ta"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;

What the code does: &lt;br /&gt;
- Get the JavaScript as mentioned in last line above &lt;br /&gt;
- This JavaScript file when executed, will read the values of above defined variables + possibly collect other information&lt;br /&gt;
&lt;span class="widget-code-header"&gt;A sample of static-javascript-variable.js:&lt;/span&gt;
&lt;table class="CodeRay"&gt;&lt;tr&gt;
  &lt;td title="click to toggle" class="line_numbers"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;6&lt;tt&gt;
&lt;/tt&gt;7&lt;tt&gt;
&lt;/tt&gt;8&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre&gt;&lt;span class="c"&gt;// static-javascript-variable.js contains the following code&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;(&lt;span class="r"&gt;function&lt;/span&gt;(){&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="r"&gt;var&lt;/span&gt; url = &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;http://www.quarkruby.com/show_data&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="r"&gt;var&lt;/span&gt; current_location = &lt;span class="pt"&gt;window&lt;/span&gt;.location.hostname;&lt;tt&gt;
&lt;/tt&gt;  url += &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;?&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; + &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;host=&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; + current_location + &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;&amp;amp;width=&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;+200 + &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;&amp;amp;key=&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;+unique_key_each_host;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="c"&gt;// sample url generated : http://www.quarkruby.com/show_data?host=quarkruby.com&amp;amp;width=200&amp;amp;key=quarkruby_123&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="pt"&gt;document&lt;/span&gt;.write(&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;&amp;lt;iframe src='&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; + url + &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;'&amp;gt;&amp;lt;/iframe&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;);&lt;tt&gt;
&lt;/tt&gt;})()&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;

This creates an iframe element at client's webpage and set the source to an external url (defined in static-javascript-variable.js file) passing above calculated parameters. The output fetched is an HTML page which is inserted iframe created in last line of code&lt;br /&gt;
    &lt;/li&gt;
&lt;br /&gt;

    &lt;li&gt;&lt;b&gt;JSON widget&lt;/b&gt;&lt;br /&gt;
For using JSON API's or JSON data. &lt;a href="#twitter-badge-2"&gt;Twitter badge type 2&lt;/a&gt; is a good example of widget using JSON calls. &lt;br /&gt; &lt;span class="widget-code-header"&gt;Sample Widget code:&lt;/span&gt;
&lt;table class="CodeRay"&gt;&lt;tr&gt;
  &lt;td title="click to toggle" class="line_numbers"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre&gt;&amp;lt;div id=&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;quarkruby_widget&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&amp;gt;&amp;lt;/div&amp;gt;&lt;tt&gt;
&lt;/tt&gt;&amp;lt;script &lt;span class="r"&gt;type&lt;/span&gt;=&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;text/javascript&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; src=&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;http://www.quarkruby.com/js/static-javascript-dom.js&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;tt&gt;
&lt;/tt&gt;&amp;lt;script text=&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;text/javascript&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; src=&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;http://www.quarkruby.com/js/json-data-callback.js&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;

Explanation :&lt;br /&gt;
- Download the script files mentioned in last 2 lines. The latter one fetches the JSON data and calls the callback function.&lt;br /&gt;
&lt;table class="CodeRay"&gt;&lt;tr&gt;
  &lt;td title="click to toggle" class="line_numbers"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;6&lt;tt&gt;
&lt;/tt&gt;7&lt;tt&gt;
&lt;/tt&gt;8&lt;tt&gt;
&lt;/tt&gt;9&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre&gt; &lt;span class="c"&gt;// sample static-javascript-dom.js file &lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="r"&gt;function&lt;/span&gt; printHelloWorld(args) {&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="r"&gt;var&lt;/span&gt; outputhtml = &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;&amp;lt;h3&amp;gt;List of Visitors: &amp;lt;/h3&amp;gt;&amp;lt;ul&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;;&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="r"&gt;for&lt;/span&gt;(&lt;span class="r"&gt;var&lt;/span&gt; x=0;x&amp;lt;args.length;x++) {outputhtml += &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;&amp;lt;li&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; + args[i]+&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;&amp;lt;/li&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;);}&lt;tt&gt;
&lt;/tt&gt;    outputhtml += &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;&amp;lt;/ul&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;;&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="pt"&gt;document&lt;/span&gt;.getElementById(&lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;quarkruby_widget&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;).innerHTML = outputhtml;&lt;tt&gt;
&lt;/tt&gt;  }&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="c"&gt;//sample json-data-callback.js&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  printHelloWorld([&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;Nakul&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;Ritesh&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;]);&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;

- The first JavaScript contains the callback function definition (possibly other functions also). These will process the JSON data, generate HTML code and insert into DOM at "#quarkruby_widget" element using innerHTML method or DOM manipulation by creating/adding/appending elements.&lt;br /&gt;
    &lt;/li&gt;
  &lt;/ol&gt;

&lt;/li&gt;
&lt;/ol&gt;


&amp;lt;!-- Examples --&gt;
&lt;a&gt;&lt;/a&gt;
&lt;h2&gt;Examples&lt;/h2&gt;
&lt;ol&gt;

&lt;a&gt;&lt;/a&gt;
&lt;li&gt;&lt;b&gt;Youtube&lt;/b&gt;
&lt;br /&gt;&lt;span class="widget-code-header"&gt;Widget code :&lt;/span&gt;
&lt;table class="CodeRay"&gt;&lt;tr&gt;
  &lt;td title="click to toggle" class="line_numbers"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre&gt;&amp;lt;object width=&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;425&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; height=&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;355&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&amp;gt;&lt;tt&gt;
&lt;/tt&gt;  &amp;lt;param name=&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;movie&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; value=&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;http://www.youtube.com/v/dMH0bHeiRNg&amp;amp;rel=1&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&amp;gt;&amp;lt;/param&amp;gt;&lt;tt&gt;
&lt;/tt&gt;  &amp;lt;param name=&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;wmode&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; value=&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;transparent&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&amp;gt;&amp;lt;/param&amp;gt;&lt;tt&gt;
&lt;/tt&gt;  &amp;lt;embed src=&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;http://www.youtube.com/v/dMH0bHeiRNg&amp;amp;rel=1&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class="r"&gt;type&lt;/span&gt;=&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;application/x-shockwave-flash&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; wmode=&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;transparent&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; width=&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;425&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; height=&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;355&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&amp;gt;&amp;lt;/embed&amp;gt;&lt;tt&gt;
&lt;/tt&gt;&amp;lt;/object&amp;gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;

 - Here, a static youtube video is loaded in flash player.&lt;br /&gt;&lt;br /&gt;
Output :&lt;br /&gt;
&amp;lt;object height="355" width="425"&gt;&amp;lt;param&gt;&amp;lt;/param&gt;&amp;lt;param&gt;&amp;lt;/param&gt;&amp;lt;embed src="http://www.youtube.com/v/qbO1zNglwvY&amp;amp;rel=1" height="355" width="425"&gt;&amp;lt;/embed&gt;&amp;lt;/object&gt;
&lt;/li&gt;


&lt;a&gt;&lt;/a&gt;
&lt;li&gt;&lt;b&gt;Twitter Flash widget&lt;/b&gt;
&lt;br /&gt;&lt;span class="widget-code-header"&gt;Widget code :&lt;/span&gt;
&lt;table class="CodeRay"&gt;&lt;tr&gt;
  &lt;td title="click to toggle" class="line_numbers"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;6&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre&gt;&amp;lt;div style=&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;width:176px;text-align:center&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&amp;gt;&lt;tt&gt;
&lt;/tt&gt;  &amp;lt;embed src=&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;http://twitter.com/flash/twitter_badge.swf&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;  flashvars=&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;color1=16594585&amp;amp;type=user&amp;amp;id=8484232&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;  quality=&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;high&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; width=&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;176&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; height=&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;176&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; name=&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;twitter_badge&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; align=&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;middle&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; allowScriptAccess=&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;always&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; wmode=&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;transparent&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class="r"&gt;type&lt;/span&gt;=&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;application/x-shockwave-flash&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; pluginspage=&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;http://www.macromedia.com/go/getflashplayer&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; /&amp;gt;&lt;tt&gt;
&lt;/tt&gt;  &amp;lt;br&amp;gt;&lt;tt&gt;
&lt;/tt&gt;  &amp;lt;a style=&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;font-size: 10px; color: #FD3699; text-decoration: none&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; href=&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;http://twitter.com/nakula&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&amp;gt;follow nakula at http://twitter.com&amp;lt;/a&amp;gt;&lt;tt&gt;
&lt;/tt&gt;&amp;lt;/div&amp;gt;&lt;tt&gt;
&lt;/tt&gt;&amp;lt;br/&amp;gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;

 - This embeds a flash file passing it &lt;i&gt;color of widget, user_id&lt;/i&gt; as variables. So, after flash file is loaded, it makes request for user specific data (mentioned in &lt;i&gt;user_id&lt;/i&gt; variable) and loads it later.&lt;br /&gt;&lt;br /&gt;
Output :&lt;br /&gt;
&lt;div&gt;&amp;lt;embed src="http://twitter.com/flash/twitter_badge.swf" height="176" width="176" /&gt;&lt;br&gt;&lt;a href="http://twitter.com/nakula"&gt;follow nakula at http://twitter.com&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
&lt;/li&gt;


&lt;a&gt;&lt;/a&gt;
&lt;li&gt;&lt;b&gt;AideRSS&lt;/b&gt;
&lt;br /&gt;&lt;span class="widget-code-header"&gt;Widget code :&lt;/span&gt;
&lt;table class="CodeRay"&gt;&lt;tr&gt;
  &lt;td title="click to toggle" class="line_numbers"&gt;&lt;pre&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre&gt;&amp;lt;script src=&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;http://www.aiderss.com/widget/top_content/year/100&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class="r"&gt;type&lt;/span&gt;=&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;text/javascript&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;

Here the widget codes gets the JavaScript, which directly does a &lt;i&gt;document.write&lt;/i&gt; at client's webpage.&lt;br /&gt;&lt;br /&gt;
Output :&lt;br /&gt;
&lt;div class="widget-output"&gt;
&lt;/div&gt;
&lt;/li&gt;


&lt;a&gt;&lt;/a&gt;
&lt;li&gt;&lt;b&gt;Google Adsense&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;
This is one of those widget which gathers a lot of information before it generates output. 
&lt;span class="widget-code-header"&gt;Widget code :&lt;/span&gt;
&lt;table class="CodeRay"&gt;&lt;tr&gt;
  &lt;td title="click to toggle" class="line_numbers"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;6&lt;tt&gt;
&lt;/tt&gt;7&lt;tt&gt;
&lt;/tt&gt;8&lt;tt&gt;
&lt;/tt&gt;9&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;11&lt;tt&gt;
&lt;/tt&gt;12&lt;tt&gt;
&lt;/tt&gt;13&lt;tt&gt;
&lt;/tt&gt;14&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;15&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre&gt;&lt;span class="ta"&gt;&amp;lt;script&lt;/span&gt; &lt;span class="an"&gt;type&lt;/span&gt;=&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;text/javascript&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class="ta"&gt;&amp;gt;&lt;/span&gt;&lt;span class="c"&gt;&amp;lt;!--&lt;tt&gt;
&lt;/tt&gt;google_ad_client = &amp;quot;pub-xyzvalue&amp;quot;;&lt;tt&gt;
&lt;/tt&gt;google_alternate_color = &amp;quot;FFFFFF&amp;quot;;&lt;tt&gt;
&lt;/tt&gt;google_ad_width = 468;&lt;tt&gt;
&lt;/tt&gt;google_ad_height = 60;&lt;tt&gt;
&lt;/tt&gt;google_ad_format = &amp;quot;468x60_as&amp;quot;;&lt;tt&gt;
&lt;/tt&gt;google_ad_type = &amp;quot;text&amp;quot;;&lt;tt&gt;
&lt;/tt&gt;google_ad_channel = &amp;quot;&amp;quot;;&lt;tt&gt;
&lt;/tt&gt;google_color_border = &amp;quot;FFFFFF&amp;quot;;&lt;tt&gt;
&lt;/tt&gt;google_color_bg = &amp;quot;FFFFFF&amp;quot;;&lt;tt&gt;
&lt;/tt&gt;google_color_link = &amp;quot;000000&amp;quot;;&lt;tt&gt;
&lt;/tt&gt;google_color_text = &amp;quot;333333&amp;quot;;&lt;tt&gt;
&lt;/tt&gt;google_color_url = &amp;quot;666666&amp;quot;;&lt;tt&gt;
&lt;/tt&gt;//--&amp;gt;&lt;/span&gt;&lt;span class="ta"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="ta"&gt;&amp;lt;script&lt;/span&gt; &lt;span class="an"&gt;src&lt;/span&gt;=&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;http://pagead2.googlesyndication.com/pagead/show_ads.js&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class="ta"&gt;&amp;gt;&lt;/span&gt;&lt;span class="ta"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;


It works as follows:&lt;br /&gt;
&lt;ol&gt;
&lt;li&gt;Fetches the JavaScript file mentioned in last line.
&lt;li&gt;This file then uses the defined parameters and gathers value for hidden parameters (so that resulting ads are more local and content specific).
&lt;li&gt;Finally creates an iframe element at client's webpage and set the source to the external url passing above calculated parameters. The output is an HTML page which is inserted into this iframe.
&lt;/ol&gt;
&lt;/li&gt;


&lt;a&gt;&lt;/a&gt;
&lt;li&gt;&lt;b&gt;Twitter badge type2&lt;/b&gt;
&lt;br /&gt;&lt;span class="widget-code-header"&gt;Widget code :&lt;/span&gt;
&lt;table class="CodeRay"&gt;&lt;tr&gt;
  &lt;td title="click to toggle" class="line_numbers"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre&gt;&amp;lt;div id=&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;twitter_div&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&amp;gt;&lt;tt&gt;
&lt;/tt&gt;&amp;lt;h2 &lt;span class="r"&gt;class&lt;/span&gt;=&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;twitter-title&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&amp;gt;Twitter Updates&amp;lt;/h2&amp;gt;&lt;tt&gt;
&lt;/tt&gt;&amp;lt;ul id=&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;twitter_update_list&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&amp;gt;&amp;lt;/ul&amp;gt;&amp;lt;/div&amp;gt;&lt;tt&gt;
&lt;/tt&gt;&amp;lt;script &lt;span class="r"&gt;type&lt;/span&gt;=&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;text/javascript&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; src=&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;http://twitter.com/javascripts/blogger.js&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;tt&gt;
&lt;/tt&gt;&amp;lt;script text=&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;text/javascript&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; src=&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;http://twitter.com/statuses/user_timeline/username.json?callback=twitterCallback2&amp;amp;count=5&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;

The second JavaScript link is the JSON call to their API, which fetches the JSON data and calls back "twitterCallback2" function which is defined in blogger.js file. Then blogger.js downloads the JavaScript code which processes the JSON data and inserts the final output into "twitter_div" element. &lt;br /&gt;&lt;br /&gt;
Output :&lt;br /&gt;
&lt;div class="widget-output"&gt;
&lt;div&gt;
&lt;span class="twitter-title"&gt;Twitter Updates&lt;/span&gt;
&lt;ul&gt;&lt;/ul&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/li&gt;


&lt;a&gt;&lt;/a&gt;
&lt;li&gt;&lt;b&gt;Amazon&lt;/b&gt;
&lt;br /&gt;&lt;span class="widget-code-header"&gt;Widget code :&lt;/span&gt;
&lt;table class="CodeRay"&gt;&lt;tr&gt;
  &lt;td title="click to toggle" class="line_numbers"&gt;&lt;pre&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre&gt;&amp;lt;SCRIPT charset=&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;utf-8&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class="r"&gt;type&lt;/span&gt;=&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;text/javascript&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; src=&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;http://ws.amazon.com/widgets/q?ServiceVersion=20070822&amp;amp;MarketPlace=US&amp;amp;ID=V20070822/US/xyz/8001/f5c7593b-5be8-4c15-345d-e8f70675f476&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&amp;gt; &amp;lt;/SCRIPT&amp;gt; &amp;lt;NOSCRIPT&amp;gt;&amp;lt;A HREF=&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;http://ws.amazon.com/widgets/q?ServiceVersion=20070822&amp;amp;MarketPlace=US&amp;amp;ID=V20070822%2FUS%2Fxyz-20%2F8001%2Ff5c75233b-5be8-4c15-916d-e8f70675f476&amp;amp;Operation=NoScript&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&amp;gt;Amazon.com Widgets&amp;lt;/A&amp;gt;&amp;lt;/NOSCRIPT&amp;gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;

The JavaScript file mentioned in script tag is fetched which contains the JSON data + link to more JavaScript files. These additional JavaScript files are fetched and then JSON data is processed and using DOM manipulation output is inserted into webpage. &lt;br /&gt;&lt;br /&gt;
Output :&lt;br /&gt;
&amp;lt;noscript&gt;&lt;a href="http://ws.amazon.com/widgets/q?ServiceVersion=20070822&amp;amp;MarketPlace=US&amp;amp;ID=V20070822%2FUS%2Fcomparisons0b-20%2F8001%2Ff5c7593b-5be8-4c15-916d-e8f70675f476&amp;amp;Operation=NoScript"&gt;Amazon.com Widgets&lt;/a&gt;&amp;lt;/noscript&gt;&lt;br /&gt;
&lt;/li&gt;


&lt;a&gt;&lt;/a&gt;
&lt;li&gt;&lt;b&gt;MyBloglog recent visitors widget&lt;/b&gt;
&lt;br /&gt;&lt;span class="widget-code-header"&gt;Widget code :&lt;/span&gt;
&lt;table class="CodeRay"&gt;&lt;tr&gt;
  &lt;td title="click to toggle" class="line_numbers"&gt;&lt;pre&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre&gt;&amp;lt;script &lt;span class="r"&gt;type&lt;/span&gt;=&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;text/javascript&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; src=&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;http://pub.mybloglog.com/comm2.php?mblID=2007123816343566&amp;amp;c_width=180&amp;amp;c_sn_opt=y&amp;amp;c_rows=5&amp;amp;c_img_size=f&amp;amp;c_heading_text=Recent+Readers&amp;amp;c_color_heading_bg=005A94&amp;amp;c_color_heading=ffffff&amp;amp;c_color_link_bg=E3E3E3&amp;amp;c_color_link=005A94&amp;amp;c_color_bottom_bg=005A94&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;

 - Fetch this file, which generates HTML code + CSS data for the final output &lt;br /&gt;
 - Fetch one more JavaScript file linked in the above mentioned file which is used for tracking the users.&lt;br /&gt;&lt;br /&gt;
Output :&lt;br /&gt;
&lt;/li&gt;
&lt;/ol&gt;


&lt;a&gt;&lt;/a&gt;
&lt;h2&gt;Key issues&lt;/h2&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Slowing down loading of client's site.&lt;/strong&gt;:&lt;br /&gt;
     What are you talking? Yes, widgets can bring down client's site who is embedding widget code in their page because:&lt;br /&gt; 
     &lt;ol&gt;
       &lt;li&gt;script tag stops page rendering until code inside it is executed and rendered.&lt;/li&gt; 
       &lt;li&gt;Script tag blocks parallel downloads :(&lt;/li&gt;
     &lt;/ol&gt;
     If the widget source goes down or is slow, the client's webpage won't load unless the widget code is executed and rendered. To avoid this problem consider following workarounds :&lt;br /&gt;
     &lt;ol&gt;&lt;li&gt;Use "defer" attribute with script (firefox doesn't support this though :-( ). This tells the browser to continue rendering and do not block the other downloads. Moreover, this can only be used if there is no "document.write" statement in your script. See more details &lt;a href="http://developer.yahoo.com/performance/rules.html#js_bottom"&gt;here&lt;/a&gt;&lt;/li&gt;
       &lt;li&gt;Put timeout on script attachment (source: &lt;a href="http://www.mikeindustries.com/blog/archive/2007/06/widget-deployment-with-wedje"&gt;WEDJE&lt;/a&gt;)&lt;br /&gt;
          Here, external scripts in widget code are not downloaded during page load, but attached after sometime. So, this does not affects loading/rendering of site. Hence, after sometime, the external scripts are downloaded, attached/executed thereafter. In example mentioned below, Twitter type-2 badge is modified to download the external scripts after 1 sec. So, if you embed this code in some html page, you will see the output after delay of 1sec&lt;br /&gt;&lt;span class="widget-code-header"&gt;Example: modifying the &lt;a href="#twitter-badge-2"&gt;twitter widget code&lt;/a&gt; :&lt;/span&gt;
&lt;table class="CodeRay"&gt;&lt;tr&gt;
  &lt;td title="click to toggle" class="line_numbers"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;6&lt;tt&gt;
&lt;/tt&gt;7&lt;tt&gt;
&lt;/tt&gt;8&lt;tt&gt;
&lt;/tt&gt;9&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;11&lt;tt&gt;
&lt;/tt&gt;12&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre&gt;&amp;lt;div id=&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;twitter_div&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&amp;gt;&lt;tt&gt;
&lt;/tt&gt;&amp;lt;h2 &lt;span class="r"&gt;class&lt;/span&gt;=&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;twitter-title&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&amp;gt;Twitter Updates&amp;lt;/h2&amp;gt;&lt;tt&gt;
&lt;/tt&gt;&amp;lt;ul id=&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;twitter_update_list&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&amp;gt;&amp;lt;/ul&amp;gt;&amp;lt;/div&amp;gt;&lt;tt&gt;
&lt;/tt&gt;&amp;lt;div id=&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;twitter_script&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&amp;gt;&amp;lt;/div&amp;gt;&lt;tt&gt;
&lt;/tt&gt;&amp;lt;script &lt;span class="r"&gt;type&lt;/span&gt;=&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;text/javascript&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&amp;gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="r"&gt;var&lt;/span&gt; script1 = &lt;span class="pt"&gt;document&lt;/span&gt;.createElement(&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;script&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;);&lt;tt&gt;
&lt;/tt&gt;script1.src=&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;http://twitter.com/javascripts/blogger.js&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="fu"&gt;setTimeout&lt;/span&gt;(&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;document.getElementById('twitter_script').appendChild(script1)&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;,1000);&lt;tt&gt;
&lt;/tt&gt;&lt;span class="r"&gt;var&lt;/span&gt; script2 = &lt;span class="pt"&gt;document&lt;/span&gt;.createElement(&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;script&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;);&lt;tt&gt;
&lt;/tt&gt;script2.src=&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;http://twitter.com/statuses/user_timeline/username.json?callback=twitterCallback2&amp;amp;count=5&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="fu"&gt;setTimeout&lt;/span&gt;(&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;document.getElementById('twitter_script').appendChild(script2)&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;,1000);&lt;tt&gt;
&lt;/tt&gt;&amp;lt;/script&amp;gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;

       &lt;/li&gt;&lt;/ol&gt;
  &lt;/li&gt;

&lt;li&gt;&lt;strong&gt;Avoid conflict's with client's JavaScript&lt;/strong&gt;:&lt;br /&gt; Widget code and external loaded Javascript files should contain minimum global variables, so as to prevent any chances of conflict with client's JavaScript which is embedding the widget. If your widget does not take any parameters from client, one should try to use anonymous JavaScript classes. &amp;lt;!--If user need to set some variable value, then one can define singleton classes. --&gt;
&lt;/li&gt;

&lt;li&gt;&lt;strong&gt;Let client apply its own CSS to widget&lt;/strong&gt;:&lt;br /&gt; This helps in customizing the style of widget as per the design/looks of client's webpage. Google allows this even via iframes by using global variables, Amazon allows this while making widget, Mybloglog and twitter doesn't use iframes so your CSS directly applies to the widget's HTML.&lt;/li&gt;

&lt;li&gt;&lt;strong&gt;Minimize number of request&lt;/strong&gt;:&lt;br /&gt;This is to load your widget faster which applies to any &lt;a href="http://developer.yahoo.com/performance/rules.html#num_http"&gt;HTML page&lt;/a&gt;&lt;/li&gt;

&lt;li&gt;&lt;strong&gt;Do you want to prevent content editing?&lt;/strong&gt;:&lt;br /&gt; If you do not want to allow content editing of the widget, then use iframes since they cannot be manipulated by JavaScript outside the iframe element.&lt;/li&gt;

&lt;li&gt;&lt;strong&gt;Using API&lt;/strong&gt;&lt;br /&gt;If you are using an API, then callback method must be provided by that API. This is just to keep in mind if you want to use some external API and display the content dynamically.&lt;/li&gt;
&lt;/ul&gt;
          </content>  <feedburner:origLink>http://www.quarkruby.com/2008/1/7/widget</feedburner:origLink></entry>
  <entry xml:base="http://www.quarkruby.com/">
    <author>
      <name>admin</name>
    </author>
    <id>tag:www.quarkruby.com,2007-12-19:1335</id>
    <published>2007-12-19T18:56:00Z</published>
    <updated>2007-12-19T19:03:49Z</updated>
    <category term="our tools" />
    <category term="quarkrank" />
    <category term="mashup" />
    <category term="shopping" />
    <link href="http://feedproxy.google.com/~r/Quarkruby/~3/tPEWefP5UM0/quarkshop" rel="alternate" type="text/html" />
    <title>Quarkshop : next-generation shopping</title>
<content type="html">
            &lt;br /&gt;

&lt;a href="http://www.quarkshop.com/mp3player/catalog?brand=&amp;amp;displaysize=&amp;amp;price=&amp;amp;songcount=&amp;amp;capacity=#compare-03TIAW,03USI4,03RMZ7"&gt;&lt;img src="http://quarkruby.com/assets/2007/12/16/quarkshop_on_quarkruby.png"&gt;&lt;/a&gt;
&lt;p&gt;QuarkShop is a next-generation shopping experience to find product of your choice based on opinions across the Internet. You give your preference and Quarkshop will fetch the best matched products for &lt;b&gt;YOU&lt;/b&gt;.&lt;/p&gt;

&lt;p&gt;For launch, currently we have following products :
&lt;ul&gt;
&lt;li&gt; Camera : &lt;a href="http://www.quarkshop.com/cameras"&gt;http://www.quarkshop.com/cameras&lt;/a&gt;
&lt;li&gt;Mp3 player : &lt;a href="http://www.quarkshop.com/mp3players"&gt;http://www.quarkshop.com/mp3players&lt;/a&gt;
&lt;li&gt;Flat panel TV : &lt;a href="http://www.quarkshop.com/flatpaneltvs"&gt;http://www.quarkshop.com/flatpaneltvs&lt;/a&gt;
&lt;li&gt;Cell phone : &lt;a href="http://www.quarkshop.com/cellphones"&gt;http://www.quarkshop.com/cellphones&lt;/a&gt;
&lt;/ul&gt;&lt;/p&gt;
&lt;/img&gt;


&lt;h2&gt;Search products&lt;/h2&gt;
&lt;p&gt;You can give your preference by selecting features you &lt;b&gt;LIKE&lt;/b&gt; and we will find the best matched products. Selection of preference can be used along with other navigation parameters like &lt;i&gt;brand, price, etc&lt;/i&gt;. These features are automatically extracted from reviews.&lt;/p&gt;

&lt;p&gt;Then click &lt;i&gt;submit&lt;/i&gt;, and you will see the three best matched products with their most related information. There is also an option to see more products. But we think that top 3 products is what consumer care about after they have given their preference, this makes searching for products simple and fast.&lt;/p&gt;
&lt;br /&gt;
&lt;b&gt;Choose your features&lt;/b&gt;
&lt;br /&gt;
&lt;img src="http://quarkruby.com/assets/2007/12/16/preference.png"&gt;
&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;

&lt;b&gt;Top 3 products&lt;/b&gt;
&lt;img src="http://quarkruby.com/assets/2007/12/16/best_matched.png"&gt;
&lt;br /&gt;

&lt;h2&gt;Comparison : QuarkGraph&lt;/h2&gt;
&lt;p&gt;You can compare the top three products on the spot!. When you click on &lt;b&gt;Compare Top Three&lt;/b&gt; button, you will see QuarkGraph, the graphical comparison showing scores of feature for each product. The graph is just not an image but you can &lt;b&gt;play&lt;/b&gt; with it.
&lt;/p&gt;
&lt;div class="linkbox"&gt;
&lt;a href="http://quarkshop.com/mp3player?features=f1&amp;amp;features=f5&amp;amp;features=f8&amp;amp;brand=Apple&amp;amp;price=201+to+400#compare"&gt;http://www.quarkshop.com/...res=f5&amp;features=f8&amp;brand=Apple&amp;price=201+to+400#compare&lt;/a&gt;
&lt;/div&gt;

&lt;img src="http://quarkruby.com/assets/2007/12/16/quarkgraph.png"&gt;


&lt;h2&gt;Features &amp; Snippets : Voice of consumer&lt;/h2&gt;

&lt;p&gt;Features are keywords that are reviewed in a review. When you read a review you are always looking for such keywords and people's comment about this keywords. Quarkshop gives an option to choose features/keywords that you like and it will give you the best matched products. You can also read sentence from actual reviews giving opinion on keywords (Snippets).&lt;/p&gt;

&lt;img src="http://quarkruby.com/assets/2007/12/16/feature_snippet.png"&gt;

&lt;h2&gt;Feedback&lt;/h2&gt;
We would really appreciate if you could give your feedback. It would help us to know where we stand and what is required to make useful shopping experience.
          </content>  <feedburner:origLink>http://www.quarkruby.com/2007/12/19/quarkshop</feedburner:origLink></entry>
  <entry xml:base="http://www.quarkruby.com/">
    <author>
      <name>admin</name>
    </author>
    <id>tag:www.quarkruby.com,2007-12-17:1322</id>
    <published>2007-12-17T10:32:00Z</published>
    <updated>2008-09-18T13:20:04Z</updated>
    <category term="our tools" />
    <category term="quarkrank" />
    <category term="api" />
    <category term="html scraping" />
    <category term="nlp" />
    <category term="scrapi" />
    <category term="shopping" />
    <category term="widget" />
    <link href="http://feedproxy.google.com/~r/Quarkruby/~3/t00gAC_KB3Q/releasing-quarkrank" rel="alternate" type="text/html" />
    <title>introducing QuarkRank</title>
<content type="html">
            &lt;br /&gt;
&lt;a href="http://www.quarkrank.com"&gt;&lt;img src="http://quarkruby.com/assets/2007/12/15/quarkrank_logo.png"&gt;&lt;/a&gt;&lt;p&gt;We're back to blogging after taking a leave for more than a month. We have been very busy developing &lt;a href="http://www.quarkrank.com"&gt;QuarkRank&lt;/a&gt;, a summarized reviews repository. It is a result of more than 18 months of dedicated research on Natural language processing, HTML Scrapping and User interface. Finally, we are happy to make this product live!!!&lt;/p&gt;
&lt;p&gt;Currently, the repository is accessible using RESTful API or Widget. Moreover, its absolutely free!&lt;/p&gt;&lt;/img&gt;
      
&lt;h2&gt;About QuarkRank&lt;/h2&gt;

&lt;p&gt;&lt;i&gt;"From product reviews, restaurant reviews, hotel reviews, to others, QuarkRank provides the information for making decisions at the point of purchase. Proprietary technology lies at the core of QuarkRank's ability to automatically summarize the opinions of millions of consumer reviews on the internet."&lt;/i&gt;&lt;/p&gt;

&lt;p&gt;QuarkRank is an intelligent engine which crawls the web for opinions on various products/services and automatically summarize them feature-by-feature using its natural language processing technique. &lt;/p&gt;

&lt;br /&gt;&lt;a href="http://www.quarkshop.com/mp3player/apple-ipod-touch-8gb" class="nostyle"&gt;&lt;img src="http://www.quarkrank.com/images/hometop/mp3player-snippet-home.gif" width="300" /&gt;&lt;/a&gt;
&lt;a href="http://www.quarkshop.com/mp3players#compare" class="nostyle"&gt;&lt;img src="http://www.quarkrank.com/images/hometop/mp3player-home-namesf.gif" width="370" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;

&lt;div&gt;
&lt;div&gt;Best and worst of Apple Ipod Touch 8gb&lt;/div&gt;
&lt;div&gt;QuarkGraph: &lt;a href="/"&gt;QuarkRank&lt;/a&gt; data displayed using &lt;a href="http://www.amcharts.com"&gt; amcharts&lt;/a&gt; at &lt;a href="http://www.quarkshop.com"&gt;Quarkshop&lt;/a&gt;&lt;/div&gt;
&lt;div&gt;&lt;/div&gt;
&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;

&lt;p&gt;QuarkRank will help consumers to quickly &lt;b&gt;educate&lt;/b&gt; themselves, based on the most &lt;b&gt;unbiased&lt;/b&gt; information possible, &lt;b&gt;without&lt;/b&gt; spending hours reading review online.&lt;/p&gt;

&lt;p&gt;If you use QuarkRank data, your customers will feel &lt;b&gt;confident&lt;/b&gt; in making purchase decision at your site, &lt;b&gt;without&lt;/b&gt; going to competitors, and at the same time &lt;b&gt;reducing&lt;/b&gt; the return rate of impulse purchases.&lt;/p&gt;


&lt;h2&gt;QuarkRank provides&lt;/h2&gt;
&lt;ul&gt;
  &lt;li&gt;Reviews gathered and combined at one place! for various products and services.&lt;/li&gt;
  &lt;li&gt;&lt;i&gt;QuarkRank, no. of reviews&lt;/i&gt; for a product/service
  &lt;li&gt;&lt;i&gt;Top 5 feature, Worst 3 feature, All features&lt;/i&gt; that people talk about a product/service. For example : sound quality, design, screen of a Mp3 player.
  &lt;li&gt;&lt;i&gt;Feature score, buzz&lt;/i&gt; and &lt;i&gt;SNIPPETS from reviews&lt;/i&gt; which have opinion about a feature.
&lt;/ul&gt;&lt;br /&gt;
No need to waste time analyzing reviews at Cnet and Amazon anymore!


&lt;h2&gt;Where can you use it?&lt;/h2&gt;
&lt;ul&gt;
  &lt;li&gt; Boost &lt;b&gt;online shopping&lt;/b&gt; experience of your users.
    &lt;ul&gt;
      &lt;li&gt; Best and Worst about a product.
      &lt;li&gt; Graphical feature-by-feature comparison.
      &lt;li&gt; Power your navigation by giving feature as an option to choose.
      &lt;li&gt; Summarized form of reviews.
    &lt;/ul&gt;
  &lt;li&gt; Add product widget to your &lt;b&gt;blog/article&lt;/b&gt;.
  &lt;li&gt; On your &lt;b&gt;social profile&lt;/b&gt;, add widget of your favourite or owned products.
  &lt;li&gt; Show feature-by-feature opinions and comparison for products at your &lt;b&gt;retail store&lt;/b&gt;.
&lt;/ul&gt;


&lt;h2&gt;API&lt;/h2&gt;
&lt;p&gt;QuarkRank provides a &lt;b&gt;RESTful API&lt;/b&gt; to access our huge repository of summarized reviews. Send us simple HTTP requests and it will send back basic XML responses, which means you can interact with our API from any language.&lt;/p&gt;

It provides data in XML and JSON format. There is no limit is using the api. For detailed information, visit :
&lt;div class="linkbox"&gt;
&lt;a href="http://www.quarkrank.com/api"&gt;www.quarkrank.com/api&lt;/a&gt;
&lt;/div&gt;

ActiveResource can be used to access QuarkRank's RESTful API in Ruby on Rails.
Note : You need to apply this &lt;a href="http://www.quarkrank.com/activeresource.patch"&gt;tiny patch&lt;/a&gt; to ActiveResource.&lt;br /&gt;
ActiveResource code:
&lt;table class="CodeRay"&gt;&lt;tr&gt;
  &lt;td title="click to toggle" class="line_numbers"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;6&lt;tt&gt;
&lt;/tt&gt;7&lt;tt&gt;
&lt;/tt&gt;8&lt;tt&gt;
&lt;/tt&gt;9&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;11&lt;tt&gt;
&lt;/tt&gt;12&lt;tt&gt;
&lt;/tt&gt;13&lt;tt&gt;
&lt;/tt&gt;14&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;15&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;16&lt;tt&gt;
&lt;/tt&gt;17&lt;tt&gt;
&lt;/tt&gt;18&lt;tt&gt;
&lt;/tt&gt;19&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;20&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;21&lt;tt&gt;
&lt;/tt&gt;22&lt;tt&gt;
&lt;/tt&gt;23&lt;tt&gt;
&lt;/tt&gt;24&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;25&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;26&lt;tt&gt;
&lt;/tt&gt;27&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre&gt;&lt;span class="r"&gt;class&lt;/span&gt; &lt;span class="cl"&gt;Product&lt;/span&gt; &amp;lt; &lt;span class="co"&gt;ActiveResource&lt;/span&gt;::&lt;span class="co"&gt;Base&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="pc"&gt;self&lt;/span&gt;.site = &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;http://username:password@quarkrank.com&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="r"&gt;def&lt;/span&gt; &lt;span class="pc"&gt;self&lt;/span&gt;.list options={&lt;span class="sy"&gt;:category&lt;/span&gt;=&amp;gt;&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;camera&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;}&lt;tt&gt;
&lt;/tt&gt;    find(&lt;span class="sy"&gt;:all&lt;/span&gt;, &lt;span class="sy"&gt;:params&lt;/span&gt;=&amp;gt;options)&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="r"&gt;def&lt;/span&gt; &lt;span class="pc"&gt;self&lt;/span&gt;.show sku, site=&lt;span class="pc"&gt;nil&lt;/span&gt;, all_features=&lt;span class="pc"&gt;false&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    params = {}&lt;tt&gt;
&lt;/tt&gt;    params[&lt;span class="sy"&gt;:site&lt;/span&gt;] = site &lt;span class="r"&gt;unless&lt;/span&gt; site.nil?&lt;tt&gt;
&lt;/tt&gt;    params[&lt;span class="sy"&gt;:all_features&lt;/span&gt;]=&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class="r"&gt;if&lt;/span&gt; all_features&lt;tt&gt;
&lt;/tt&gt;    find(sku, &lt;span class="sy"&gt;:params&lt;/span&gt;=&amp;gt;params)&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="r"&gt;def&lt;/span&gt; &lt;span class="pc"&gt;self&lt;/span&gt;.search query&lt;tt&gt;
&lt;/tt&gt;    find(&lt;span class="sy"&gt;:all&lt;/span&gt;,&lt;span class="sy"&gt;:params&lt;/span&gt;=&amp;gt;{&lt;span class="sy"&gt;:search&lt;/span&gt;=&amp;gt;query})&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="r"&gt;class&lt;/span&gt; &lt;span class="cl"&gt;Snippet&lt;/span&gt; &amp;lt; &lt;span class="co"&gt;ActiveResource&lt;/span&gt;::&lt;span class="co"&gt;Base&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="pc"&gt;self&lt;/span&gt;.site = &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;http://username:password@www.quarkrank.com/products/:product_id&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="r"&gt;def&lt;/span&gt; &lt;span class="pc"&gt;self&lt;/span&gt;.snippets product, name&lt;tt&gt;
&lt;/tt&gt;    find name.gsub(&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt; &lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;,&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;%20&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;),&lt;span class="sy"&gt;:params&lt;/span&gt;=&amp;gt;{&lt;span class="sy"&gt;:product_id&lt;/span&gt;=&amp;gt;product}&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="r"&gt;end&lt;/span&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;



&lt;h2&gt;Widget&lt;/h2&gt;
QuarkRank provides two kinds of customizable widget. 
&lt;ol&gt;
  &lt;li&gt;&lt;b&gt;Top 5 features&lt;/b&gt;
        &lt;br /&gt;
  &lt;li&gt;&lt;b&gt;Interactive widget for features and review snippets of a product&lt;/b&gt;
	&lt;/ol&gt;
&lt;br /&gt;
&lt;p&gt;More informatin at: &lt;/p&gt;
&lt;div class="linkbox"&gt;
&lt;a href="http://www.quarkrank.com/widget"&gt;www.quarkrank.com/widget&lt;/a&gt;
&lt;/div&gt;


&lt;h2&gt;Technologies and tools used&lt;/h2&gt;
A lot of them .... 
&lt;ul&gt;
  &lt;li&gt;&lt;b&gt;HTML scrapping&lt;/b&gt; : NLP, Scrapi, &lt;a href="http://www.quarkruby.com/2007/9/5/firequark-quick-html-screen-scraping"&gt;Firequark&lt;/a&gt;, CSS Selectors. Implemented in Ruby. 
  &lt;li&gt;&lt;b&gt;Text-mining&lt;/b&gt; : Statistics, Text parsing, chunking, cleaning and many enhancements. 
  &lt;li&gt;&lt;b&gt;API and QuarkRank site&lt;/b&gt; : Ruby on Rails, REST, Acts_as_solr, Request routing. 
&lt;/ul&gt;

&lt;h2&gt;Coming next&lt;/h2&gt;
&lt;b&gt;QuarkShop&lt;/b&gt; : a mashup of QuarkRank, Cnet, Amazon, Shopping.com and Yahoo.com.
          </content>  <feedburner:origLink>http://www.quarkruby.com/2007/12/17/releasing-quarkrank</feedburner:origLink></entry>
  <entry xml:base="http://www.quarkruby.com/">
    <author>
      <name>admin</name>
    </author>
    <id>tag:www.quarkruby.com,2007-11-06:1033</id>
    <published>2007-11-06T15:37:00Z</published>
    <updated>2007-11-06T18:14:06Z</updated>
    <category term="ruby on rails" />
    <category term="css selector" />
    <category term="javascript" />
    <link href="http://feedproxy.google.com/~r/Quarkruby/~3/QkfsCR70OaM/why-i-moved-from-prototype-to-jquery" rel="alternate" type="text/html" />
    <title>Why I moved from Prototype to jQuery</title>
<summary type="html">&lt;br /&gt;
&lt;p&gt;
&lt;a href="http://jquery.com/"&gt;jQuery&lt;/a&gt; is a JavaScript library which follows unobtrusive paradigm for application development using JavaScript. jQuery inherently supports Behavior driven development and is based on traversing HTML documents using CSS Selectors. On the other hand, &lt;a href="http://www.prototypejs.org/"&gt;Prototype&lt;/a&gt; is a JavaScript library for Class driven development which makes life easier working with JavaScript. Prototype library has a good support in Ruby on Rails via helper functions.
&lt;/p&gt;

&lt;p&gt;
I have always used Prototype library for most of my projects until I was introduced to jQuery three months back ... and it enchanted me.
&lt;/p&gt;</summary><content type="html">
            &amp;lt;style&gt;
table.sample {
 border-width: 1px;
 border-spacing: 2px;
 border-style: hidden;
 border-color: gray;
 border-collapse: collapse;
 background-color: white;
 width:100%;
}
table.sample th {
 border-width: 1px;
 padding: 6px;
 border-style: inset;
 border-color: gray;
 background-color: white;
 text-align:center;
}
table.sample td {
 border-width: 1px;
 padding: 6px;
 border-style: inset;
 border-color: gray;
 background-color: white;
}
.underline {
border-bottom: 1px dotted;
}
#tablediv {margin-left:-40px;}
p.toppadding {padding-top:0.5em;}
&amp;lt;/style&gt;

&lt;br /&gt;
&lt;p&gt;
&lt;a href="http://jquery.com/"&gt;jQuery&lt;/a&gt; is a JavaScript library which follows unobtrusive paradigm for application development using JavaScript. jQuery inherently supports Behavior driven development and is based on traversing HTML documents using CSS Selectors. On the other hand, &lt;a href="http://www.prototypejs.org/"&gt;Prototype&lt;/a&gt; is a JavaScript library for Class driven development which makes life easier working with JavaScript. Prototype library has a good support in Ruby on Rails via helper functions.
&lt;/p&gt;

&lt;p&gt;
I have always used Prototype library for most of my projects until I was introduced to jQuery three months back ... and it enchanted me.
&lt;/p&gt;

&lt;h2&gt; The reasons &lt;/h2&gt;
&lt;ol&gt;
  &lt;li&gt;&lt;b&gt;Behavior driven development (BDD)&lt;/b&gt;
&lt;p class="toppadding"&gt;Using jQuery, behavior(s) of HTML elements is defined separately from HTML code similar to defining style of an element using CSS. Lets look at a &lt;i&gt;simple example&lt;/i&gt; to display alert box on click of an element&lt;/p&gt;
&lt;table class="CodeRay"&gt;&lt;tr&gt;
  &lt;td title="click to toggle" class="line_numbers"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre&gt;$(element).click(&lt;span class="r"&gt;function&lt;/span&gt;(){&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="fu"&gt;alert&lt;/span&gt;(&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;warning&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;);&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="c"&gt;//fill stub for confirming this action from user&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;});&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;

&lt;p&gt;
&lt;i&gt;A complex example&lt;/i&gt;: All elements of class "speciallinks" should emit the following behavior: 
&lt;ol&gt;&lt;li&gt;change their href link to "javascript:void(0);"
&lt;li&gt;generate logs on click
&lt;li&gt;onhover should change background color.
&lt;/ol&gt;
&lt;/p&gt;
&lt;table class="CodeRay"&gt;&lt;tr&gt;
  &lt;td title="click to toggle" class="line_numbers"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre&gt;$(&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;div.speciallinks&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;).attr(&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;href&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;,&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;javascript:void(0)&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;)&lt;tt&gt;
&lt;/tt&gt;    .click(&lt;span class="r"&gt;function&lt;/span&gt;() {console.&lt;span class="fu"&gt;log&lt;/span&gt;(&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;div.speciallinks clicked&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;);})&lt;tt&gt;
&lt;/tt&gt;    .hover(&lt;span class="r"&gt;function&lt;/span&gt;(){$(&lt;span class="pc"&gt;this&lt;/span&gt;).addClass(&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;hovered&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;);}, &lt;tt&gt;
&lt;/tt&gt;             &lt;span class="r"&gt;function&lt;/span&gt;(){$(&lt;span class="pc"&gt;this&lt;/span&gt;).removeClass(&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;hovered&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;);});&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;

   &lt;/li&gt;

  &lt;li&gt;&lt;b&gt;MVC + J&lt;/b&gt;
&lt;p class="toppadding"&gt;MVC framework divides web development into 3 separate parts &lt;i&gt;Model-View-Controller&lt;/i&gt; and Ruby on Rails  is a great MVC framework. The &lt;i&gt;View&lt;/i&gt; part of MVC framework comprises of HTML, CSS and JavaScript which is bulky, combining three different parts of GUI development into one. Moreover, using Prototype helpers in Ruby on Rails views messes up HTML and JavaScript together. Here, jQuery fits in nicely (due to BDD) to separate JavaScript(J) from &lt;i&gt;Views(V)&lt;/i&gt; to visualize the framework as MVC + J which I find very powerful especially working with Ajax.&lt;/p&gt;
&lt;p&gt;Using jQuery, I keep all my HTML files are clean and clear as all the JavaScript code is kept in .js files defining behavior of HTML elements.&lt;/p&gt;
  &lt;/li&gt;

  &lt;li&gt;&lt;b&gt;Chaining of actions&lt;/b&gt;
&lt;p class="toppadding"&gt;Chaining of actions for a HTML element follows DRY principals and increases readability of JavaScript code. If I want to add a bunch of operations on a single/multiple elements, it can be as simple as:&lt;/p&gt;
&lt;table class="CodeRay"&gt;&lt;tr&gt;
  &lt;td title="click to toggle" class="line_numbers"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre&gt;$(&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;div.message&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;).show()&lt;tt&gt;
&lt;/tt&gt;  .append(&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;&amp;lt;p&amp;gt;Action has been executed successfully&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;)&lt;tt&gt;
&lt;/tt&gt;  .addClass(&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;flash&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;);&lt;tt&gt;
&lt;/tt&gt;&lt;span class="c"&gt;// chained functions can be on separate lines :)&lt;/span&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;

&lt;p&gt;Now, this is possible because every method within jQuery returns the query object itself on which further methods can be applied to form a chain of methods on "selected" HTML elements.&lt;/p&gt;  
&lt;/li&gt;

  &lt;li&gt;&lt;b&gt;CSS Selector rocks!&lt;/b&gt;
&lt;p class="toppadding"&gt;CSS Selectors are very powerful when playing with HTML DOM. jQuery is &lt;b&gt;based on&lt;/b&gt; CSS Selectors to identify elements in a HTML document, which avoids tedious job of managing &lt;b&gt;id&lt;/b&gt; attribute for each of my HTML tags. Most of &lt;b&gt;id&lt;/b&gt; attributes can be avoided using right CSS Selector. Prototype does supports CSS Selectors via $$ function, but it doesn't fully leverages the power of CSS Selectors. I find Prototype working best with element's id attribute.&lt;/p&gt;
  &lt;/li&gt;

  &lt;li&gt;&lt;b&gt;No more checks for presence of an element&lt;/b&gt;
&lt;p class="toppadding"&gt;In prototype, I always need to check if an element exists before applying an action to it. For example: I want to display user specific content in a div{id='user-box'} only if user is logged in (this div will exist on rendered page only if user is logged in). In Prototype I will do : &lt;/p&gt;
&lt;table class="CodeRay"&gt;&lt;tr&gt;
  &lt;td title="click to toggle" class="line_numbers"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre&gt;&lt;span class="r"&gt;if&lt;/span&gt; ($(&lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;user-box&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;)!=&lt;span class="pc"&gt;null&lt;/span&gt;) {&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="c"&gt;// this if block is redundant with jQuery&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  $(&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;user-box&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;).style.backgroundColor = &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;red&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;;&lt;tt&gt;
&lt;/tt&gt;}&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;

&lt;/li&gt;

  &lt;li&gt;&lt;b&gt;Aids development process&lt;/b&gt;
&lt;p&gt;Using jQuery HTML code is clean and nearly untouched. My web designer can easily modify html and stylesheets without learning the Prototype library.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;


&lt;h2&gt;Examples&lt;/h2&gt;
Here are few examples highlighting the difference in using jQuery and Prototype. (code in the examples may not be the shortest way possible.)
&lt;div&gt;
  &lt;table class="sample"&gt;
    &lt;tr&gt;&lt;th&gt;jQuery&lt;/th&gt;&lt;th&gt;Prototype&lt;/th&gt;&lt;/tr&gt;
    &lt;tr&gt;&lt;td&gt;&lt;span class="underline"&gt;Example1&lt;/span&gt;: &lt;br /&gt;Tabbing system with 3 tabs of class "tabs" and ids=&gt;["tabs1","tabs2","tabs3"] respectively. When user clicks on the link "show first tab", #tab1 should only be displayed.&lt;/td&gt;&lt;/tr&gt;
    &lt;tr&gt;&lt;td&gt;
&lt;div class="CodeRay"&gt;
  &lt;div class="code"&gt;&lt;pre&gt;&lt;span class="no"&gt;1&lt;/span&gt; $(&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;div.tabs&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;).hide();
&lt;span class="no"&gt;2&lt;/span&gt; $(&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;div#tabs1&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;).show();&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;

    &lt;/td&gt;&lt;td&gt;
&lt;div class="CodeRay"&gt;
  &lt;div class="code"&gt;&lt;pre&gt;&lt;span class="no"&gt;1&lt;/span&gt; $$(&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;div.tabs&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;).invoke(&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;hide&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;);
&lt;span class="no"&gt;2&lt;/span&gt;      &lt;span class="c"&gt;//or&lt;/span&gt;
&lt;span class="no"&gt;3&lt;/span&gt; $$(&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;div.tabs&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;).each(&lt;span class="r"&gt;function&lt;/span&gt;(x){
&lt;span class="no"&gt;4&lt;/span&gt;   Element.hide(x);
&lt;span class="no"&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;/span&gt; });
&lt;span class="no"&gt;6&lt;/span&gt; &lt;span class="c"&gt;// then..&lt;/span&gt;
&lt;span class="no"&gt;7&lt;/span&gt; $(&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;tabs1&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;).show();&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;

    &lt;/td&gt;&lt;/tr&gt;
    &lt;tr&gt;&lt;td&gt;&lt;span class="underline"&gt;Example2&lt;/span&gt;:&lt;br /&gt;Modify CSS of some element&lt;/td&gt;&lt;/tr&gt;
    &lt;tr&gt;&lt;td&gt;&lt;div class="CodeRay"&gt;
  &lt;div class="code"&gt;&lt;pre&gt;&lt;span class="no"&gt;1&lt;/span&gt; $(&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;#user-box&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;).css(&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;background-color&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;,&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;red&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;)&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;

    &lt;/td&gt;&lt;td&gt;
&lt;div class="CodeRay"&gt;
  &lt;div class="code"&gt;&lt;pre&gt;&lt;span class="no"&gt;1&lt;/span&gt; &lt;span class="r"&gt;var&lt;/span&gt; a = $(&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;user-box&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;);
&lt;span class="no"&gt;2&lt;/span&gt; a.style.cssText +=
&lt;span class="no"&gt;3&lt;/span&gt;        &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;background-color:red;&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;

    &lt;/td&gt;&lt;/tr&gt;
  &lt;/table&gt;
&lt;/div&gt;

&lt;br /&gt;

For more examples checkout, Remy Sharp's presentation
&lt;div class="linkbox"&gt;
 &lt;a href="http://ajaxian.com/archives/prototype-and-jquery-a-code-comparison"&gt;http://ajaxian.com/archives/prototype-and-jquery-a-code-comparison&lt;/a&gt;
&lt;/div&gt;

&lt;h2&gt;I miss prototype&lt;/h2&gt;
&lt;ol&gt;
    &lt;li&gt;On Ajax request, when a div is updated with a partial and this partial contains elements with JavaScript behavior, the behavior needs to be activated/reactivated. In jQuery I do not have to write a lot of code for this, but still I have to keep this in mind every time a partial is loaded with Ajax. In Prototype, each HTML element use to contain the corresponding JavaScript code along with it in the partial.&lt;/li&gt;

  &lt;li&gt;Ruby on Rails helpers for Prototype library are awesome and makes life a lot easier working with JavaScript and Ajax.&lt;/li&gt;

  &lt;li&gt;Prototype library provides Ruby like syntax in JavaScript for functions on arrays, objects, etc which further makes development easier and faster.&lt;/li&gt;

  &lt;li&gt;With jQuery, element behavior gets activated only after DOM has been built and JavaScript files have been downloaded. For slow connections, this can be painful as there is a delay in activation of behavior.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;Conclusion:&lt;/h2&gt;
Jquery and prototype are both great libraries. For me, jQuery's philosophy (type less, do more, keeping things intuitive and unobstrusive) makes a big difference. But, I miss prototype core javascript additions. Waiting for jquery-rails integration. Some &lt;a href="http://yehudakatz.com/2007/05/17/jquery-on-rails-a-fresh-approach/"&gt;steps&lt;/a&gt; have been taken toward this goal. I would love to listen some of your personal experiences in shifting.&lt;br /&gt;&lt;br /&gt;
&lt;b&gt;P.S:&lt;/b&gt; For using both libraries together, check &lt;a href="http://docs.jquery.com/Using_jQuery_with_Other_Libraries"&gt;this&lt;/a&gt;.


          </content>  <feedburner:origLink>http://www.quarkruby.com/2007/11/6/why-i-moved-from-prototype-to-jquery</feedburner:origLink></entry>
  <entry xml:base="http://www.quarkruby.com/">
    <author>
      <name>admin</name>
    </author>
    <id>tag:www.quarkruby.com,2007-10-21:763</id>
    <published>2007-10-21T17:06:00Z</published>
    <updated>2007-10-24T02:49:02Z</updated>
    <category term="guides" />
    <category term="ruby on rails" />
    <category term="sessions" />
    <link href="http://feedproxy.google.com/~r/Quarkruby/~3/3v97Nd4DSIs/sessions-and-cookies-in-ruby-on-rails" rel="alternate" type="text/html" />
    <title>Sessions and cookies in Ruby on Rails</title>
<summary type="html">An important issue rarely talked about with little documentation on Internet. So, here we go ... a guide to session and cookies in Rails. Session and cookies are an integral part of any good web application and rails has a good support for them. Continuing with our DRY approach, this guide contains link to cool articles with good description wherever necessary. 


&lt;h2&gt;Table of Contents &lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href="#sintro"&gt;Introduction&lt;/a&gt;&lt;br /&gt;
&lt;li&gt;&lt;a href="#ssessions"&gt;Sessions&lt;/a&gt;
&lt;ol&gt;
   &lt;li&gt;&lt;a href="#sinrails"&gt;Session in rails&lt;/a&gt;
   &lt;li&gt;&lt;a href="#sconfig"&gt;Configure your sessions&lt;/a&gt;
   &lt;li&gt;&lt;a href="#sstorage"&gt;Storage options&lt;/a&gt;
   &lt;li&gt;&lt;a href="#slimitations"&gt;Session storage limitations&lt;/a&gt;
   &lt;li&gt;&lt;a href="#ssecurity"&gt;Session and Security&lt;/a&gt;
   &lt;li&gt;&lt;a href="#showto"&gt;HowTo&lt;/a&gt;
      &lt;ol&gt;
          &lt;li&gt;&lt;a href="#sexpire"&gt;Implement session expiration&lt;/a&gt;
          &lt;li&gt;&lt;a href="#sstale"&gt;Delete stale sessions&lt;/a&gt;
          &lt;li&gt;&lt;a href="#sactive"&gt;Find out active users&lt;/a&gt;
          &lt;li&gt;&lt;a href="#ssessionid"&gt;Access session data using session_id&lt;/a&gt;
      &lt;/ol&gt;
   &lt;li&gt;&lt;a href="#smisc"&gt;Miscellaneous&lt;/a&gt;
&lt;/ol&gt;
&lt;li&gt;&lt;a href="#scookies"&gt;Cookies&lt;/a&gt;
&lt;ol&gt;
   &lt;li&gt;&lt;a href="#scinrails"&gt;Cookie on rails&lt;/a&gt;
   &lt;li&gt;&lt;a href="#scvr"&gt;cookies vs. request.cookies&lt;/a&gt;
   &lt;li&gt;&lt;a href="#scookiejar"&gt;CookieJar&lt;/a&gt;
   &lt;li&gt;&lt;a href="#scmisc"&gt;Miscellaneous&lt;/a&gt;
&lt;/ol&gt;
&lt;/ol&gt;


&lt;br /&gt;


&lt;a&gt;&lt;/a&gt;
&lt;h1&gt;Introduction&lt;/h1&gt;

&lt;p&gt;HTTP is a stateless protocol which creates problem in uniquely tracking a visitor to a web application. The process of managing the state between browser and server is through the use of session IDs which uniquely identifies a client browser. &lt;/p&gt;

Session IDs can be stored and communicated in one of the following ways :
&lt;ol&gt;
&lt;li&gt;Embedded in URL
&lt;li&gt;In form field
&lt;li&gt;Using cookies.
&lt;/ol&gt;

&lt;p&gt;Information stored between multiple client browser request is called Session Data. Session data for each visitor can be stored at the server or in cookies. Upon client request to server, session data is extracted from session storage using session ID send by client browser. A good common example for session data is &lt;i&gt;user information for authentication&lt;/i&gt;.&lt;/p&gt;

&lt;p&gt;In the present times, its hard to imagine a good web application not using Sessions.&lt;/p&gt;

A wonderful article on implementation techniques of Session ID.
&lt;div class="linkbox"&gt;
&lt;a href="http://www.technicalinfo.net/papers/WebBasedSessionManagement.html"&gt;http://www.technicalinfo.net/papers/WebBasedSessionManagement.html&lt;/a&gt;
&lt;/div&gt;</summary><content type="html">
            An important issue rarely talked about with little documentation on Internet. So, here we go ... a guide to session and cookies in Rails. Session and cookies are an integral part of any good web application and rails has a good support for them. Continuing with our DRY approach, this guide contains link to cool articles with good description wherever necessary. 


&lt;h2&gt;Table of Contents &lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href="#sintro"&gt;Introduction&lt;/a&gt;&lt;br /&gt;
&lt;li&gt;&lt;a href="#ssessions"&gt;Sessions&lt;/a&gt;
&lt;ol&gt;
   &lt;li&gt;&lt;a href="#sinrails"&gt;Session in rails&lt;/a&gt;
   &lt;li&gt;&lt;a href="#sconfig"&gt;Configure your sessions&lt;/a&gt;
   &lt;li&gt;&lt;a href="#sstorage"&gt;Storage options&lt;/a&gt;
   &lt;li&gt;&lt;a href="#slimitations"&gt;Session storage limitations&lt;/a&gt;
   &lt;li&gt;&lt;a href="#ssecurity"&gt;Session and Security&lt;/a&gt;
   &lt;li&gt;&lt;a href="#showto"&gt;HowTo&lt;/a&gt;
      &lt;ol&gt;
          &lt;li&gt;&lt;a href="#sexpire"&gt;Implement session expiration&lt;/a&gt;
          &lt;li&gt;&lt;a href="#sstale"&gt;Delete stale sessions&lt;/a&gt;
          &lt;li&gt;&lt;a href="#sactive"&gt;Find out active users&lt;/a&gt;
          &lt;li&gt;&lt;a href="#ssessionid"&gt;Access session data using session_id&lt;/a&gt;
      &lt;/ol&gt;
   &lt;li&gt;&lt;a href="#smisc"&gt;Miscellaneous&lt;/a&gt;
&lt;/ol&gt;
&lt;li&gt;&lt;a href="#scookies"&gt;Cookies&lt;/a&gt;
&lt;ol&gt;
   &lt;li&gt;&lt;a href="#scinrails"&gt;Cookie on rails&lt;/a&gt;
   &lt;li&gt;&lt;a href="#scvr"&gt;cookies vs. request.cookies&lt;/a&gt;
   &lt;li&gt;&lt;a href="#scookiejar"&gt;CookieJar&lt;/a&gt;
   &lt;li&gt;&lt;a href="#scmisc"&gt;Miscellaneous&lt;/a&gt;
&lt;/ol&gt;
&lt;/ol&gt;


&lt;br /&gt;


&lt;a&gt;&lt;/a&gt;
&lt;h1&gt;Introduction&lt;/h1&gt;

&lt;p&gt;HTTP is a stateless protocol which creates problem in uniquely tracking a visitor to a web application. The process of managing the state between browser and server is through the use of session IDs which uniquely identifies a client browser. &lt;/p&gt;

Session IDs can be stored and communicated in one of the following ways :
&lt;ol&gt;
&lt;li&gt;Embedded in URL
&lt;li&gt;In form field
&lt;li&gt;Using cookies.
&lt;/ol&gt;

&lt;p&gt;Information stored between multiple client browser request is called Session Data. Session data for each visitor can be stored at the server or in cookies. Upon client request to server, session data is extracted from session storage using session ID send by client browser. A good common example for session data is &lt;i&gt;user information for authentication&lt;/i&gt;.&lt;/p&gt;

&lt;p&gt;In the present times, its hard to imagine a good web application not using Sessions.&lt;/p&gt;

A wonderful article on implementation techniques of Session ID.
&lt;div class="linkbox"&gt;
&lt;a href="http://www.technicalinfo.net/papers/WebBasedSessionManagement.html"&gt;http://www.technicalinfo.net/papers/WebBasedSessionManagement.html&lt;/a&gt;
&lt;/div&gt;



&lt;a&gt;&lt;/a&gt;
&lt;h1&gt;- Sessions -&lt;/h1&gt;

&lt;a&gt;&lt;/a&gt;
&lt;h2&gt;Session in rails&lt;/h2&gt;

&lt;p&gt;Session in rails is a hash-like structure which allows you to store data across requests. Sessions can hold any kind of data object (with some limitations) because they store data using Data Marshalling (aka Data Serialization or Data Deflating).&lt;/p&gt;

Rails way of implementing session:
&lt;ol&gt;
&lt;li&gt;session_id is a 32 hex character MD5 hash based upon time, random number and constant string. It is stored in cookie at client browser. Rails provides transparent support for session_id.
&lt;li&gt;&lt;a href="#sstorage"&gt;Session storage&lt;/a&gt; discussed below.
&lt;/ol&gt;
&lt;br /&gt;

&lt;p&gt;Remember, you can insert or access values from session similar to hash ... but session is NOT a hash. Most of the other hash methods will not work with sessions.&lt;/p&gt;

Working with session in rails
&lt;div class="linkbox"&gt;
&lt;a href="http://wiki.rubyonrails.org/rails/pages/HowtoWorkWithSessions"&gt;http://wiki.rubyonrails.org/rails/pages/HowtoWorkWithSessions&lt;/a&gt;
&lt;/div&gt;

Data Serialization in Ruby
&lt;div class="linkbox"&gt;
&lt;a href="http://en.wikipedia.org/wiki/Serialization#Ruby"&gt;http://en.wikipedia.org/wiki/Serialization#Ruby&lt;/a&gt;
&lt;/div&gt;

CGI::Session creates a new instance of session everytime a new user visits your site.
&lt;div class="linkbox"&gt;
&lt;a href="http://corelib.rubyonrails.org/classes/CGI/Session.html"&gt;http://corelib.rubyonrails.org/classes/CGI/Session.html&lt;/a&gt;
&lt;/div&gt;



&lt;a&gt;&lt;/a&gt;
&lt;h2&gt;Configure your sessions&lt;/h2&gt;

Configure &lt;i&gt;key, prefix, expiry&lt;/i&gt; and &lt;i&gt;domain&lt;/i&gt; of your session.
&lt;div class="linkbox"&gt;
&lt;a href="http://wiki.rubyonrails.org/rails/pages/HowtoChangeSessionOptions"&gt;http://wiki.rubyonrails.org/rails/pages/HowtoChangeSessionOptions&lt;/a&gt;
&lt;/div&gt;

&lt;i&gt;Switch on/off&lt;/i&gt; session at controller and action level.
&lt;div class="linkbox"&gt;
&lt;a href="http://errtheblog.com/post/24"&gt;http://errtheblog.com/post/24&lt;/a&gt;
&lt;/div&gt;

&lt;i&gt;session_path&lt;/i&gt; and &lt;i&gt;session_secure&lt;/i&gt;
&lt;div class="linkbox"&gt;
&lt;a href="http://corelib.rubyonrails.org/classes/CGI/Session.html"&gt;http://corelib.rubyonrails.org/classes/CGI/Session.html&lt;/a&gt;
&lt;/div&gt;

&lt;p&gt;Refer to next section on options for &lt;a href="#sstorage"&gt;session storage&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Note:&lt;/b&gt; By default &lt;i&gt;session_id&lt;/i&gt; is stored as key in cookies. For multiple rails application from same domain its a good practice to set 'session_key' to avoid conflicts.&lt;/p&gt;



&lt;a&gt;&lt;/a&gt;
&lt;h2&gt;Storage options&lt;/h2&gt;
Ruby on Rails provides you with many session storage option.
&lt;ol&gt;
&lt;li&gt;PStore
&lt;li&gt;ActiveRecordStore
&lt;li&gt;CookieStore
&lt;li&gt;DRbStore
&lt;li&gt;FileStore
&lt;li&gt;MemoryStore
&lt;/ol&gt;

&lt;p&gt;CookieStore is available only in edge rails. PStore is the default option for stable release, whereas its CookieStore as default for edge rails.&lt;/p&gt;

Good description on session stores.
&lt;div class="linkbox"&gt;
&lt;a href="http://errtheblog.com/post/24"&gt;http://errtheblog.com/post/24&lt;/a&gt;&lt;br /&gt;
&lt;a href="http://wiki.rubyonrails.org/rails/pages/HowtoChangeSessionStore"&gt;http://wiki.rubyonrails.org/rails/pages/HowtoChangeSessionStore&lt;/a&gt;
&lt;/div&gt;

Cookie-based session storage
&lt;div class="linkbox"&gt;
&lt;a href="http://ryandaigle.com/articles/2007/2/21/what-s-new-in-edge-rails-cookie-based-sessions"&gt;http://ryandaigle.com/articles/2007/2/21/what-s-new-in-edge-rails-cookie-based-sessions&lt;/a&gt;&lt;br /&gt;
&lt;a href="http://www.caboo.se/articles/2007/2/21/new-controversial-default-rails-session-storage-cookies"&gt;http://www.caboo.se/articles/2007/2/21/new-controversial-default-rails-session-storage-cookies&lt;/a&gt;
&lt;/div&gt;

Improve performance : use SQLSessionStore instead of ActiveRecordStore
&lt;div class="linkbox"&gt;
&lt;a href="http://railsexpress.de/blog/articles/2005/12/19/roll-your-own-sql-session-store"&gt;http://railsexpress.de/blog/articles/2005/12/19/roll-your-own-sql-session-store&lt;/a&gt;&lt;br /&gt;
&lt;a href="http://agilewebdevelopment.com/plugins/sql_session_store"&gt;http://agilewebdevelopment.com/plugins/sql_session_store&lt;/a&gt;
&lt;/div&gt;

Comparison of session storage option
&lt;div class="linkbox"&gt;
&lt;a href="http://scott.elitists.net/sessions.html"&gt;http://scott.elitists.net/sessions.html&lt;/a&gt;
&lt;/div&gt;


&lt;a&gt;&lt;/a&gt;
&lt;h2&gt;Session storage limitations&lt;/h2&gt;

Following objects cannot be stored in session storage:
&lt;ol&gt;
&lt;li&gt;Bindings
&lt;li&gt;Singleton
&lt;li&gt;I/O objects
&lt;li&gt;Procedure objects
&lt;/ol&gt;


Do not store &lt;b&gt;model objects&lt;/b&gt; in session
&lt;ol&gt;
&lt;li&gt;Change in model objects saved in session would also change table row corresponding to model object.
&lt;li&gt;Breaks validations. 
&lt;li&gt;On change in class definition, model objects in session will go out of sync.
  &lt;div class="linkbox"&gt;
    &lt;a href="http://railscasts.com/episodes/13"&gt;http://railscasts.com/episodes/13&lt;/a&gt;
    &lt;a href="http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/268624"&gt;http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/268624&lt;/a&gt;&lt;/div&gt;
&lt;/li&gt;&lt;li&gt;
A general belief is marshalling/unmarshalling of session on each request is expensive. This might be wrong - read Eric Hodel's comment at : 
&lt;div class="linkbox"&gt;
&lt;a href="http://www.caboo.se/articles/2007/2/21/new-controversial-default-rails-session-storage-cookies#comment-1331"&gt;http://www.caboo.se/articles/2007/2/21/new-controversial-...-cookies#comment-1331&lt;/a&gt;
&lt;/li&gt;&lt;/ol&gt;

&lt;p&gt;Incase you are storing model objects in session, upon change in class definition you will need to delete sessions and then restart your applications.&lt;/p&gt;

More limitations :
&lt;ol&gt;
&lt;li&gt;Store only &lt;b&gt;user-specific data&lt;/b&gt;. Session data will become stale if other users can modify/update it. For e.g. if you store blog comments in session then session of active users need to be explicitly updated when new comment in made. &lt;li&gt;&lt;b&gt;Critical information&lt;/b&gt; should be stored in database and not sessions as you might loose information if client cookie is lost/deleted. For e.g. user purchase information on a shopping site.
&lt;li&gt;Session are not meant for storing massive objects or tons of information, use your application database instead.&lt;/p&gt;
&lt;/ol&gt;



&lt;a&gt;&lt;/a&gt;
&lt;h2&gt;Session and Security&lt;/h2&gt;
A detailed look into security issues concerning sessions. Lookout into sections named as 'Session Hijacking' and 'Common Failings'
&lt;div class="linkbox"&gt;
&lt;a href="http://www.technicalinfo.net/papers/WebBasedSessionManagement.html"&gt;http://www.technicalinfo.net/papers/WebBasedSessionManagement.html&lt;/a&gt;
&lt;/div&gt;

Minimize session attacks
&lt;div class="linkbox"&gt;
&lt;a href="http://www.quarkruby.com/2007/9/20/ruby-on-rails-security-guide#sessions"&gt;http://www.quarkruby.com/2007/9/20/ruby-on-rails-security-guide#sessions&lt;/a&gt;
&lt;/div&gt;

Using XSS attacks a hacker can steal user's session-id ... be careful.
&lt;div class="linkbox"&gt;
&lt;a href="http://www.quarkruby.com/2007/9/20/ruby-on-rails-security-guide#xss"&gt;http://www.quarkruby.com/2007/9/20/ruby-on-rails-security-guide#xss&lt;/a&gt;
&lt;/div&gt;



&lt;a&gt;&lt;/a&gt;
&lt;h2&gt;HowTo&lt;/h2&gt;

&lt;a&gt;&lt;/a&gt;
&lt;h3&gt;Implement session expiration&lt;/h3&gt;
A good description
&lt;div class="linkbox"&gt;
&lt;a href="http://wiki.rubyonrails.org/rails/pages/HowtoChangeSessionOptions"&gt;http://wiki.rubyonrails.org/rails/pages/HowtoChangeSessionOptions&lt;/a&gt;
&lt;/div&gt;

A concise version 
&lt;div class="linkbox"&gt;
&lt;a href="http://www.quarkruby.com/2007/9/20/ruby-on-rails-security-guide#sessions"&gt;http://www.quarkruby.com/2007/9/20/ruby-on-rails-security-guide#sessions&lt;/a&gt;
&lt;/div&gt;


&lt;a&gt;&lt;/a&gt;
&lt;h3&gt;Delete stale sessions&lt;/h3&gt;
&lt;p&gt;Every session created in session storage (ActiveReocord, PStore ...) is not deleted upon session expiration or browser close by client. Which means you will have to run a cron job to delete old sessions else your session storage will shoot up in size.&lt;/p&gt;

&lt;p&gt;As a good practice disable sessions for those part of your web application which does not require sessions. This will avoid 
creation and storing unnecessary sessions in your storage.&lt;/p&gt;


&lt;a&gt;&lt;/a&gt;
&lt;h3&gt;Find out active users&lt;/h3&gt;
&lt;div class="linkbox"&gt;
&lt;a href="http://matt-beedle.com/2006/12/13/rails-how-to-find-out-who-is-online/"&gt;http://matt-beedle.com/2006/12/13/rails-how-to-find-out-who-is-online/&lt;/a&gt;
&lt;/div&gt;

&lt;p&gt;If you want to find no. of active users, simply use updated_at column of sessions table.&lt;/p&gt;


&lt;a&gt;&lt;/a&gt;
&lt;h3&gt;Access session data using session_id&lt;/h3&gt;
This might be helpful if another application in same domain wants to access your session.
&lt;div class="linkbox"&gt;
&lt;a href="http://webonrails.com/2006/12/08/accessing-session-data-using-session_id/"&gt;http://webonrails.com/2006/12/08/accessing-session-data-using-session_id/&lt;/a&gt;
&lt;/div&gt;



&lt;a&gt;&lt;/a&gt;
&lt;h2&gt;Miscellaneous&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Use &lt;i&gt;model&lt;/i&gt; method to access row in sessions table corresponding to current session. For e.g. &lt;code class="inline"&gt;session.model.id&lt;/code&gt; or &lt;code class="inline"&gt;session.model.updated_at&lt;/code&gt;&lt;/li&gt;

&lt;li&gt;Smart plugin for better session experience in rails specially for session expiration.
&lt;div class="linkbox"&gt;
&lt;a href="http://agilewebdevelopment.com/plugins/limited_sessions"&gt;http://agilewebdevelopment.com/plugins/limited_sessions&lt;/a&gt;
&lt;/div&gt;&lt;/li&gt;

&lt;li&gt;Flash messages to communicate between actions are stored in sessions. So, if you switch off your sessions, flash messages will stop working.&lt;/li&gt;

&lt;li&gt;Do not let bots make unnecessary sessions
&lt;div class="linkbox"&gt;
&lt;a href="http://jroller.com/obie/entry/wrestling_with_the_bots"&gt;http://jroller.com/obie/entry/wrestling_with_the_bots&lt;/a&gt;
&lt;a href="http://gurge.com/blog/2007/01/08/turn-off-rails-sessions-for-robots/"&gt;http://gurge.com/blog/2007/01/08/turn-off-rails-sessions-for-robots/&lt;/a&gt;
&lt;/div&gt;&lt;/li&gt;

&lt;li&gt;Do not write unchanged sessions back to database -- improves performance
&lt;div class="linkbox"&gt;
&lt;a href="http://pastie.caboo.se/53086"&gt;http://pastie.caboo.se/53086&lt;/a&gt;
&lt;/div&gt;&lt;/li&gt;

&lt;li&gt;Non-cookie session :

&lt;p&gt;If the client has cookies disabled, the session_id must be included as a parameter of all requests sent by the client to the server. The CGI::Session class will transparently add the session_id as a hidden input field to all forms generated. No built-in support is provided for other mechanisms, such as URL re-writing.&lt;/p&gt;

If you care about browsers which do not support cookies, checkout the following plugins (disclaimer : I have never used these plugins :P )
&lt;div class="linkbox"&gt;
Hidden Field Session : &lt;a href="http://agilewebdevelopment.com/plugins/hidden_field_session"&gt;http://agilewebdevelopment.com/plugins/hidden_field_session&lt;/a&gt;&lt;br /&gt;
No cookie session support : &lt;a href="http://www.edgesoft.ca/blog/read/2"&gt;http://www.edgesoft.ca/blog/read/2&lt;/a&gt;
&lt;/div&gt;

&lt;p&gt;Beware, session information in URL might be dangerous. Someone might post a link to a product on a board and everyone following this link is logged with all user data available.&lt;/p&gt;
&lt;/li&gt;


&lt;li&gt;PStore in Windows : Marshal Data Too Short Error
&lt;div class="linkbox"&gt;
&lt;a href="http://wiki.rubyonrails.org/rails/pages/MarshalDataTooShort"&gt;http://wiki.rubyonrails.org/rails/pages/MarshalDataTooShort&lt;/a&gt;
&lt;/div&gt;&lt;/li&gt;
&lt;/ol&gt;




&lt;a&gt;&lt;/a&gt;
&lt;h1&gt;- Cookies -&lt;/h1&gt;

&lt;a&gt;&lt;/a&gt;
&lt;h2&gt;Cookie on rails&lt;/h2&gt;

&lt;p&gt;Cookies are stored at client browser and is sent back to server on each request. Rails provides a hash-like structure ActionController#cookies in controller to manage cookies. Session in rails is implemented using cookies.&lt;/p&gt;

Description, options and example
&lt;div class="linkbox"&gt;
&lt;a href="http://api.rubyonrails.com/classes/ActionController/Cookies.html"&gt;http://api.rubyonrails.com/classes/ActionController/Cookies.html&lt;/a&gt;
&lt;/div&gt;

&lt;b&gt;Note :&lt;/b&gt;
&lt;ol&gt;
&lt;li&gt;Only string can be stored in cookies. 
&lt;li&gt;session_id is by default stored in cookies at client browser.
&lt;/ol&gt;


&lt;a&gt;&lt;/a&gt;
&lt;h2&gt;cookies vs. request.cookies&lt;/h2&gt;
Both cookies and request.cookies are used to access cookie information in your rails application. They are very different in their behavior which can be &lt;b&gt;daunting&lt;/b&gt; for beginners. Examples below explains the basic difference between them.

&lt;table class="CodeRay"&gt;&lt;tr&gt;
  &lt;td title="click to toggle" class="line_numbers"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;6&lt;tt&gt;
&lt;/tt&gt;7&lt;tt&gt;
&lt;/tt&gt;8&lt;tt&gt;
&lt;/tt&gt;9&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;11&lt;tt&gt;
&lt;/tt&gt;12&lt;tt&gt;
&lt;/tt&gt;13&lt;tt&gt;
&lt;/tt&gt;14&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;15&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;16&lt;tt&gt;
&lt;/tt&gt;17&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre&gt;&lt;span class="c"&gt;## cookies and request.cookies are different&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;cookies.class &lt;span class="c"&gt;#=&amp;gt; ActionController::CookieJar&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;request.cookies &lt;span class="c"&gt;#=&amp;gt; Hash&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="c"&gt;## how to access value from cookies and request.cookies&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="c"&gt;# First set some value in cookies&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;cookies[&lt;span class="sy"&gt;:key&lt;/span&gt;] = &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;value&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;cookies[&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;key&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;] &lt;span class="c"&gt;#=&amp;gt; &amp;quot;value&amp;quot;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;cookies[&lt;span class="sy"&gt;:key&lt;/span&gt;] &lt;span class="c"&gt;#=&amp;gt; &amp;quot;value&amp;quot;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="c"&gt;# both the output are of type String&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;request.cookies[&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;key&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;] &lt;span class="c"&gt;#=&amp;gt; &amp;quot;value&amp;quot;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;request.cookies[&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;key&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;].class &lt;span class="c"&gt;#=&amp;gt; CGI::Cookie&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;request.cookies[&lt;span class="sy"&gt;:key&lt;/span&gt;].empty? &lt;span class="c"&gt;#=&amp;gt; true&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;request.cookies[&lt;span class="sy"&gt;:key&lt;/span&gt;].class &lt;span class="c"&gt;#=&amp;gt; Array&lt;/span&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;



&lt;a&gt;&lt;/a&gt;
&lt;h2&gt;CookieJar&lt;/h2&gt;

cookies in rails is of type CookieJar. CookieJar manages incoming and outgoing cookie information and works as follows.

&lt;table class="CodeRay"&gt;&lt;tr&gt;
  &lt;td title="click to toggle" class="line_numbers"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;6&lt;tt&gt;
&lt;/tt&gt;7&lt;tt&gt;
&lt;/tt&gt;8&lt;tt&gt;
&lt;/tt&gt;9&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;11&lt;tt&gt;
&lt;/tt&gt;12&lt;tt&gt;
&lt;/tt&gt;13&lt;tt&gt;
&lt;/tt&gt;14&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;15&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;16&lt;tt&gt;
&lt;/tt&gt;17&lt;tt&gt;
&lt;/tt&gt;18&lt;tt&gt;
&lt;/tt&gt;19&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre&gt;&lt;span class="r"&gt;def&lt;/span&gt; &lt;span class="fu"&gt;index&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  cookies[&lt;span class="sy"&gt;:key&lt;/span&gt;] = &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;val&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  puts cookies[&lt;span class="sy"&gt;:key&lt;/span&gt;]&lt;tt&gt;
&lt;/tt&gt;  redirect_to &lt;span class="sy"&gt;:second_index&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="r"&gt;def&lt;/span&gt; &lt;span class="fu"&gt;second_index&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  cookies[&lt;span class="sy"&gt;:key&lt;/span&gt;] = &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;newval&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  puts cookies[&lt;span class="sy"&gt;:key&lt;/span&gt;]&lt;tt&gt;
&lt;/tt&gt;&lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="c"&gt;## Output :&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="c"&gt;## Open index page for the first time&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="c"&gt;# nil&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="c"&gt;# val&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="c"&gt;## Open index page the second time&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="c"&gt;# newval&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="c"&gt;# val&lt;/span&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;


So, &lt;br /&gt;
&lt;code class="inline"&gt;cookies[]&lt;/code&gt; gives you value from the incoming cookie.&lt;br /&gt;
&lt;code class="inline"&gt;cookies[]=&lt;/code&gt; sets value in the outgoing cookie.&lt;br /&gt;&lt;br /&gt;

Reference :
&lt;div class="linkbox"&gt;
&lt;a href="http://www.40withegg.com/2007/1/5/rails-cookies-mangles-the-hash-interface/"&gt;http://www.40withegg.com/2007/1/5/rails-cookies-mangles-the-hash-interface/&lt;/a&gt;
&lt;/div&gt;



&lt;a&gt;&lt;/a&gt;
&lt;h2&gt;Miscellaneous&lt;/h2&gt;

&lt;p&gt;Checkout &lt;a href="#sstorage"&gt;cookie based session store&lt;/a&gt; explained above.&lt;/p&gt;

Testing cookies
&lt;div class="linkbox"&gt;
&lt;a href="http://www.robbyonrails.com/articles/2006/08/28/testing-cookies-in-ruby-on-rails"&gt;http://www.robbyonrails.com/articles/2006/08/28/testing-cookies-in-ruby-on-rails&lt;/a&gt;
&lt;/div&gt;

Open ticket - making CookieJar behave like a Hash.
&lt;div class="linkbox"&gt;
&lt;a href="http://dev.rubyonrails.org/ticket/9459"&gt;http://dev.rubyonrails.org/ticket/9459&lt;/a&gt;
&lt;/div&gt;

Performance and cookies : a good read
&lt;div class="linkbox"&gt;
&lt;a href="http://yuiblog.com/blog/2007/03/01/performance-research-part-3/"&gt;http://yuiblog.com/blog/2007/03/01/performance-research-part-3/&lt;/a&gt;
&lt;/div&gt;
          </content>  <feedburner:origLink>http://www.quarkruby.com/2007/10/21/sessions-and-cookies-in-ruby-on-rails</feedburner:origLink></entry>
  <entry xml:base="http://www.quarkruby.com/">
    <author>
      <name>admin</name>
    </author>
    <id>tag:www.quarkruby.com,2007-09-20:28</id>
    <published>2007-09-20T05:02:00Z</published>
    <updated>2007-10-20T19:13:06Z</updated>
    <category term="guides" />
    <category term="ruby on rails" />
    <category term="security" />
    <link href="http://feedproxy.google.com/~r/Quarkruby/~3/GRks7VB5tKc/ruby-on-rails-security-guide" rel="alternate" type="text/html" />
    <title>Ruby on Rails Security Guide</title>
<summary type="html">&lt;p&gt;Ruby on Rails does a decent job in handling security concerns in the background. You will have to configure your application to avoid few security attacks while plugins would be required for many security concerns which are not at all or poorly managed by rails.&lt;/p&gt;

&lt;p&gt;In this article I have described the security issues related to a ruby on rails web application. I have followed &lt;abbr title="Don't Repeat Yourself"&gt;DRY&lt;/abbr&gt; by linking to articles with good explanation and solutions to security concerns wherever required. This guide can also be used as a quick security check for your current web application. &lt;/p&gt;

&lt;h2&gt;Table of Contents &lt;/h2&gt;
&lt;ol&gt;
   &lt;li&gt;&lt;a href="#authen"&gt;Authentication&lt;/a&gt;
   &lt;li&gt;&lt;a href="#model"&gt;Model&lt;/a&gt;
      &lt;ol&gt;
          &lt;li&gt;&lt;a href="#sqlinjection"&gt;SQL Injection&lt;/a&gt;
          &lt;li&gt;&lt;a href="#validation"&gt;Activerecord Validation&lt;/a&gt;
          &lt;li&gt;&lt;a href="#crdfp"&gt;Creating records directly from parameters&lt;/a&gt;
      &lt;/ol&gt;
   &lt;li&gt;&lt;a href="#controller"&gt;Controller&lt;/a&gt;
      &lt;ol&gt;
          &lt;li&gt;&lt;a href="#em"&gt;Exposing methods&lt;/a&gt;
          &lt;li&gt;&lt;a href="#authorization"&gt;Authorize parameters&lt;/a&gt;
          &lt;li&gt;&lt;a href="#fsl"&gt;Filter sensitive logs&lt;/a&gt;
          &lt;li&gt;&lt;a href="#csrf"&gt;Cross Site Reference(or Request) Forgery (CSRF)&lt;/a&gt;
          &lt;li&gt;&lt;a href="#sessions"&gt;Minimize session attacks&lt;/a&gt;
          &lt;li&gt;&lt;a href="#dnsbl"&gt;Stop spam on your website from DNS Blacklist&lt;/a&gt;
          &lt;li&gt;&lt;a href="#cap"&gt;Caching authenticated pages&lt;/a&gt;
      &lt;/ol&gt;
   &lt;li&gt;&lt;a href="#view"&gt;View&lt;/a&gt;
      &lt;ol&gt;
          &lt;li&gt;&lt;a href="#xss"&gt;Cross site scripting(XSS) attack&lt;/a&gt;
          &lt;li&gt;&lt;a href="#asfp"&gt;Anti-spam form protection&lt;/a&gt;
          &lt;li&gt;&lt;a href="#mailto"&gt;Hide mailto links&lt;/a&gt;
          &lt;li&gt;&lt;a href="#upse"&gt;Use password strength evaluators&lt;/a&gt;
      &lt;/ol&gt;
   &lt;li&gt;&lt;a href="#misc"&gt;Miscellaneous&lt;/a&gt;
     &lt;ol&gt;
          &lt;li&gt;&lt;a href="#transmission"&gt;Transmission of Sensitive information&lt;/a&gt;
          &lt;li&gt;&lt;a href="#fileupload"&gt;File upload&lt;/a&gt;
          &lt;li&gt;&lt;a href="#environment"&gt;Secure your setup / environment&lt;/a&gt;
          &lt;li&gt;&lt;a href="#mysql"&gt;Mysql configuration&lt;/a&gt; 
          &lt;li&gt;&lt;a href="#goodpassword"&gt;Use good passwords&lt;/a&gt;
     &lt;/ol&gt;
   &lt;li&gt;&lt;a href="#directory"&gt;Security plugins directory&lt;/a&gt;
&lt;/ol&gt;</summary><content type="html">
            &lt;p&gt;Ruby on Rails does a decent job in handling security concerns in the background. You will have to configure your application to avoid few security attacks while plugins would be required for many security concerns which are not at all or poorly managed by rails.&lt;/p&gt;

&lt;p&gt;In this article I have described the security issues related to a ruby on rails web application. I have followed &lt;abbr title="Don't Repeat Yourself"&gt;DRY&lt;/abbr&gt; by linking to articles with good explanation and solutions to security concerns wherever required. This guide can also be used as a quick security check for your current web application. &lt;/p&gt;

&lt;h2&gt;Table of Contents &lt;/h2&gt;
&lt;ol&gt;
   &lt;li&gt;&lt;a href="#authen"&gt;Authentication&lt;/a&gt;
   &lt;li&gt;&lt;a href="#model"&gt;Model&lt;/a&gt;
      &lt;ol&gt;
          &lt;li&gt;&lt;a href="#sqlinjection"&gt;SQL Injection&lt;/a&gt;
          &lt;li&gt;&lt;a href="#validation"&gt;Activerecord Validation&lt;/a&gt;
          &lt;li&gt;&lt;a href="#crdfp"&gt;Creating records directly from parameters&lt;/a&gt;
      &lt;/ol&gt;
   &lt;li&gt;&lt;a href="#controller"&gt;Controller&lt;/a&gt;
      &lt;ol&gt;
          &lt;li&gt;&lt;a href="#em"&gt;Exposing methods&lt;/a&gt;
          &lt;li&gt;&lt;a href="#authorization"&gt;Authorize parameters&lt;/a&gt;
          &lt;li&gt;&lt;a href="#fsl"&gt;Filter sensitive logs&lt;/a&gt;
          &lt;li&gt;&lt;a href="#csrf"&gt;Cross Site Reference(or Request) Forgery (CSRF)&lt;/a&gt;
          &lt;li&gt;&lt;a href="#sessions"&gt;Minimize session attacks&lt;/a&gt;
          &lt;li&gt;&lt;a href="#dnsbl"&gt;Stop spam on your website from DNS Blacklist&lt;/a&gt;
          &lt;li&gt;&lt;a href="#cap"&gt;Caching authenticated pages&lt;/a&gt;
      &lt;/ol&gt;
   &lt;li&gt;&lt;a href="#view"&gt;View&lt;/a&gt;
      &lt;ol&gt;
          &lt;li&gt;&lt;a href="#xss"&gt;Cross site scripting(XSS) attack&lt;/a&gt;
          &lt;li&gt;&lt;a href="#asfp"&gt;Anti-spam form protection&lt;/a&gt;
          &lt;li&gt;&lt;a href="#mailto"&gt;Hide mailto links&lt;/a&gt;
          &lt;li&gt;&lt;a href="#upse"&gt;Use password strength evaluators&lt;/a&gt;
      &lt;/ol&gt;
   &lt;li&gt;&lt;a href="#misc"&gt;Miscellaneous&lt;/a&gt;
     &lt;ol&gt;
          &lt;li&gt;&lt;a href="#transmission"&gt;Transmission of Sensitive information&lt;/a&gt;
          &lt;li&gt;&lt;a href="#fileupload"&gt;File upload&lt;/a&gt;
          &lt;li&gt;&lt;a href="#environment"&gt;Secure your setup / environment&lt;/a&gt;
          &lt;li&gt;&lt;a href="#mysql"&gt;Mysql configuration&lt;/a&gt; 
          &lt;li&gt;&lt;a href="#goodpassword"&gt;Use good passwords&lt;/a&gt;
     &lt;/ol&gt;
   &lt;li&gt;&lt;a href="#directory"&gt;Security plugins directory&lt;/a&gt;
&lt;/ol&gt;

&lt;br /&gt;

&lt;a&gt;&lt;/a&gt;
&lt;h2&gt;Authentication&lt;/h2&gt;
&lt;p&gt;Authentication is the foremost requirement of most of the web applications to authenticate and give privileges to their users. Apart from normal authentication mechanism rails have plugins for OpenID, CAS and Access Control. Build your own authentication system only if your requirements are very unique or you do not trust other implementations.&lt;/p&gt;

Plugin - &lt;b&gt;Restful Authentication&lt;/b&gt; (recommended) - easy to use and you can tweak it according to your requirements.
&lt;div class="linkbox"&gt;
&lt;a href="http://railscasts.com/episodes/67"&gt;http://railscasts.com/episodes/67&lt;/a&gt;
&lt;a href="http://svn.techno-weenie.net/projects/plugins/restful_authentication/"&gt;http://svn.techno-weenie.net/projects/plugins/restful_authentication/&lt;/a&gt;
&lt;/div&gt;

&lt;b&gt;Build your own authentication&lt;/b&gt;. You should rarely need to do this ... Restful Authentication is quite flexible.
&lt;div class="linkbox"&gt;
&lt;a href="http://www.aidanf.net/rails_user_authentication_tutorial"&gt;http://www.aidanf.net/rails_user_authentication_tutorial&lt;/a&gt;
&lt;/div&gt;

&lt;b&gt;OpenID&lt;/b&gt; - a universal authentication system to avoid use of multiple username and password on the Internet. OpenID is getting quite famous now-a-days.
&lt;div class="linkbox"&gt;
&lt;a href="http://media.railscasts.com/videos/068_openid_authentication.mov"&gt;http://media.railscasts.com/videos/068_openid_authentication.mov&lt;/a&gt;
&lt;a href="http://agilewebdevelopment.com/plugins/openidauthentication"&gt;http://agilewebdevelopment.com/plugins/openidauthentication&lt;/a&gt;
&lt;/div&gt;

&lt;b&gt;Access Control&lt;/b&gt; : To easily proivde different priviliges to your users. There are a lot of cool plugins available for access control.
&lt;div class="linkbox"&gt;
&lt;a href="https://opensvn.csie.org/traccgi/tobionrails"&gt;https://opensvn.csie.org/traccgi/tobionrails&lt;/a&gt;&lt;br /&gt;
&lt;a href="http://code.google.com/p/rolerequirement/"&gt;http://code.google.com/p/rolerequirement/&lt;/a&gt;&lt;br /&gt;
&lt;a href="http://agilewebdevelopment.com/plugins/activeacl_rails_authorization_system"&gt;http://agilewebdevelopment.com/plugins/activeacl_rails_authorization_system&lt;/a&gt;
&lt;/div&gt;

&lt;b&gt;Centralized Authentication Server&lt;/b&gt; - is used to implement single login/password for your users across multiple application. It can also be used for a single sign-on system. For example, Gmail and Google Reader have a single sign-on between them.
&lt;div class="linkbox"&gt;
&lt;a href="http://agilewebdevelopment.com/plugins/cas_authentication_filter"&gt;http://agilewebdevelopment.com/plugins/cas_authentication_filter&lt;/a&gt;
&lt;/div&gt;

Use &lt;b&gt;Google Authentication API&lt;/b&gt; to let your users login using their google username and password.
&lt;div class="linkbox"&gt;
&lt;a href="http://rubyforge.org/projects/asgoogleaccount/"&gt;http://rubyforge.org/projects/asgoogleaccount/&lt;/a&gt;
&lt;/div&gt;

&lt;b&gt;More Plugins&lt;/b&gt; :
&lt;div class="linkbox"&gt;
Rails inbuilt Authentication -  &lt;a href="http://ryandaigle.com/articles/2006/12/4/whats-new-in-edge-rails-new-http-authentication-plugin-and-a-plea-to-contribute"&gt;http://ryandaigle.com/articles/2006/12/4/whats-new-in...&lt;/a&gt;&lt;br /&gt;
Acts_as_authenticated - &lt;a href="http://technoweenie.stikipad.com/plugins/show/User+Authentication"&gt;http://technoweenie.stikipad.com/plugins/show/User+Authentication&lt;/a&gt;&lt;br /&gt;
Super Simple Authentication - &lt;a href="http://ariejan.net/2007/08/24/super-simple-authentication-plugin-and-generator/"&gt;http://ariejan.net/2007/08/24/super-simple-...&lt;/a&gt;
&lt;/div&gt;



&lt;br /&gt;
&lt;a&gt;&lt;/a&gt;
&lt;h1&gt;- Model -&lt;/h1&gt;



&lt;a&gt;&lt;/a&gt;
&lt;h2&gt;SQL Injection&lt;/h2&gt;
&lt;p&gt;The problem arises when metacharacters are injected into your queries to database. Rails has a very good support to avoid SQL injection if you follow conventions in issuing queries to your database.&lt;/p&gt;

&lt;b&gt;Description&lt;/b&gt; :
&lt;div class="linkbox"&gt;
&lt;a href="http://manuals.rubyonrails.com/read/chapter/43"&gt;http://manuals.rubyonrails.com/read/chapter/43&lt;/a&gt;
&lt;/div&gt;

&lt;b&gt;Alternate Solution&lt;/b&gt; - use hash for specifying conditions in &lt;code class="inline"&gt;#find&lt;/code&gt;&lt;/br&gt;
&lt;div class="linkbox"&gt;
&lt;a href="http://weblog.rubyonrails.org/2006/11/26/1-2-new-in-activerecord"&gt;http://weblog.rubyonrails.org/2006/11/26/1-2-new-in-activerecord&lt;/a&gt;
&lt;/div&gt;



&lt;a&gt;&lt;/a&gt;
&lt;h2&gt;Activerecord Validation&lt;/h2&gt;
&lt;p&gt;To validate the contents of model object before records are created/modified in the database. Activerecord validations are very useful over database data-type constraints to ensure values entered into the database follow your rules. You might have javascript validations for forms but javascript can easily be switched off. Use javascript validations only for better user experience.&lt;/p&gt;

&lt;b&gt;Description&lt;/b&gt; :
&lt;div class="linkbox"&gt;
&lt;a href="http://rails.rubyonrails.com/classes/ActiveRecord/Validations/ClassMethods.html"&gt;http://rails.rubyonrails.com/classes/ActiveRecord/Validations/ClassMethods.html&lt;/a&gt;
&lt;/div&gt;

&lt;b&gt;Conditional validation&lt;/b&gt; using &lt;code class="inline"&gt;:on&lt;/code&gt; and &lt;code class="inline"&gt;:if&lt;/code&gt; options. Checkout this cool video
&lt;div class="linkbox"&gt;
&lt;a href="http://media.railscasts.com/videos/041_conditional_validations.mov"&gt;http://media.railscasts.com/videos/041_conditional_validations.mov&lt;/a&gt;
&lt;/div&gt;

Be careful using &lt;b&gt;validates_uniqueness_of&lt;/b&gt;, it has problems when used with &lt;code class="inline"&gt;:scope&lt;/code&gt; option. Open bug tickets :
&lt;div class="linkbox"&gt;
&lt;a href="http://dev.rubyonrails.org/ticket/5608"&gt;http://dev.rubyonrails.org/ticket/5608&lt;/a&gt;&lt;br /&gt;
&lt;a href="http://dev.rubyonrails.org/ticket/9235"&gt;http://dev.rubyonrails.org/ticket/9235&lt;/a&gt;&lt;br /&gt;
&lt;a href="http://dev.rubyonrails.org/ticket/8811"&gt;http://dev.rubyonrails.org/ticket/8811&lt;/a&gt;&lt;br /&gt;
&lt;a href="http://dev.rubyonrails.org/ticket/8774"&gt;http://dev.rubyonrails.org/ticket/8774&lt;/a&gt;
&lt;/div&gt;

Use &lt;b&gt;:allow_blank&lt;/b&gt; to pass validations if value is nil or empty string
&lt;div class="linkbox"&gt;
&lt;a href="http://ryandaigle.com/articles/2007/9/5/what-s-new-in-edge-rails-validations-now-allow_blank"&gt;http://ryandaigle.com/articles/2007/9/5/what-s-new-in-edge-rails-validations-now-allow_blank&lt;/a&gt;
&lt;/div&gt;

&lt;b&gt;Testing Validations&lt;/b&gt; - do read the comments in this article
&lt;div class="linkbox"&gt;
&lt;a href="http://blog.jayfields.com/2006/12/rails-unit-testing-activerecord.html"&gt;http://blog.jayfields.com/2006/12/rails-unit-testing-activerecord.html
&lt;/a&gt;
&lt;/div&gt;

&lt;b&gt;Useful Tips&lt;/b&gt;
&lt;ul&gt;
&lt;li&gt;Its easy to manage 'nil' values using &lt;code class="inline"&gt;:allow_nil&lt;/code&gt;, its quite handy. For ex: set &lt;code class="inline"&gt;:allow_nil =&gt; true&lt;/code&gt; in validates_uniqueness_of to check uniqueness of non-nil values and ignore nil values
&lt;li&gt; validates_presence_of is not required if you are using validates_format_of, unless regular expression accepts empty string.
&lt;/ul&gt;



&lt;a&gt;&lt;/a&gt;
&lt;h2&gt;Creating records directly from parameters&lt;/h2&gt;
&lt;p&gt;While creating database records directly from form params, a malicious user can add extra fields into the params and manually submit the web page which will set values of fields which you do not want user to set.&lt;/p&gt;

&lt;b&gt;Description&lt;/b&gt; :
&lt;div class="linkbox"&gt;
&lt;a href="http://manuals.rubyonrails.com/read/chapter/47"&gt;http://manuals.rubyonrails.com/read/chapter/47&lt;/a&gt;
&lt;/div&gt;

&lt;b&gt;Alternate Solution&lt;/b&gt; - Trim the parameters to keep the required keys and remove the others.
&lt;div class="linkbox"&gt;
&lt;a href="http://wiki.rubyonrails.org/rails/pages/HowToPreventFormInjection"&gt;http://wiki.rubyonrails.org/rails/pages/HowToPreventFormInjection&lt;/a&gt;
&lt;/div&gt;
&lt;br /&gt;



&lt;a&gt;&lt;/a&gt;
&lt;h1&gt;- Controller -&lt;/h1&gt;



&lt;a&gt;&lt;/a&gt;
&lt;h2&gt;Exposing methods&lt;/h2&gt;
&lt;p&gt;Use private and protected in controller for methods which should not be actions. Actions are pubic methods and can be invoked from the browser.&lt;/p&gt;

&lt;b&gt;hide_action&lt;/b&gt; : If non-action controller methods must be public, hide them using hide_action.
&lt;div class="linkbox"&gt;
&lt;a href="http://www.mathewabonyi.com/articles/2006/08/11/hide_action-a-hidden-treasure"&gt;http://www.mathewabonyi.com/articles/2006/08/11/hide_action-a-hidden-treasure&lt;/a&gt;
&lt;/div&gt;

Be careful of bypassing private and protected using &lt;b&gt;meta-programming&lt;/b&gt;
&lt;div class="linkbox"&gt;
&lt;a href="http://dev.zeraweb.com/design-blog-14"&gt;http://dev.zeraweb.com/design-blog-14&lt;/a&gt;
&lt;/div&gt;



&lt;a&gt;&lt;/a&gt;
&lt;h2&gt;Authorize parameters&lt;/h2&gt;
&lt;p&gt;Always authorize user request. By tweaking form parameters or url a user can send request to view/modify other users information if there is no proper authorization of parameters.&lt;/p&gt;
For example :

&lt;table class="CodeRay"&gt;&lt;tr&gt;
  &lt;td title="click to toggle" class="line_numbers"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;6&lt;tt&gt;
&lt;/tt&gt;7&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre&gt;&lt;span class="c"&gt;## To find information of an order which belongs to a particular user.&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="c"&gt;#Incorrect :&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="iv"&gt;@order&lt;/span&gt; = &lt;span class="co"&gt;Order&lt;/span&gt;.find(order_id)&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="c"&gt;#Correct :&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="iv"&gt;@order&lt;/span&gt; = &lt;span class="iv"&gt;@user&lt;/span&gt;.orders.find(order_id)&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;


Do not ignore &lt;b&gt;hidden fields&lt;/b&gt; - a user can easily modify their value, so suspect them similar to params[:id]
&lt;div class="linkbox"&gt;
&lt;a href="http://searchsecurity.techtarget.com/tip/1,289483,sid14_gci1153816,00.html"&gt;http://searchsecurity.techtarget.com/tip/1,289483,sid14_gci1153816,00.html&lt;/a&gt;
&lt;/div&gt;



&lt;a&gt;&lt;/a&gt;
&lt;h2&gt;Filter sensitive logs&lt;/h2&gt;
&lt;p&gt;Prevent logs of sensitive unencrypted data using &lt;code class="inline"&gt;#filter_parameter_logging&lt;/code&gt; in controller.  The default behavior is to log request parameters in production as well as development environment, and you would not like logging of password, credit card number, etc.&lt;/p&gt;

&lt;b&gt;Video Tutorial&lt;/b&gt;
&lt;div class="linkbox"&gt;
&lt;a href="http://railscasts.com/episodes/9"&gt;http://railscasts.com/episodes/9&lt;/a&gt;
&lt;/div&gt;



&lt;a&gt;&lt;/a&gt;
&lt;h2&gt;Cross Site Reference(or Request) Forgery (CSRF)&lt;/h2&gt;
&lt;p&gt;In a CSRF attack, the attacker makes victim click on a link of his choice which would contain a GET/POST request and causes web application to take malicious action. The link could be embedded in a iframe or an img tag. Its recommended to use secret token while communicating with user to avoid this attack. &lt;/p&gt;
&lt;p&gt;Its little complex to understand this attack. So, only those readers who are very enthusiastic to know about it, please read the &lt;b&gt;Description&lt;/b&gt; below. Rest can directly move ahead to use the plugin.&lt;/p&gt;

&lt;b&gt;Description&lt;/b&gt; :
&lt;div class="linkbox"&gt;
&lt;a href="http://isc.sans.org/diary.html?storyid=1750"&gt;http://isc.sans.org/diary.html?storyid=1750&lt;/a&gt;
&lt;a href="http://en.wikipedia.org/wiki/Cross-site_request_forgery"&gt;http://en.wikipedia.org/wiki/Cross-site_request_forgery&lt;/a&gt;
&lt;/div&gt;

Use &lt;b&gt;Get and Post&lt;/b&gt; appropiately (note : Both get and post are vulnerable to CSRF)
&lt;div class="linkbox"&gt;
&lt;a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.1.1"&gt;http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.1.1&lt;/a&gt;
&lt;/div&gt;

&lt;b&gt;Example&lt;/b&gt; - Gmail CSRF security flaw
&lt;div class="linkbox"&gt;
&lt;a href="http://ajaxian.com/archives/gmail-csrf-security-flaw"&gt;http://ajaxian.com/archives/gmail-csrf-security-flaw&lt;/a&gt;
&lt;/div&gt;

Plugin - &lt;b&gt;CSRF Killer&lt;/b&gt; (recommended) - it requires edge rails
&lt;div class="linkbox"&gt;
&lt;a href="http://svn.techno-weenie.net/projects/plugins/csrf_killer/"&gt;http://svn.techno-weenie.net/projects/plugins/csrf_killer/&lt;/a&gt;&lt;br /&gt;
&lt;a href="http://activereload.net/2007/3/6/your-requests-are-safe-with-us"&gt;http://activereload.net/2007/3/6/your-requests-are-safe-with-us&lt;/a&gt;
&lt;/div&gt;

&lt;div class="linkbox"&gt;
Secure action - &lt;a href="http://code.google.com/p/secure-action-plugin/"&gt;http://code.google.com/p/secure-action-plugin/&lt;/a&gt;&lt;br /&gt;
Security extension - &lt;a href="http://svn.aviditybytes.com/rails/plugins/security_extensions/"&gt;http://svn.aviditybytes.com/rails/plugins/security_extensions/&lt;/a&gt;
&lt;/div&gt;



&lt;a&gt;&lt;/a&gt;
&lt;h2&gt;Minimize session attacks&lt;/h2&gt;
&lt;p&gt;If an attacker has session-id of your user, he can create HTTP requests to access user account. An attacker can get session-id by direct access to user machine or is able to successfully run malicious scripts at user machine. In this section we will talk about how to avoid or minimize the risk if attacker has user session-id. Following steps are helpful:
&lt;ol&gt;
  &lt;li&gt;Store IP Address, but creates problem if user moves from one network to another.
  &lt;li&gt;Create a new session everytime someone logs in.
  &lt;li&gt;Expire session on user logout, user is idle for a time period or on closing of browser/tab. For maximum security expire sessions on all the three conditions. 
&lt;/ol&gt;
&lt;/p&gt;

&lt;b&gt;Code for session expiry on timeout&lt;/b&gt;
&lt;table class="CodeRay"&gt;&lt;tr&gt;
  &lt;td title="click to toggle" class="line_numbers"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;6&lt;tt&gt;
&lt;/tt&gt;7&lt;tt&gt;
&lt;/tt&gt;8&lt;tt&gt;
&lt;/tt&gt;9&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;11&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre&gt;&lt;span class="c"&gt;## Timeout after inactivity of one hour.&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="co"&gt;MAX_SESSION_PERIOD&lt;/span&gt; = &lt;span class="i"&gt;3600&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;before_filter &lt;span class="sy"&gt;:session_expiry&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="r"&gt;def&lt;/span&gt; &lt;span class="fu"&gt;session_expiry&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;   reset_session &lt;span class="r"&gt;if&lt;/span&gt; session[&lt;span class="sy"&gt;:expiry_time&lt;/span&gt;] &lt;span class="r"&gt;and&lt;/span&gt; session[&lt;span class="sy"&gt;:expiry_time&lt;/span&gt;] &amp;lt; &lt;span class="co"&gt;Time&lt;/span&gt;.now&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;   session[&lt;span class="sy"&gt;:expiry_time&lt;/span&gt;] = &lt;span class="co"&gt;MAX_SESSION_PERIOD&lt;/span&gt;.seconds.from_now&lt;tt&gt;
&lt;/tt&gt;   &lt;span class="r"&gt;return&lt;/span&gt; &lt;span class="pc"&gt;true&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="r"&gt;end&lt;/span&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;


Plugin - &lt;b&gt;Session Expiration&lt;/b&gt; for session expiry on timeout
&lt;div class="linkbox"&gt;
&lt;a href="http://www.naffis.com/2007/5/22/automatically-expiring-sessions-in-rails"&gt;http://www.naffis.com/2007/5/22/automatically-expiring-sessions-in-rails&lt;/a&gt;
&lt;/div&gt;

Do not put expiry time in the cookie unless your cookie information is properly encrypted. If not, use server side session expiry.
&lt;div class="linkbox"&gt;
&lt;a href="http://wiki.rubyonrails.org/rails/pages/HowtoChangeSessionOptions"&gt;http://wiki.rubyonrails.org/rails/pages/HowtoChangeSessionOptions&lt;/a&gt;
&lt;/div&gt;

Persistent session / login in rails - global setting in enviornment.rb
&lt;table class="CodeRay"&gt;&lt;tr&gt;
  &lt;td title="click to toggle" class="line_numbers"&gt;&lt;pre&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre&gt;&lt;span class="co"&gt;ActionController&lt;/span&gt;::&lt;span class="co"&gt;Base&lt;/span&gt;.session_options[&lt;span class="sy"&gt;:session_expires&lt;/span&gt;] = &amp;lt;i&amp;gt;say after two years&amp;lt;&lt;span class="rx"&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;span class="k"&gt;i&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;


Persistent session / login in rails - to give your users a feature - &lt;b&gt;remember me&lt;/b&gt;
&lt;div class="linkbox"&gt;
&lt;a href="http://blog.codahale.com/2006/04/08/dynamic-session-expiration-times-with-rails/"&gt;http://blog.codahale.com/2006/04/08/dynamic-session-expiration-times-with-rails/&lt;/a&gt;
&lt;a href="http://www.onrails.org/articles/2006/02/18/auto-login"&gt;http://www.onrails.org/articles/2006/02/18/auto-login&lt;/a&gt;
&lt;a href="http://livsey.org/2006/6/30/persistent-logins-in-rails"&gt;http://livsey.org/2006/6/30/persistent-logins-in-rails&lt;/a&gt;
&lt;/div&gt;



&lt;a&gt;&lt;/a&gt;
&lt;h2&gt;Stop spam on your website from DNS Blacklist&lt;/h2&gt;
&lt;p&gt;Avoid access to your website from IP addresses which are present in DNS Blacklist(DNSBL).&lt;/p&gt;

Plugin - &lt;b&gt;DNSBL check&lt;/b&gt;
&lt;div class="linkbox"&gt;
&lt;a href="http://spacebabies.nl/dnsbl_check/"&gt;http://spacebabies.nl/dnsbl_check/&lt;/a&gt;
&lt;/div&gt;



&lt;a&gt;&lt;/a&gt;
&lt;h2&gt;Caching authenticated pages&lt;/h2&gt;
&lt;p&gt;Page caching does bypass any security filters in your application. So avoid caching authenticated pages and use action or fragment caching instead.&lt;/p&gt;
&lt;br /&gt;


&lt;a&gt;&lt;/a&gt;
&lt;h1&gt;- View -&lt;/h1&gt;

&lt;a&gt;&lt;/a&gt;
&lt;h2&gt;Cross site scripting(XSS) attack&lt;/h2&gt;
&lt;p&gt;Cross Site Scripting is a technique found in web applications which allow code injection by malicious web users into the web pages viewed by other users. An attacker can steal login of your user by stealing his cookie. The most common method of attack is to place javascript code on a website that can receive the session cookie. To avoid  the attack, escape HTML meta characters which will avoid execution of malicious Javascript code. Ruby on Rails has inbuilt methods like escape_html() (h()), url_encode(), sanatize(), etc to escape HTML meta characters.&lt;/p&gt;

&lt;b&gt;Description&lt;/b&gt;
&lt;div class="linkbox"&gt;
&lt;a href="http://manuals.rubyonrails.com/read/chapter/44"&gt;http://manuals.rubyonrails.com/read/chapter/44&lt;/a&gt;
&lt;/div&gt;

&lt;b&gt;Can we avoid tedious use of h() in views?&lt;/b&gt;
&lt;div class="linkbox"&gt;
&lt;a href="http://wiki.rubyonrails.org/rails/pages/HowToEscapeHTML"&gt;http://wiki.rubyonrails.org/rails/pages/HowToEscapeHTML&lt;/a&gt;
&lt;/div&gt;

&lt;b&gt;Sanitize()&lt;/b&gt; is used to escape script tags and other malicious content other than html tags. Avoid using it ... its unsecure. Use white_list instead.
&lt;div class="linkbox"&gt;
&lt;a href="http://www.rorsecurity.info/2007/08/17/dont-use-strip_tags-strip_links-and-sanitize/"&gt;http://www.rorsecurity.info/2007/08/17/dont-use-strip_tags-strip_links-and-sanitize/&lt;/a&gt;
&lt;/div&gt;

&lt;b&gt;White_list&lt;/b&gt; plugin
&lt;div class="linkbox"&gt;
&lt;a href="http://svn.techno-weenie.net/projects/plugins/white_list/README"&gt;http://svn.techno-weenie.net/projects/plugins/white_list/README&lt;/a&gt;
&lt;/div&gt;



&lt;a&gt;&lt;/a&gt;
&lt;h2&gt;Anti-spam form protection&lt;/h2&gt;

&lt;p&gt;Use &lt;a href="http://en.wikipedia.org/wiki/Captcha"&gt;Captcha&lt;/a&gt; or Javascript based form protection techniques to ensure only human can submit forms successfully.&lt;/p&gt; 

&lt;p&gt;When using Captcha do ensure the following :
&lt;ol&gt;
   &lt;li&gt;Images are rendered on webpage using &lt;code class="inline"&gt;send_data&lt;/code&gt; and are not stored at the server, because its not required to store images and are redundant.
   &lt;li&gt;Avoid using algorithm used by standard Catpcha plugins as they can easily be hacked, instead tweak an existing algorithm or write your own.
   &lt;li&gt;Use a Captcha which does not store secret code or images in filesystem, as you will have trouble using Captcha with multiple servers.
&lt;/ol&gt;
&lt;/p&gt;

&lt;b&gt;Tutorial&lt;/b&gt; - a nice article on concepts of captcha
&lt;div class="linkbox"&gt;
&lt;a href="http://revolutiononrails.blogspot.com/2007/04/pedo-mellon-minno-or-captcha-on-rails.html"&gt;http://revolutiononrails.blogspot.com/2007/04/pedo-mellon-minno-or-captcha-on-rails.html&lt;/a&gt;
&lt;/div&gt;

Plugin - &lt;b&gt;ReCaptcha&lt;/b&gt; (recommended)
&lt;div class="linkbox"&gt;
&lt;a href="http://recaptcha.net/"&gt;http://recaptcha.net/&lt;/a&gt;&lt;br /&gt;
&lt;a href="http://ambethia.com/recaptcha/"&gt;http://ambethia.com/recaptcha/&lt;/a&gt;
&lt;/div&gt;

Plugin - BrainBuster - a &lt;b&gt;logic captcha&lt;/b&gt; based on simple puzzles, math and word problems. By default, it has limited set of problems and you would have to come up with large set of your own problems.
&lt;div class="linkbox"&gt;
&lt;a href="http://robsanheim.com/brain-buster"&gt;http://robsanheim.com/brain-buster&lt;/a&gt;
&lt;/div&gt;

Plugin - &lt;b&gt;Simple Captcha&lt;/b&gt; (not recommended) as it breaks all the must have features of a good Captcha implementation.
&lt;div class="linkbox"&gt;
&lt;a href="http://expressica.com/2007/03/23/simple_captcha_1_0/"&gt;http://expressica.com/2007/03/23/simple_captcha_1_0/&lt;/a&gt;
&lt;/div&gt;

For less critical systems like blogs, a more &lt;b&gt;user-friendly option&lt;/b&gt; can be use of CSS based technique or JavaScript based plugin unlike Captcha. Both JavaScript and CSS based techniques can only avoid spam from dumb or general bots. If an hacker specifically targets your site or bot is smart enough, you are dead,  so be careful.
&lt;div class="linkbox"&gt;
CSS based Negative Captcha - &lt;a href="http://damienkatz.net/2007/01/negative_captch.html"&gt;http://damienkatz.net/2007/01/negative_captch.html&lt;/a&gt;&lt;br /&gt;
Inverse Captcha for Mephisto - &lt;a href="http://www.artweb-design.de/projects/mephisto-plugin-inverse-captcha-for-comments-anti-spam"&gt;http://www.artweb-design.de/projects/mephisto-plugin-inverse...&lt;/a&gt;&lt;br /&gt;
JavaScript based Form Spam Protection - &lt;a href="http://form-spam-protection.googlecode.com/svn/form_spam_protection/"&gt;http://form-spam-protection.googlecode.com/svn/form...&lt;/a&gt;
&lt;/div&gt;

&lt;b&gt;Captcha with Multiple Servers&lt;/b&gt;
&lt;div class="linkbox"&gt;
&lt;a href="http://upstream-berlin.com/blog/2007/08/17/captchas-with-rails-and-multiple-servers/"&gt;http://upstream-berlin.com/blog/2007/08/17/captchas-with-rails-and-multiple-servers/&lt;/a&gt;
&lt;/div&gt;



&lt;a&gt;&lt;/a&gt;
&lt;h2&gt;Hide mailto links&lt;/h2&gt;
&lt;p&gt;Mailto links in a webpage can be attacked by e-mail harvesting bots. Use the plugin CipherMail to generate a 1024 bit random key and obfuscate the mailto link.&lt;/p&gt;

Plugin - &lt;b&gt;CipherMail&lt;/b&gt;
&lt;div class="linkbox"&gt;
&lt;a href="http://agilewebdevelopment.com/plugins/ciphermail"&gt;http://agilewebdevelopment.com/plugins/ciphermail&lt;/a&gt;
&lt;/div&gt;



&lt;a&gt;&lt;/a&gt;
&lt;h2&gt;Use password strength evaluators&lt;/h2&gt;
&lt;p&gt;A lot of people have used password strength evaluators simply because its used by google in their registration form. You can use it to help your users register with strong password. But I don't think its a must have security addon. Uptill now I have not found a good algorithm to assess strength of a password, but some of them are reasonable.&lt;/p&gt;

&lt;p&gt;Also, if there is an open source tool or algorithm for evaluating password strength, it can easily be broken. So, you might consider tweaking the algorithm or building one from scratch.&lt;/p&gt;

&lt;b&gt;Tools&lt;/b&gt;
&lt;div class="linkbox"&gt;
&lt;a href="http://www.certainkey.com/demos/password/"&gt;http://www.certainkey.com/demos/password/&lt;/a&gt;
&lt;a href="http://www.jeffro2pt0.com/ajax-powered-password-strength-meter/"&gt;http://www.jeffro2pt0.com/ajax-powered-password-strength-meter/&lt;/a&gt;
&lt;a href="http://www.geekwisdom.com/dyn/passwdmeter"&gt;http://www.geekwisdom.com/dyn/passwdmeter&lt;/a&gt;
&lt;a href="http://www.jvoorhis.com/articles/2006/04/06/automatic-password-suggestion-for-your-rails-app"&gt;http://www.jvoorhis.com/articles/2006/04/06/automatic-password-suggestion-for-your-rails-app&lt;/a&gt;
&lt;/div&gt;

&lt;br /&gt;


&lt;a&gt;&lt;/a&gt;
&lt;h1&gt;- Miscellaneous -&lt;/h1&gt;



&lt;a&gt;&lt;/a&gt;
&lt;h2&gt;Transmission of Sensitive information&lt;/h2&gt;
&lt;p&gt;Use SSL to encrypt sensitive data between transfer from client to server. SSL hits server performace, so you might consider using SSL only for few pages which transfer sensitive data to and fro.&lt;/p&gt;

Plugin &lt;b&gt;ssl_requirement&lt;/b&gt;
&lt;div class="linkbox"&gt;
&lt;a href="http://svn.rubyonrails.org/rails/plugins/ssl_requirement/README"&gt;http://svn.rubyonrails.org/rails/plugins/ssl_requirement/README&lt;/a&gt;
&lt;/div&gt;

&lt;b&gt;Mongrel, rails, apache and SSL&lt;/b&gt;
&lt;div class="linkbox"&gt;
&lt;a href="http://blog.innerewut.de/2006/06/21/mongrel-and-rails-behind-apache-2-2-and-ssl"&gt;http://blog.innerewut.de/2006/06/21/mongrel-and-rails-behind-apache-2-2-and-ssl&lt;/a&gt;
&lt;/div&gt;

Controller in &lt;b&gt;SSL subdomain&lt;/b&gt;
&lt;div class="linkbox"&gt; 
&lt;a href="http://www.railsonwave.com/railsonwave/2007/7/10/howto-put-a-controller-under-a-ssl-subdomain"&gt;http://www.railsonwave.com/railsonwave/2007/7/10/howto-put-a-controller-under-a-ssl-subdomain&lt;/a&gt;
&lt;/div&gt;

&lt;b&gt;Sample SSL code in rails&lt;/b&gt;
&lt;div class="linkbox"&gt;
&lt;a href="http://blog.caboo.se/articles/2007/4/21/sample-rails-app-branch-with-ssl"&gt;http://blog.caboo.se/articles/2007/4/21/sample-rails-app-branch-with-ssl&lt;/a&gt;
&lt;/div&gt;



&lt;a&gt;&lt;/a&gt;
&lt;h2&gt;File upload&lt;/h2&gt;
&lt;p&gt;Be very careful when you allow your users to upload files and make them available for other users to download.&lt;/p&gt;

&lt;b&gt;Description&lt;/b&gt;
&lt;div class="linkbox"&gt;
&lt;a href="http://www.rorsecurity.info/2007/03/27/working-with-files-in-rails/"&gt;http://www.rorsecurity.info/2007/03/27/working-with-files-in-rails/&lt;/a&gt;
&lt;/div&gt;

&lt;b&gt;Must read&lt;/b&gt; - Section 26.7 of Agile web development with rails - 2nd edition
&lt;div class="linkbox"&gt;
&lt;a href="http://www.pragmaticprogrammer.com/titles/rails2/"&gt;http://www.pragmaticprogrammer.com/titles/rails2/&lt;/a&gt;
&lt;/div&gt;

&lt;b&gt;In place file upload&lt;/b&gt;
&lt;div class="linkbox"&gt;
&lt;a href="http://kpumuk.info/ruby-on-rails/in-place-file-upload-with-ruby-on-rails/"&gt;http://kpumuk.info/ruby-on-rails/in-place-file-upload-with-ruby-on-rails/&lt;/a&gt;
&lt;/div&gt;

3 plugins for file upload reviewed at :
&lt;div class="linkbox"&gt;
&lt;a href="http://www.flex888.com/2007/03/21/three-ruby-on-rails-file-upload-plugins-reviewed.html"&gt;http://www.flex888.com/2007/03/21/three-ruby-on-rails-file-upload-plugins-reviewed.html&lt;/a&gt;
&lt;/div&gt;



&lt;a&gt;&lt;/a&gt;
&lt;h2&gt;Secure your setup / environment&lt;/h2&gt;
&lt;div class="linkbox"&gt;
&lt;a href="http://www.igvita.com/blog/2006/10/10/securing-your-rails-environment/"&gt;http://www.igvita.com/blog/2006/10/10/securing-your-rails-environment/&lt;/a&gt;
&lt;/div&gt;



&lt;a&gt;&lt;/a&gt;
&lt;h2&gt;Proper Mysql configuration&lt;/h2&gt;
&lt;div class="linkbox"&gt;
&lt;a href="http://www.rorsecurity.info/2007/02/25/securing-mysql/"&gt;http://www.rorsecurity.info/2007/02/25/securing-mysql/&lt;/a&gt;
&lt;a href="http://www.rorsecurity.info/2007/02/27/rails%e2%80%99-friends-securing-mysql-continued/"&gt;http://www.rorsecurity.info/2007/02/27/rails%e2%80%99-friends-securing-mysql-continued/&lt;/a&gt;
&lt;/div&gt;



&lt;a&gt;&lt;/a&gt;
&lt;h2&gt;Use good passwords&lt;/h2&gt;
&lt;div class="linkbox"&gt;
&lt;a href="http://en.wikipedia.org/wiki/Password_strength"&gt;http://en.wikipedia.org/wiki/Password_strength&lt;/a&gt;
&lt;a href="http://www.rorsecurity.info/2007/06/05/use-good-passwords/"&gt;http://www.rorsecurity.info/2007/06/05/use-good-passwords/&lt;/a&gt;
&lt;/div&gt;
&lt;br /&gt;


&lt;a&gt;&lt;/a&gt;
&lt;h1&gt;Security plugins directory&lt;/h1&gt;
&lt;div class="linkbox"&gt;
&lt;a href="http://agilewebdevelopment.com/plugins/category/1"&gt;http://agilewebdevelopment.com/plugins/category/1&lt;/a&gt;&lt;br /&gt;
&lt;a href="http://www.railslodge.com/plugins"&gt;http://www.railslodge.com/plugins&lt;/a&gt;&lt;br /&gt;
&lt;a href="http://railsify.com/categories/security-production"&gt;http://railsify.com/categories/security-production&lt;/a&gt;
&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;


&lt;b&gt;Note&lt;/b&gt; : I will keep this security guide updated. Any additions/improvements are welcome.
          </content>  <feedburner:origLink>http://www.quarkruby.com/2007/9/20/ruby-on-rails-security-guide</feedburner:origLink></entry>
  <entry xml:base="http://www.quarkruby.com/">
    <author>
      <name>admin</name>
    </author>
    <id>tag:www.quarkruby.com,2007-09-14:27</id>
    <published>2007-09-14T04:15:00Z</published>
    <updated>2007-12-19T06:47:25Z</updated>
    <category term="ruby on rails" />
    <category term="tutorials" />
    <category term="plugin" />
    <category term="solr" />
    <link href="http://feedproxy.google.com/~r/Quarkruby/~3/7Sx0Y_9_CF0/advanced-acts_as_solr" rel="alternate" type="text/html" />
    <title>Advanced acts_as_solr</title>
<summary type="html">&lt;p&gt;This article extends our &lt;a href="http://www.quarkruby.com/2007/8/12/acts_as_solr-for-search-and-faceting"&gt;acts_as_solr : search and faceting tutorial&lt;/a&gt; and talks about how to manage rails associations, solr indexes and more with acts_as_solr.&lt;/p&gt;

&lt;h2&gt;Table Of Contents&lt;/h2&gt;
&lt;ol&gt;
   &lt;li&gt;&lt;a href="#rs"&gt;Rebuild Solr index&lt;/a&gt;
   &lt;li&gt;&lt;a href="#import"&gt;Import existing Solr index or your custom Solr schema.xml&lt;/a&gt;
   &lt;li&gt;&lt;a href="#hst"&gt;Highlight search term&lt;/a&gt;
   &lt;li&gt;&lt;a href="#ra"&gt;Rails associations and acts_as_solr&lt;/a&gt;
   &lt;li&gt;&lt;a href="#tips"&gt;Tips&lt;/a&gt;
&lt;/ol&gt;



&lt;a&gt;&lt;/a&gt;
&lt;h2&gt;Rebuild Solr Index&lt;/h2&gt;
&lt;code class="inline"&gt;rebuild_solr_index&lt;/code&gt; is a class method to re-build your model indexes on import of external data. &lt;br /&gt;&lt;br /&gt;

&lt;p&gt;For large tables rebuilding Solr index is a time consuming process. See the fifth line in the pseudo code below (index optimization call), it makes rebuild_solr_index a slow process. For large tables, you do not want optimization to take place for each object added to the table. Whereas, removing optimization calls slows down the process of updating solr index.&lt;/p&gt;

&lt;table class="CodeRay"&gt;&lt;tr&gt;
  &lt;td title="click to toggle" class="line_numbers"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;6&lt;tt&gt;
&lt;/tt&gt;7&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre&gt;## pseudo code&lt;tt&gt;
&lt;/tt&gt;def rebuild_solr_index&lt;tt&gt;
&lt;/tt&gt;  for_each_row_in_table do |doc|&lt;tt&gt;
&lt;/tt&gt;    doc.save_to_solr_index&lt;tt&gt;
&lt;/tt&gt;    index.optimize&lt;tt&gt;
&lt;/tt&gt;  end&lt;tt&gt;
&lt;/tt&gt;end&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;


&lt;p&gt;The solution to the problem is to use &lt;code class="inline"&gt;batch_size&lt;/code&gt; in &lt;code class="inliine"&gt;#rebuild_solr_index&lt;/code&gt;. With batch size, say for example 100, the &lt;i&gt;index optimization call&lt;/i&gt; is executed after indexing 100 rows.&lt;/p&gt;</summary><content type="html">
            &lt;p&gt;This article extends our &lt;a href="http://www.quarkruby.com/2007/8/12/acts_as_solr-for-search-and-faceting"&gt;acts_as_solr : search and faceting tutorial&lt;/a&gt; and talks about how to manage rails associations, solr indexes and more with acts_as_solr.&lt;/p&gt;

&lt;h2&gt;Table Of Contents&lt;/h2&gt;
&lt;ol&gt;
   &lt;li&gt;&lt;a href="#rs"&gt;Rebuild Solr index&lt;/a&gt;
   &lt;li&gt;&lt;a href="#import"&gt;Import existing Solr index or your custom Solr schema.xml&lt;/a&gt;
   &lt;li&gt;&lt;a href="#hst"&gt;Highlight search term&lt;/a&gt;
   &lt;li&gt;&lt;a href="#ra"&gt;Rails associations and acts_as_solr&lt;/a&gt;
   &lt;li&gt;&lt;a href="#tips"&gt;Tips&lt;/a&gt;
&lt;/ol&gt;



&lt;a&gt;&lt;/a&gt;
&lt;h2&gt;Rebuild Solr Index&lt;/h2&gt;
&lt;code class="inline"&gt;rebuild_solr_index&lt;/code&gt; is a class method to re-build your model indexes on import of external data. &lt;br /&gt;&lt;br /&gt;

&lt;p&gt;For large tables rebuilding Solr index might be time consuming process because each row is comitted to solr index. Rather saving each row individually, you can save them in batch. Using &lt;code class="inline"&gt;batch_size&lt;/code&gt; argument, in &lt;code class="inliine"&gt;#rebuild_solr_index&lt;/code&gt;(say for example 100), solr index would be updated with 100 rows in 1 commit rather updating solr index for each of them.&lt;/p&gt;

&lt;p&gt;If you do not want to index the complete data but only few rows based on conditions, use optional arguments &lt;code class="inline"&gt;batch_size&lt;/code&gt; and &lt;code class="inline"&gt;finder&lt;/code&gt; in rebuild_solr_index.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;b&gt;batch_size&lt;/b&gt; : to send this many rows to solr for index update. Default value is 1.
&lt;li&gt;&lt;b&gt;finder&lt;/b&gt; : it is used for conditional indexation. It takes a method as argument which returns objects to be indexed. Default method is :
&lt;table class="CodeRay"&gt;&lt;tr&gt;
  &lt;td title="click to toggle" class="line_numbers"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre&gt;&lt;span class="r"&gt;def&lt;/span&gt; &lt;span class="fu"&gt;finder&lt;/span&gt;(ar, options)&lt;tt&gt;
&lt;/tt&gt;  ar.find (&lt;span class="sy"&gt;:all&lt;/span&gt;, options.merge({&lt;span class="sy"&gt;:order&lt;/span&gt; =&amp;gt; &lt;span class="pc"&gt;self&lt;/span&gt;.primary_key}))&lt;tt&gt;
&lt;/tt&gt;&lt;span class="r"&gt;end&lt;/span&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;

&lt;/ul&gt;



&lt;a&gt;&lt;/a&gt;
&lt;h2&gt;Import existing Solr index or your custom Solr schema.xml&lt;/h2&gt;
&lt;p&gt;Assumption: Column names in table definition are same as the names of the fields using which index has been/will be created.
  &lt;ul&gt;
    &lt;li&gt;Add your &lt;b&gt;indexed&lt;/b&gt; fields to &lt;code class="inline"&gt;vendor/plugins/acts_as_solr/solr/solr/conf/schema.xml&lt;/code&gt; (continuing with example of our previous &lt;a href="http://www.quarkruby.com/2007/8/12/acts_as_solr-for-search-and-faceting"&gt;tutorial&lt;/a&gt;, we add name1, brand, resolution to schema.xml). &lt;br /&gt;
Remember, to copy them to text field using solr's copyfield directive. &lt;b&gt;text&lt;/b&gt; is the default field/column in which search is made, so using copyField we add all data to default search field. The new schema.xml looks like...
      &lt;table class="CodeRay"&gt;&lt;tr&gt;
  &lt;td title="click to toggle" class="line_numbers"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;6&lt;tt&gt;
&lt;/tt&gt;7&lt;tt&gt;
&lt;/tt&gt;8&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre&gt;&lt;span class="ta"&gt;&amp;lt;field&lt;/span&gt; &lt;span class="an"&gt;name&lt;/span&gt;=&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;text&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class="an"&gt;type&lt;/span&gt;=&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;text&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class="an"&gt;indexed&lt;/span&gt;=&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class="an"&gt;stored&lt;/span&gt;=&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class="an"&gt;multiValued&lt;/span&gt;=&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class="ta"&gt;/&amp;gt;&lt;/span&gt; &lt;tt&gt;
&lt;/tt&gt;&lt;span class="ta"&gt;&amp;lt;field&lt;/span&gt; &lt;span class="an"&gt;name&lt;/span&gt;=&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;name1&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class="an"&gt;type&lt;/span&gt;=&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;text&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class="an"&gt;indexed&lt;/span&gt;=&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class="an"&gt;stored&lt;/span&gt;=&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;false&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class="ta"&gt;/&amp;gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="ta"&gt;&amp;lt;field&lt;/span&gt; &lt;span class="an"&gt;name&lt;/span&gt;=&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;brand&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class="an"&gt;type&lt;/span&gt;=&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;string&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class="an"&gt;indexed&lt;/span&gt;=&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class="an"&gt;stored&lt;/span&gt;=&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;false&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class="ta"&gt;/&amp;gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="ta"&gt;&amp;lt;field&lt;/span&gt; &lt;span class="an"&gt;name&lt;/span&gt;=&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;resolution&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class="an"&gt;type&lt;/span&gt;=&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;sfloat&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class="an"&gt;indexed&lt;/span&gt;=&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class="an"&gt;stored&lt;/span&gt;=&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;false&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class="ta"&gt;/&amp;gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="ta"&gt;&amp;lt;copyField&lt;/span&gt; &lt;span class="an"&gt;source&lt;/span&gt;=&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;*_facet&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class="an"&gt;dest&lt;/span&gt;=&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;text&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class="ta"&gt;/&amp;gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="ta"&gt;&amp;lt;copyField&lt;/span&gt; &lt;span class="an"&gt;source&lt;/span&gt;=&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;brand&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class="an"&gt;dest&lt;/span&gt;=&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;text&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class="ta"&gt;/&amp;gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="ta"&gt;&amp;lt;copyField&lt;/span&gt; &lt;span class="an"&gt;source&lt;/span&gt;=&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;name1&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class="an"&gt;dest&lt;/span&gt;=&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;text&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class="ta"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;

    
    &lt;li&gt;&lt;a href="http://www.quarkruby.com/assets/2007/9/9/custom-schema.patch"&gt;Apply our patch &lt;i&gt;(download)&lt;/i&gt;&lt;/a&gt;. For indexing and searching, acts_as_solr suffixes dataType (e.g. int, float, string etc) of column to the column name, this patch tells acts_as_solr not to do this since we have explicitly created entries for these columns in schema file:
      &lt;table class="CodeRay"&gt;&lt;tr&gt;
  &lt;td title="click to toggle" class="line_numbers"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre&gt;cd &lt;span class="rx"&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;span class="k"&gt;path&lt;/span&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;/span&gt;to/rails/dir&lt;tt&gt;
&lt;/tt&gt;patch -p0 custom-schema.patch&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;

    
    &lt;li&gt;Modify your acts_as_solr definition:
       &lt;table class="CodeRay"&gt;&lt;tr&gt;
  &lt;td title="click to toggle" class="line_numbers"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre&gt;&lt;span class="r"&gt;class&lt;/span&gt; &lt;span class="cl"&gt;Camera&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  acts_as_solr &lt;span class="sy"&gt;:custom_schema&lt;/span&gt;=&amp;gt;&lt;span class="pc"&gt;true&lt;/span&gt;, &lt;span class="sy"&gt;:fields&lt;/span&gt;=&amp;gt;[&lt;span class="sy"&gt;:name&lt;/span&gt;,&lt;span class="sy"&gt;:brand&lt;/span&gt;,&lt;span class="sy"&gt;:resolution&lt;/span&gt;]&lt;tt&gt;
&lt;/tt&gt;&lt;span class="r"&gt;end&lt;/span&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;

    
    &lt;li&gt;... and it works!
  &lt;/ul&gt;
&lt;/p&gt;



&lt;a&gt;&lt;/a&gt;
&lt;h2&gt;Highlight search terms&lt;/h2&gt;
&lt;p&gt;Goal is to highlight search term(s) in search results. Follow the steps below :
  &lt;ul&gt;
    &lt;li&gt;Modify solrConfig.xml to enable highlighting. Apply &lt;a href="http://www.quarkruby.com/assets/2007/9/9/highlight-solrconfig.patch"&gt;our patch &lt;i&gt;(download)&lt;/i&gt;&lt;/a&gt; as:
      &lt;table class="CodeRay"&gt;&lt;tr&gt;
  &lt;td title="click to toggle" class="line_numbers"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre&gt;cd &lt;span class="rx"&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;span class="k"&gt;path&lt;/span&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;/span&gt;to/rails/dir&lt;tt&gt;
&lt;/tt&gt;patch -p0 highlight-solrconfig.patch&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;

    
    &lt;li&gt;acts_as_solr does not stores any of the field values as it is in its index. We need to modify the configuration file &lt;code class="inline"&gt;vendor/plugins/acts_as_solr/solr/solr/conf/schema.xml&lt;/code&gt; to enable storage of data, which is required to return the highlighted text data. For example,  we modify configuration file to store the fields having &lt;b&gt;text&lt;/b&gt; dataType to get highlighted matching terms for name1 field.
       &lt;table class="CodeRay"&gt;&lt;tr&gt;
  &lt;td title="click to toggle" class="line_numbers"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre&gt;&lt;span class="c"&gt;&amp;lt;!-- Original config --&amp;gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="ta"&gt;&amp;lt;dynamicField&lt;/span&gt; &lt;span class="an"&gt;name&lt;/span&gt;=&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;*_t&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class="an"&gt;type&lt;/span&gt;=&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;text&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class="an"&gt;indexed&lt;/span&gt;=&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class="an"&gt;stored&lt;/span&gt;=&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;false&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class="ta"&gt;/&amp;gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="c"&gt;&amp;lt;!-- New config --&amp;gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="ta"&gt;&amp;lt;dynamicField&lt;/span&gt; &lt;span class="an"&gt;name&lt;/span&gt;=&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;*_t&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class="an"&gt;type&lt;/span&gt;=&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;text&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class="an"&gt;indexed&lt;/span&gt;=&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class="an"&gt;stored&lt;/span&gt;=&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class="ta"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;

    
    &lt;li&gt;&lt;p&gt;&lt;a href="http://www.quarkruby.com/assets/2007/9/9/highlight.patch"&gt;Apply one more patch&lt;/a&gt; in the same way as the previous one. This patch enables acts_as_solr to handle the option of highlighting in find_by_solr queries and parses the results returned by solr.  And now we are ready to roar...&lt;/p&gt;

    &lt;li&gt;Lets see it in action with an example
       &lt;table class="CodeRay"&gt;&lt;tr&gt;
  &lt;td title="click to toggle" class="line_numbers"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;6&lt;tt&gt;
&lt;/tt&gt;7&lt;tt&gt;
&lt;/tt&gt;8&lt;tt&gt;
&lt;/tt&gt;9&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre&gt;&lt;span class="iv"&gt;@results&lt;/span&gt; = &lt;span class="co"&gt;Camera&lt;/span&gt;.find_by_solr(&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;canon powershot&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class="sy"&gt;:highlight&lt;/span&gt;=&amp;gt;{&lt;span class="sy"&gt;:fields&lt;/span&gt;=&amp;gt;&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;name1&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;})&lt;tt&gt;
&lt;/tt&gt;&lt;span class="iv"&gt;@results&lt;/span&gt;.highlights&lt;tt&gt;
&lt;/tt&gt;&lt;span class="c"&gt;## returns hash of objects id and hash of the columns with matched text data&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;{&lt;span class="i"&gt;1&lt;/span&gt;=&amp;gt;{&lt;span class="sy"&gt;:name1&lt;/span&gt;=&amp;gt;&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;&amp;lt;em&amp;gt;Canon&amp;lt;/em&amp;gt; &amp;lt;em&amp;gt;Powershot&amp;lt;/em&amp;gt; sd1000&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;} ... }&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="c"&gt;#You want to display names with highlighted terms:&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="iv"&gt;@results&lt;/span&gt;.docs.each &lt;span class="r"&gt;do&lt;/span&gt; |doc|&lt;tt&gt;
&lt;/tt&gt;   &amp;lt;%= &lt;span class="iv"&gt;@results&lt;/span&gt;.highlights[doc.id][&lt;span class="sy"&gt;:name1&lt;/span&gt;]  -&lt;span class="s"&gt;&lt;span class="dl"&gt;%&amp;gt;&lt;/span&gt;&lt;span class="k"&gt;&amp;lt;br/&lt;/span&gt;&lt;span class="dl"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="r"&gt;end&lt;/span&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;

    
    &lt;li&gt;Options for highlighting (You can also refer them &lt;a href="http://wiki.apache.org/solr/HighlightingParameters"&gt;here&lt;/a&gt;)&lt;br /&gt;
      &lt;ol&gt;
         &lt;li&gt;&lt;code class="inline"&gt;fields&lt;/code&gt;: columns to highlight terms for (default is none, and no highlighted text)&lt;/li&gt;
         &lt;li&gt;&lt;code class="inline"&gt;prefix&lt;/code&gt;: You do not want to have "&amp;lt;em&amp;gt;" tag around matched search term(s), tell your tag here. (eg. "&amp;lt;span class='highlight'&amp;gt;")&lt;/li&gt;
         &lt;li&gt;&lt;code class="inline"&gt;suffix&lt;/code&gt;: Ending tag for matched term(s)&lt;/li&gt;
         &lt;li&gt;&lt;code class="inline"&gt;max_snippets&lt;/code&gt;: stop searching the  column after max_snippets matched terms found&lt;/li&gt;
      &lt;/ol&gt;
      Currenlty acts_as_solr does not implements these options at each column level, so you cannot ask to apply some of the options to only one (or few) columns. For e.g. you cannot ask acts_as_solr to use &amp;lt;em&amp;gt; tags for one field and &amp;lt;span class='highlight'&amp;gt; for other field.
    
  &lt;/ul&gt;
&lt;/p&gt;
&lt;br /&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt;  If you want both the functionalities &lt;i&gt;Custom schema&lt;/i&gt; and &lt;i&gt;Highlighting&lt;/i&gt; together, use these two patches. &lt;a href="http://www.quarkruby.com/assets/2007/9/9/highlight-custom-schema.diff"&gt;Patch 1&lt;/a&gt; and &lt;a href="http://www.quarkruby.com/assets/2007/9/9/highlight-solrconfig.patch"&gt;Patch 2&lt;/a&gt;.



&lt;a&gt;&lt;/a&gt;
&lt;h2&gt;Rails associations and acts_as_solr&lt;/h2&gt;
&lt;p&gt;Lets say I have two models,  User &lt;i&gt;(columns: username, password)&lt;/i&gt; and UserProfile &lt;i&gt;(columns:  full name, location, favorite food .... and many more)&lt;/i&gt;. These two models have one-to-one association (:has_one, :belongs_to) between them and I have two problems :
&lt;ol&gt;
&lt;li&gt;When searching the User model, I also want to search UserProfile model. 
&lt;li&gt;I want to allow faceting based on few columns in UserProfile lets say location and favorite food.&lt;/p&gt;
&lt;/ol&gt;
&lt;p&gt;Fabio Confalonieri has &lt;a href="http://groups.google.com/group/acts_as_solr/msg/5f52527d25e831ff "&gt;written a small hack&lt;/a&gt; for the solution to both the problems along with good explanation.&lt;/p&gt;




&lt;a /&gt;
&lt;h2&gt;Tips:&lt;/h2&gt;
&lt;ol&gt;
   &lt;li&gt;&lt;p&gt;Wanna see the statistics for created index? &lt;br /&gt; 
Download &lt;a href="http://svn.apache.org/viewvc/lucene/solr/trunk/example/solr/conf/xslt/luke.xsl?revision=572881&amp;amp;pathrev=573897"&gt;this xsl file&lt;/a&gt; as luke.xsl to &lt;code class="inline"&gt;vendor/plugins/acts_as_solr/solr/solr/conf/xslt/&lt;/code&gt; and then open url: &lt;a href="http://localhost:8982/solr/admin/luke?wt=xslt&amp;amp;tr=luke.xsl"&gt;http://localhost:8982/solr/admin/luke?wt=xslt&amp;tr=luke.xsl&lt;/a&gt;&lt;/p&gt;
   
   &lt;li&gt;&lt;p&gt;If your search results are not good enough because the text is not indexed properly, it might be due to presence of acronyms or words having apostrophes or html content in your data. Solr provides you with many options for analyzing and modifying &lt;i&gt;text&lt;/i&gt; before it is indexed and searched. Read these options at &lt;a href="http://wiki.apache.org/solr/AnalyzersTokenizersTokenFilters"&gt;Solr's Wiki page&lt;/a&gt;. Remember, you need to make these modifications in schema.xml file.&lt;/p&gt;
   &lt;li&gt;&lt;p&gt;&lt;b&gt;Note&lt;/b&gt; : The default behaviour of acts_as_solr is to index model objects automatically upon save or update of a record.&lt;/p&gt;
   
&lt;/ol&gt;

&amp;lt;!--
&amp;lt;h3&gt;More Todo's&amp;lt;/h3&gt;
&amp;lt;ul&gt;
   &amp;lt;li&gt;Full STI support&amp;lt;/li&gt;
   &amp;lt;li&gt;Adding spell Checker functionality, and &amp;lt;/li&gt;
   &amp;lt;li&gt;Getting solr index stats (via ruby code) for displaying on site (index size, number of docs indexed, number of searches etc)&amp;lt;/li&gt;
   &amp;lt;li&gt;Faceting on non-string type columns&amp;lt;/li&gt;
&amp;lt;/ul&gt;
--&gt;
          </content>  <feedburner:origLink>http://www.quarkruby.com/2007/9/14/advanced-acts_as_solr</feedburner:origLink></entry>
  <entry xml:base="http://www.quarkruby.com/">
    <author>
      <name>admin</name>
    </author>
    <id>tag:www.quarkruby.com,2007-09-05:11</id>
    <published>2007-09-05T19:42:00Z</published>
    <updated>2008-08-23T03:20:58Z</updated>
    <category term="our tools" />
    <category term="css selector" />
    <category term="firebug" />
    <category term="html scraping" />
    <category term="scrapi" />
    <link href="http://feedproxy.google.com/~r/Quarkruby/~3/B6wZknYV9_I/firequark-quick-html-screen-scraping" rel="alternate" type="text/html" />
    <title>Firequark : quick html screen scraping</title>
<summary type="html">&lt;br&gt;&lt;span class="header"&gt; Table of Contents &lt;/span&gt;&lt;br&gt;
&lt;ol&gt;
   &lt;li&gt; &lt;a href="#intro"&gt;Introduction&lt;/a&gt;
   &lt;li&gt; &lt;a href="#why"&gt;Why Firequark?&lt;/a&gt;
      &lt;ol&gt;
          &lt;li&gt;&lt;a href="#xpathcss"&gt;XPath vs. CSS Selector&lt;/a&gt;
          &lt;li&gt;&lt;a href="#cssmanual"&gt;Find CSS Selector manually&lt;/a&gt;
          &lt;li&gt;&lt;a href="#bundle"&gt;Bundle Scraping&lt;/a&gt;
      &lt;/ol&gt;
   &lt;li&gt; &lt;a href="#use"&gt;Usage - screencast&lt;/a&gt;
   &lt;li&gt; &lt;a href="#install"&gt;Installation&lt;/a&gt;
   &lt;li&gt; &lt;a href="#document"&gt;Documentation&lt;/a&gt;
   &lt;li&gt; &lt;a href="#todo"&gt;Todo&lt;/a&gt;
&lt;/ol&gt;
&lt;br /&gt;

&lt;a&gt;&lt;/a&gt;
&lt;p&gt;Firequark is an extension to &lt;a href="http://www.getfirebug.com/"&gt;Firebug&lt;/a&gt; to aid the process of &lt;a href="http://en.wikipedia.org/wiki/Screen_scraping"&gt;HTML Screen Scraping&lt;/a&gt;. Firequark automatically extracts &lt;i&gt;css selector&lt;/i&gt; for a single or multiple html node(s) from a web page using Firebug (a web development plugin for Firefox). The css selector generated can be given as an input to html screen scrapers like &lt;a href="http://swik.net/scrapi-ruby"&gt;Scrapi&lt;/a&gt; to extract information. Firequark is built to unleash the power of css selector for use of html screen scraping.&lt;/p&gt;

&lt;p&gt;HTML screen scraping is a common technique of extracting information about &lt;i&gt;specific&lt;/i&gt; and &lt;i&gt;useful&lt;/i&gt; elements from a web page. Independent of programming language, for extracting an element from a web page one need to know its exact location or a key to uniquely identify the element. There are two approaches for uniquely identifying an element: using &lt;a href="http://en.wikipedia.org/wiki/XPath"&gt;XPath&lt;/a&gt; or &lt;a href="http://www.w3.org/TR/REC-CSS2/selector.html"&gt;CSS Selectors&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;Firebug has an inbuilt functionality of generating XPath for an html element. Ilya Grigorik has written a good article on using &lt;a href="http://www.igvita.com/blog/2007/02/04/ruby-screen-scraper-in-60-seconds/"&gt;XPath for HTML screen scraping&lt;/a&gt;.  Whereas, Firequark extends Firebug for generating &lt;b&gt;CSS Selector&lt;/b&gt; for elements on a web page.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Example case&lt;/b&gt; : Lets take a practical example where you want to scrape Amazon.com. My goal is to get product name, price and rating for all the products from the &lt;a href="http://amazon.com/b/ref=amb_link_4663762_1/102-9095771-9717732?ie=UTF8&amp;amp;node=330405011&amp;amp;pf_rd_m=ATVPDKIKX0DER&amp;amp;pf_rd_s=gp-center-5&amp;amp;pf_rd_r=0BK2VSWJY4N6HHR6VKWK&amp;amp;pf_rd_t=101&amp;amp;pf_rd_p=300424601&amp;amp;pf_rd_i=502394"&gt;Amazon point-and-shoot camera catalog page&lt;/a&gt;. I will use this example in screencast and explanation below.&lt;/p&gt;</summary><content type="html">
            &lt;br&gt;&lt;span class="header"&gt; Table of Contents &lt;/span&gt;&lt;br&gt;
&lt;ol&gt;
   &lt;li&gt; &lt;a href="#intro"&gt;Introduction&lt;/a&gt;
   &lt;li&gt; &lt;a href="#why"&gt;Why Firequark?&lt;/a&gt;
      &lt;ol&gt;
          &lt;li&gt;&lt;a href="#xpathcss"&gt;XPath vs. CSS Selector&lt;/a&gt;
          &lt;li&gt;&lt;a href="#cssmanual"&gt;Find CSS Selector manually&lt;/a&gt;
          &lt;li&gt;&lt;a href="#bundle"&gt;Bundle Scraping&lt;/a&gt;
      &lt;/ol&gt;
   &lt;li&gt; &lt;a href="#use"&gt;Usage - screencast&lt;/a&gt;
   &lt;li&gt; &lt;a href="#install"&gt;Installation&lt;/a&gt;
   &lt;li&gt; &lt;a href="#document"&gt;Documentation&lt;/a&gt;
   &lt;li&gt; &lt;a href="#todo"&gt;Todo&lt;/a&gt;
&lt;/ol&gt;
&lt;br /&gt;

&lt;a&gt;&lt;/a&gt;
&lt;p&gt;Firequark is an extension to &lt;a href="http://www.getfirebug.com/"&gt;Firebug&lt;/a&gt; to aid the process of &lt;a href="http://en.wikipedia.org/wiki/Screen_scraping"&gt;HTML Screen Scraping&lt;/a&gt;. Firequark automatically extracts &lt;i&gt;css selector&lt;/i&gt; for a single or multiple html node(s) from a web page using Firebug (a web development plugin for Firefox). The css selector generated can be given as an input to html screen scrapers like &lt;a href="http://blog.labnotes.org/2006/07/11/scraping-with-style-scrapi-toolkit-for-ruby/"&gt;Scrapi&lt;/a&gt; to extract information. Firequark is built to unleash the power of css selector for use of html screen scraping.&lt;/p&gt;

&lt;p&gt;HTML screen scraping is a common technique of extracting information about &lt;i&gt;specific&lt;/i&gt; and &lt;i&gt;useful&lt;/i&gt; elements from a web page. Independent of programming language, for extracting an element from a web page one need to know its exact location or a key to uniquely identify the element. There are two approaches for uniquely identifying an element: using &lt;a href="http://en.wikipedia.org/wiki/XPath"&gt;XPath&lt;/a&gt; or &lt;a href="http://www.w3.org/TR/REC-CSS2/selector.html"&gt;CSS Selectors&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;Firebug has an inbuilt functionality of generating XPath for an html element. Ilya Grigorik has written a good article on using &lt;a href="http://www.igvita.com/blog/2007/02/04/ruby-screen-scraper-in-60-seconds/"&gt;XPath for HTML screen scraping&lt;/a&gt;.  Whereas, Firequark extends Firebug for generating &lt;b&gt;CSS Selector&lt;/b&gt; for elements on a web page.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Example case&lt;/b&gt; : Lets take a practical example where you want to scrape Amazon.com. My goal is to get product name, price and rating for all the products from the &lt;a href="http://amazon.com/b/ref=amb_link_4663762_1/102-9095771-9717732?ie=UTF8&amp;amp;node=330405011&amp;amp;pf_rd_m=ATVPDKIKX0DER&amp;amp;pf_rd_s=gp-center-5&amp;amp;pf_rd_r=0BK2VSWJY4N6HHR6VKWK&amp;amp;pf_rd_t=101&amp;amp;pf_rd_p=300424601&amp;amp;pf_rd_i=502394"&gt;Amazon point-and-shoot camera catalog page&lt;/a&gt;. I will use this example in screencast and explanation below.&lt;/p&gt;

&lt;a&gt;&lt;/a&gt;
&lt;span class="header"&gt;Why Firequark?&lt;/span&gt;&lt;br /&gt;
&lt;a&gt;&lt;/a&gt;
&lt;span class="subheader"&gt;XPath vs. CSS Selector&lt;/span&gt;&lt;br /&gt;
When XPath is already provided by Firebug then why do I need CSS Selector? Xpath is great for scaping XML documents but for (x)html documents, it runs into many issues like :
&lt;ul&gt;
&lt;li&gt;Various parsers generate different xpath for the same element depending on their handling of broken markup with badly nested tags, errors in html pages, custom tags etc.&lt;/li&gt;
&lt;li&gt; Firefox adds &amp;lt;tbody&amp;gt; tag in table nodes, independent of whether html page has tbody tag or not, which makes it difficult to figure out to keep &amp;lt;tbody&amp;gt; tag or not.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;CSS Selector does not suffer from these problems because css selector of an html node is based on properties of self and neighboring nodes. Attributes of element and its neighbors like &lt;i&gt;id, class, etc&lt;/i&gt; are used to find css selector for an element.&lt;/p&gt;

&lt;a&gt;&lt;/a&gt;
&lt;span class="subheader"&gt;Find CSS Selector manually&lt;/span&gt;&lt;br /&gt;

&lt;p&gt;Its difficult to find css selector for a html node. Its a trial and error method until you find a right combination of rule (css selector). In the worst case the css selector would be the xpath itself. In our example case, its more difficult to manually find one unique css selector for 24 camera products and one each for their attributes like camera name, price, rating, etc (4 in total). &lt;/p&gt;

&lt;a&gt;
&lt;span class="subheader"&gt;Bundle Scraping&lt;/span&gt;&lt;br /&gt;
&lt;p&gt;I am big fan of &lt;a href="http://blog.labnotes.org/2006/07/11/scraping-with-style-scrapi-toolkit-for-ruby/"&gt;Scrapi&lt;/a&gt;, a html scraping toolkit in Ruby because it supports bundle scraping. Bundle scraping refers to extraction of multiple attributes of an object from a web page in one parse. Bundle scraping is well-defined at &lt;a href="http://quarkruby.com/2007/8/23/qscraper-hpricot-interface-to-scrapi"&gt;Qscraper: a hpricot interface to scrapi&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Continuing with the example case, &lt;i&gt;object&lt;/i&gt; is a camera product (there are 24 such objects on the page) and price, rating, product name, etc are &lt;i&gt;attributes&lt;/i&gt; of camera object. One way of extracting attributes is to separately get list of product name, price and rating from the web page and then combine these list. But, how do you combine them? What if one of the camera product is not rated or amazon does not provide its price?&lt;/p&gt;

&lt;p&gt;Firequark is really powerful in solving this problem. Using Firequark, first get one css selector to identify all the camera objects on the page which contain the attribute information inside them (name, price and rating). Set camera object to parent and find css selector of attributes relative to the parent. Give these css selectors as an input to html screen scraper supporting bundle scraping like Scrapi and &lt;b&gt;bingo!&lt;/b&gt; Our screencast below explains this case in detail.&lt;/p&gt;


&lt;a&gt;&lt;/a&gt;
&lt;span class="header"&gt;Usage - screencast&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;
&lt;p&gt;&lt;span&gt;&lt;a href="http://www.quarkruby.com/assets/2007/9/5/firequark.avi"&gt;Click here to view the screencast&lt;/a&gt;&lt;/span&gt; [format:avi, size:6.6MB]&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Note&lt;/b&gt; : Avoid using &lt;i&gt;CSS Selector functionality&lt;/i&gt; on first 2-3 products on a page because top 2-3 products are usually displayed differently like &lt;i&gt;top sellers or top rated&lt;/i&gt; with same &lt;i&gt;id&lt;/i&gt; which causes problems in getting good &amp; simple css selectors. 
&lt;/p&gt;
&lt;p&gt;Even in our &lt;b&gt;screencast&lt;/b&gt; we analyze the 4th product on the page to get a simple css selector&lt;/p&gt;


&lt;a&gt;&lt;/a&gt;
&lt;span class="header"&gt;Installation&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;
&lt;p&gt;&lt;span&gt;&lt;a href="http://www.quarkruby.com/assets/2007/9/5/firequark.xpi"&gt;Click here to install&lt;/a&gt;&lt;/span&gt;, this will overwrite your current Firebug installation (built on Firebug v1.05).&lt;/p&gt;
&lt;p&gt;&lt;span&gt;&lt;a href="http://www.quarkruby.com/firequark-1.2.xpi"&gt;(FF3 users) Click here to install&lt;/a&gt;&lt;/span&gt;, this will overwrite your current Firebug installation (build on firebug 1.2).&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Note&lt;/b&gt;: in case you are doing firebug development over 1.05 then please backup your work before installing Firequark. &lt;/p&gt;


&lt;a&gt;&lt;/a&gt;
&lt;span class="header"&gt;Documentation&lt;/span&gt;&lt;br /&gt;
&lt;p&gt;Firequark adds four new functions to each node element in &lt;i&gt;html source&lt;/i&gt;  tab of Firebug. In &lt;i&gt;html source&lt;/i&gt; tab of Firebug, when you click on an html node:
&lt;table width="80%"&gt;
&lt;tr&gt;&lt;th&gt;Current menu&lt;/th&gt;&lt;th&gt;New menu&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;
  &lt;td&gt;&lt;img src="http://quarkruby.com/assets/2007/9/5/orig_selection_layer1.JPG"&gt;&lt;/td&gt;
  &lt;td&gt;&lt;img src="http://quarkruby.com/assets/2007/9/5/new_selection_layer.JPG"&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;/p&gt;

&lt;ol&gt;
   &lt;li&gt;&lt;b&gt;Get U CSS Selector&lt;/b&gt;: Get css selector for the selected element which uniquely identifies that element.  
   &lt;li&gt;&lt;b&gt;Get CSS Selector&lt;/b&gt;: Get one css selector for group of elements on a web page. When you select this option, it will prompt you for &lt;i&gt;how many such elements exist on this page&lt;/i&gt;. In our example case, right click on camera object node, in the prompt box put 24, as there are 24 camera objects on the page, press enter and you will get one unique css selector to extract 24 camera objects.
   &lt;li&gt;&lt;b&gt;Mark as parent&lt;/b&gt;: Used in bundle scraping to mark an object as parent. It is followed by &lt;i&gt; Get U CSS Selector&lt;/i&gt; for attributes of parent, which will return you with css selector of attributes relative to parent object.
   &lt;li&gt;&lt;b&gt;Unmark parentnode&lt;/b&gt;: To unmark object as parent.
&lt;/ol&gt;
&lt;br /&gt;

&lt;a&gt;&lt;/a&gt;
&lt;span class="header"&gt;Todo&lt;/span&gt;&lt;br /&gt;
&lt;ol&gt;
  &lt;li&gt;The current algorithm to find css selector is not sophisticated but solves my purpose very well. 
  &lt;li&gt;Firquark is based on CSS Selector 2. We want to move to CSS Selector 3 because it has more selectors.
&lt;/ol&gt;
          </content>  <feedburner:origLink>http://www.quarkruby.com/2007/9/5/firequark-quick-html-screen-scraping</feedburner:origLink></entry>
  <entry xml:base="http://www.quarkruby.com/">
    <author>
      <name>nakul</name>
    </author>
    <id>tag:www.quarkruby.com,2007-08-28:7</id>
    <published>2007-08-28T16:06:00Z</published>
    <updated>2008-09-09T10:23:30Z</updated>
    <category term="ruby" />
    <category term="html scraping" />
    <category term="scrapi" />
    <link href="http://feedproxy.google.com/~r/Quarkruby/~3/XwdQwtYX1kI/html-tag-class-in-scrapi" rel="alternate" type="text/html" />
    <title>HTML::Tag class in scrapi</title>
<summary type="html">&lt;p&gt;While working with scrapi, I found there is no external documentation for HTML::Tag class. This article is to ensure no one says this again.&lt;/p&gt;
&lt;p&gt;
In scrapi, HTML::Node represents a html node which can be of 2 types: HTML::Text and HTML::Tag for a text node and html tag node respectively. Here is a code snippet in which scrapi returns the html node  as a HTML::Tag object.</summary><content type="html">
            &amp;lt;style&gt;
table.sample {
	border-width: 1px;
	border-spacing: 2px;
	border-style: hidden;
	border-color: gray;
	border-collapse: collapse;
	background-color: white;
}
table.sample th {
	border-width: 1px;
	padding: 6px;
	border-style: inset;
	border-color: gray;
	background-color: white;
}
table.sample td {
	border-width: 1px;
	padding: 6px;
	border-style: inset;
	border-color: gray;
	background-color: white;
}
&amp;lt;/style&gt;
&lt;p&gt;While working with scrapi, I found there is no external documentation for HTML::Tag class. This article is to ensure no one says this again.&lt;/p&gt;
&lt;p&gt;
In scrapi, HTML::Node represents a html node which can be of 2 types: HTML::Text and HTML::Tag for a text node and html tag node respectively. Here is a code snippet in which scrapi returns the html node  as a HTML::Tag object.

&lt;table class="CodeRay"&gt;&lt;tr&gt;
  &lt;td title="click to toggle" class="line_numbers"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;6&lt;tt&gt;
&lt;/tt&gt;7&lt;tt&gt;
&lt;/tt&gt;8&lt;tt&gt;
&lt;/tt&gt;9&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre&gt;require &lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;rubygems&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;require &lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;scrapi&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;require &lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;open-uri&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;scraper = (&lt;span class="co"&gt;Scraper&lt;/span&gt;.define &lt;span class="r"&gt;do&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;   process_first &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;span.metaspan&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class="sy"&gt;:node&lt;/span&gt;=&amp;gt;&lt;span class="sy"&gt;:element&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;   result &lt;span class="sy"&gt;:node&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="r"&gt;end&lt;/span&gt;).scrape(open(&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;http://www.quarkruby.com&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;){|f| f.read})&lt;tt&gt;
&lt;/tt&gt;&lt;span class="c"&gt;# scraper.class&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;=&amp;gt; &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;HTML::Tag&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;

&lt;br&gt;

&lt;span class="header"&gt;Methods of HTML::Tag object&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;
&lt;table class="sample"&gt;
&lt;tr&gt;&lt;th&gt; METHOD &lt;/th&gt;&lt;th&gt; DESCRIPTION &lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt; tag? &lt;/td&gt;&lt;td&gt;              &lt;i&gt;true&lt;/i&gt; if this is HTML::Tag . HTML::Tag and HTML::Text have many different methods so its an important check.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt; name &lt;/td&gt;&lt;td&gt; returns name of the tag&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt; attributes &lt;/td&gt;&lt;td&gt; returns hash of attributes name/value pairs &lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt; children &lt;/td&gt;&lt;td&gt; returns array of children nodes, which may contain both HTML::Text and HTML::Tag class objects&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt; next_sibling &lt;/td&gt;&lt;td&gt; returns next adjacent node, which can be HTML::Text or HTML::Tag &lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt; next_element &lt;/td&gt;&lt;td&gt; returns next HTML::Tag node &lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt; to_s &lt;/td&gt;&lt;td&gt;                  returns html content of this node and its children &lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt; find &lt;/td&gt;&lt;td&gt;               match on subtree of this node (not  root node). &lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt; position &lt;/td&gt;&lt;td&gt;           byte index of matched node in html content &lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt; line &lt;/td&gt;&lt;td&gt;               line number of matched node in html content &lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt; parent &lt;/td&gt;&lt;td&gt;           returns parent HTML::Tag &lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt; match &lt;/td&gt;&lt;td&gt;              matches the given node with given arguments (explained with examples below) &lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;th&gt; &lt;br&gt;Next two methods are not a part of HTML::Tag class but I frequently find them useful. Their code is available below&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt; inner_html &lt;/td&gt;&lt;td&gt;          javascript's innerHTML :) &lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt; text &lt;/td&gt;&lt;td&gt;              returns the text content for this node and its childrens &lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;&lt;br /&gt;&lt;br /&gt;

&lt;span class="header"&gt;Some examples on how to use &lt;code class="inline"&gt;match&lt;/code&gt;&lt;/span&gt;&lt;br /&gt;
&lt;table class="CodeRay"&gt;&lt;tr&gt;
  &lt;td title="click to toggle" class="line_numbers"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;6&lt;tt&gt;
&lt;/tt&gt;7&lt;tt&gt;
&lt;/tt&gt;8&lt;tt&gt;
&lt;/tt&gt;9&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;11&lt;tt&gt;
&lt;/tt&gt;12&lt;tt&gt;
&lt;/tt&gt;13&lt;tt&gt;
&lt;/tt&gt;14&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;15&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;16&lt;tt&gt;
&lt;/tt&gt;17&lt;tt&gt;
&lt;/tt&gt;18&lt;tt&gt;
&lt;/tt&gt;19&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;20&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;21&lt;tt&gt;
&lt;/tt&gt;22&lt;tt&gt;
&lt;/tt&gt;23&lt;tt&gt;
&lt;/tt&gt;24&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;25&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;26&lt;tt&gt;
&lt;/tt&gt;27&lt;tt&gt;
&lt;/tt&gt;28&lt;tt&gt;
&lt;/tt&gt;29&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;30&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;31&lt;tt&gt;
&lt;/tt&gt;32&lt;tt&gt;
&lt;/tt&gt;33&lt;tt&gt;
&lt;/tt&gt;34&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre&gt;&lt;span class="c"&gt;#test if the node is a &amp;quot;span&amp;quot; tag&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  node.match &lt;span class="sy"&gt;:tag&lt;/span&gt; =&amp;gt; &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;span&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="c"&gt;#test if the node's parent is a &amp;quot;div&amp;quot;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  node.match &lt;span class="sy"&gt;:parent&lt;/span&gt; =&amp;gt; { &lt;span class="sy"&gt;:tag&lt;/span&gt; =&amp;gt; &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;div&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; }&lt;tt&gt;
&lt;/tt&gt;&lt;span class="c"&gt;#test if any of the node's ancestors are &amp;quot;table&amp;quot; tags&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  node.match &lt;span class="sy"&gt;:ancestor&lt;/span&gt; =&amp;gt; { &lt;span class="sy"&gt;:tag&lt;/span&gt; =&amp;gt; &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;table&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; }&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="c"&gt;#test if any of the node's immediate children are &amp;quot;em&amp;quot; tags&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  node.match &lt;span class="sy"&gt;:child&lt;/span&gt; =&amp;gt; { &lt;span class="sy"&gt;:tag&lt;/span&gt; =&amp;gt; &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;em&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; }&lt;tt&gt;
&lt;/tt&gt;  &lt;tt&gt;
&lt;/tt&gt;&lt;span class="c"&gt;#test if any of the node's descendants are &amp;quot;strong&amp;quot; tags&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  node.match &lt;span class="sy"&gt;:descendant&lt;/span&gt; =&amp;gt; { &lt;span class="sy"&gt;:tag&lt;/span&gt; =&amp;gt; &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;strong&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; }&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="c"&gt;#test if the node has between 2 and 4 span tags as immediate children&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  node.match &lt;span class="sy"&gt;:children&lt;/span&gt; =&amp;gt; { &lt;span class="sy"&gt;:count&lt;/span&gt; =&amp;gt; &lt;span class="i"&gt;2&lt;/span&gt;..&lt;span class="i"&gt;4&lt;/span&gt;, &lt;span class="sy"&gt;:only&lt;/span&gt; =&amp;gt; { &lt;span class="sy"&gt;:tag&lt;/span&gt; =&amp;gt; &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;span&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; } }&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="c"&gt;#get funky: test to see if the node is a &amp;quot;div&amp;quot;, has a &amp;quot;ul&amp;quot; ancestor&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="c"&gt;#and an &amp;quot;li&amp;quot; parent (with &amp;quot;class&amp;quot; = &amp;quot;enum&amp;quot;), and whether or not it has&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="c"&gt;#a &amp;quot;span&amp;quot; descendant that contains # text matching /hello world/:&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  node.match &lt;span class="sy"&gt;:tag&lt;/span&gt; =&amp;gt; &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;div&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;,&lt;tt&gt;
&lt;/tt&gt;             &lt;span class="sy"&gt;:ancestor&lt;/span&gt; =&amp;gt; { &lt;span class="sy"&gt;:tag&lt;/span&gt; =&amp;gt; &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;ul&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; },&lt;tt&gt;
&lt;/tt&gt;             &lt;span class="sy"&gt;:parent&lt;/span&gt; =&amp;gt; { &lt;span class="sy"&gt;:tag&lt;/span&gt; =&amp;gt; &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;li&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;,&lt;tt&gt;
&lt;/tt&gt;             &lt;span class="sy"&gt;:attributes&lt;/span&gt; =&amp;gt; { &lt;span class="sy"&gt;:class&lt;/span&gt; =&amp;gt; &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;enum&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; } },&lt;tt&gt;
&lt;/tt&gt;             &lt;span class="sy"&gt;:descendant&lt;/span&gt; =&amp;gt; { &lt;span class="sy"&gt;:tag&lt;/span&gt; =&amp;gt; &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;span&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;,&lt;tt&gt;
&lt;/tt&gt;             &lt;span class="sy"&gt;:child&lt;/span&gt; =&amp;gt; &lt;span class="rx"&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;span class="k"&gt;hello world&lt;/span&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;/span&gt; }&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="c"&gt;# Sometimes, you can get a HTML::Text node in return&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="c"&gt;# if its a text node, following are ways of using match on that node.&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  node.match (conditions)&lt;tt&gt;
&lt;/tt&gt;&lt;span class="c"&gt;# * if +conditions+ is a string, it must be a substring of the node's  content&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="c"&gt;# * if +conditions+ is a regular expression, it must match the node's content&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="c"&gt;# * if +conditions+ is a hash, it must contain a &amp;lt;tt&amp;gt;:content&amp;lt;/tt&amp;gt; key that&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="c"&gt;#   is either a string or a regexp, and which is interpreted as described above.&lt;/span&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;

(&lt;i&gt;above examples are shamelessly copied from html/node.rb, scrapi&lt;/i&gt;)
&lt;br /&gt;&lt;br /&gt;


&lt;span class="header"&gt;Code for new methods &lt;i&gt;text&lt;/i&gt; and &lt;i&gt;inner_html&lt;/i&gt;..&lt;/span&gt;&lt;br /&gt;
&lt;table class="CodeRay"&gt;&lt;tr&gt;
  &lt;td title="click to toggle" class="line_numbers"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;6&lt;tt&gt;
&lt;/tt&gt;7&lt;tt&gt;
&lt;/tt&gt;8&lt;tt&gt;
&lt;/tt&gt;9&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;11&lt;tt&gt;
&lt;/tt&gt;12&lt;tt&gt;
&lt;/tt&gt;13&lt;tt&gt;
&lt;/tt&gt;14&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;15&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;16&lt;tt&gt;
&lt;/tt&gt;17&lt;tt&gt;
&lt;/tt&gt;18&lt;tt&gt;
&lt;/tt&gt;19&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre&gt;&lt;span class="r"&gt;module&lt;/span&gt; &lt;span class="cl"&gt;HTML&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;   &lt;span class="r"&gt;class&lt;/span&gt; &lt;span class="cl"&gt;Tag&lt;/span&gt; &amp;lt; &lt;span class="co"&gt;Node&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;      &lt;span class="r"&gt;def&lt;/span&gt; &lt;span class="fu"&gt;text&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;         &lt;span class="r"&gt;return&lt;/span&gt; &lt;span class="iv"&gt;@content&lt;/span&gt; &lt;span class="r"&gt;if&lt;/span&gt; respond_to? &lt;span class="sy"&gt;:content&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;         data=&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;         &lt;span class="i"&gt;0&lt;/span&gt;.upto(children.size&lt;span class="i"&gt;-1&lt;/span&gt;) {|i|&lt;tt&gt;
&lt;/tt&gt;             &lt;span class="r"&gt;next&lt;/span&gt; &lt;span class="r"&gt;if&lt;/span&gt; children[i].respond_to?&lt;span class="sy"&gt;:name&lt;/span&gt; &lt;span class="r"&gt;and&lt;/span&gt; children[i].name==&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;script&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;             data += children[i].text&lt;tt&gt;
&lt;/tt&gt;         }&lt;tt&gt;
&lt;/tt&gt;         &lt;span class="r"&gt;return&lt;/span&gt; data&lt;tt&gt;
&lt;/tt&gt;      &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;     &lt;tt&gt;
&lt;/tt&gt;      &lt;span class="r"&gt;def&lt;/span&gt; &lt;span class="fu"&gt;inner_html&lt;/span&gt; &lt;tt&gt;
&lt;/tt&gt;         data = &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;         children.each {|e| data += e.to_s}&lt;tt&gt;
&lt;/tt&gt;         data&lt;tt&gt;
&lt;/tt&gt;       &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;   &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="r"&gt;end&lt;/span&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;

&lt;/p&gt;
&lt;br /&gt;

&lt;p&gt;Assaf Arkin has written a &lt;a href="http://labnotes.org/svn/public/ruby/scrapi/cheat/scrapi.html"&gt;well-documented cheetsheet&lt;/a&gt; on scrapi. Surprisingly, I found few selectors left unexplained.&lt;/a&gt;. 
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;E,F&lt;/strong&gt; : i.e. alternate selectors (matching any of E or F)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;E:content('hello world')&lt;/strong&gt;: content match&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;E[foo=bar][foo2=bar2]&lt;/strong&gt;: element E with attribute foo and foo2 having values bar and bar2 respectively&lt;/li&gt;
&lt;/ol&gt;
&lt;/p&gt;
          </content>  <feedburner:origLink>http://www.quarkruby.com/2007/8/28/html-tag-class-in-scrapi</feedburner:origLink></entry>
  <entry xml:base="http://www.quarkruby.com/">
    <author>
      <name>admin</name>
    </author>
    <id>tag:www.quarkruby.com,2007-08-25:5</id>
    <published>2007-08-25T09:45:00Z</published>
    <updated>2008-09-09T10:23:19Z</updated>
    <category term="ruby on rails" />
    <category term="domain forwarding" />
    <link href="http://feedproxy.google.com/~r/Quarkruby/~3/-b1hezfYH_0/domain-forwarding-or-domain-redirection" rel="alternate" type="text/html" />
    <title>Domain Forwarding or URL Redirection</title>
<summary type="html">&lt;p&gt;also known as &lt;b&gt;URL Forwarding&lt;/b&gt; or &lt;b&gt;Domain Redirection&lt;/b&gt;. Its a technique of making webpage available through many URLs.&lt;/p&gt;

&lt;p&gt;Checkout &lt;a href="http://en.wikipedia.org/wiki/URL_redirection#Purposes"&gt;
wikipedia article on URL redirection&lt;/a&gt; for uses of redirection.&lt;/p&gt;

In Short,&lt;ul&gt;
&lt;li&gt;&lt;b&gt;Client Side Fowarding&lt;/b&gt; : URL in client browser changes.
&lt;li&gt;&lt;b&gt;Server Side Redirection&lt;/b&gt; : URL in client browser does NOT change. User remains on same website/domain.
&lt;li&gt;&lt;b&gt;Server Side Forwarding&lt;/b&gt; or &lt;b&gt;DNS Forwarding&lt;/b&gt; : URL in client browser does NOT change. User  is moved to NEW website.
&lt;/ul&gt;
&lt;p&gt;All the above methods are explained below in detail. I will be using Ruby on Rails for illustration.&lt;/p&gt;</summary><content type="html">
            &lt;p&gt;also known as &lt;b&gt;URL Forwarding&lt;/b&gt; or &lt;b&gt;Domain Redirection&lt;/b&gt;. Its a technique of making webpage available through many URLs.&lt;/p&gt;

&lt;p&gt;Checkout &lt;a href="http://en.wikipedia.org/wiki/URL_redirection#Purposes"&gt;
wikipedia article on URL redirection&lt;/a&gt; for uses of redirection.&lt;/p&gt;

In Short,&lt;ul&gt;
&lt;li&gt;&lt;b&gt;Client Side Fowarding&lt;/b&gt; : URL in client browser changes.
&lt;li&gt;&lt;b&gt;Server Side Redirection&lt;/b&gt; : URL in client browser does NOT change. User remains on same website/domain.
&lt;li&gt;&lt;b&gt;Server Side Forwarding&lt;/b&gt; or &lt;b&gt;DNS Forwarding&lt;/b&gt; : URL in client browser does NOT change. User  is moved to NEW website.
&lt;/ul&gt;
&lt;p&gt;All the above methods are explained below in detail. I will be using Ruby on Rails for illustration.&lt;/p&gt;

&lt;span class="header"&gt;Domain forwarding techniques&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;
&lt;strong&gt;Client-Side Redirection&lt;/strong&gt;&lt;br&gt;
&lt;p&gt;The server sends a 301 or 302 redirect response with a Location: header containing the new URL. The client browser makes another request to the new URL. This is the most common form of domain forwarding.&lt;/p&gt;

&lt;i&gt;302 is for temporary redirection&lt;/i&gt;. It is used when the requested resource resides temporarily under a different URL. For Example: Latest article at my site are available at www.mysite.com/latest/ which would temporarily redirect to www.mysite/article/356.html and then to www.mysite/article/357.html

&lt;table class="CodeRay"&gt;&lt;tr&gt;
  &lt;td title="click to toggle" class="line_numbers"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;6&lt;tt&gt;
&lt;/tt&gt;7&lt;tt&gt;
&lt;/tt&gt;8&lt;tt&gt;
&lt;/tt&gt;9&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;11&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre&gt;&lt;span class="c"&gt;# 302 is default response status of redirect_to&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="c"&gt;# in controller latest&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="r"&gt;def&lt;/span&gt; &lt;span class="fu"&gt;index&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  redirect_to &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;article/356&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="c"&gt;# or redirect to another website&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="r"&gt;def&lt;/span&gt; &lt;span class="fu"&gt;index&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;redirect_to &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;http://www.newsite.com&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="r"&gt;end&lt;/span&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;


&lt;i&gt;301 is used for permanent redirection&lt;/i&gt; which means that the resource has moved permanently and people should update their information for this URL.

&lt;table class="CodeRay"&gt;&lt;tr&gt;
  &lt;td title="click to toggle" class="line_numbers"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre&gt;&lt;span class="r"&gt;def&lt;/span&gt; &lt;span class="fu"&gt;index&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  headers[&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;Status&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;] = &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;301 Moved Permanently&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  redirect_to &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;http://www.newsite.com&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="r"&gt;end&lt;/span&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;

&lt;br&gt;

&lt;strong&gt;Server side Redirection&lt;/strong&gt;&lt;br&gt;
The server transparently rewrites the request URL to another URL. User remains on the same website and the URL on the client browser does not change.

&lt;table class="CodeRay"&gt;&lt;tr&gt;
  &lt;td title="click to toggle" class="line_numbers"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;6&lt;tt&gt;
&lt;/tt&gt;7&lt;tt&gt;
&lt;/tt&gt;8&lt;tt&gt;
&lt;/tt&gt;9&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre&gt;&lt;span class="c"&gt;##&amp;lt;strong&amp;gt;Two ways&amp;lt;/strong&amp;gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="c"&gt;# 1. Use routes.rb&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="c"&gt;# in routes.rb write following to redirect incoming request to 'your_controller/create_new'&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;map.connect &lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;my_controller/create&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;, &lt;span class="sy"&gt;:controller&lt;/span&gt; =&amp;gt; &lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;your_controller&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;, &lt;span class="sy"&gt;:action&lt;/span&gt; =&amp;gt; &lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;create_new&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt; &lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="c"&gt;# 2. render :action&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="c"&gt;# in my_controller&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="r"&gt;def&lt;/span&gt; &lt;span class="fu"&gt;create&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  render &lt;span class="sy"&gt;:controller&lt;/span&gt; =&amp;gt; &lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;your_controller&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;, &lt;span class="sy"&gt;:action&lt;/span&gt; =&amp;gt; &lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;create_new&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="r"&gt;end&lt;/span&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;

&lt;br&gt;

&lt;strong&gt; Server side Forwarding &lt;/strong&gt;&lt;br&gt;
&lt;p&gt;The server transparently rewrites the requrest URL to another URL. The user is moved to a NEW website and the URL on the client browser does not change. Also known as url masking or url cloaking or url shadowing. The most common method is by &lt;a href="http://en.wikipedia.org/wiki/URL_redirection#Frame_redirects"&gt;Frame Redirects&lt;/a&gt;&lt;/p&gt;&lt;br /&gt;

&lt;p&gt;&lt;b&gt;Note&lt;/b&gt; : &lt;i&gt;Apache "core" does NOT perform ANY sort of redirection. Add on modules like &lt;b&gt;mod_redirect&lt;/b&gt; to get Client-Side Redirection, &lt;b&gt;mod_rewrite&lt;/b&gt; to get Server-Side Redirection, and &lt;b&gt;mod_proxy&lt;/b&gt; to get Server-Side Forwarding. So, the ability to redirect is NOT built-in; the modules happen to be in common distros and configuration is baked into httpd.config and .htaccess.&lt;/i&gt;&lt;/p&gt;

&lt;p&gt;&lt;span&gt;&lt;b&gt;(shamelessly copied from &lt;a href="http://blogs.msdn.com/david.wang/archive/2005/08/01/HOWTO_Common_URL_Redirection_Techniques_for_IIS_Summary.aspx"&gt;Domain Forwarding in IIS&lt;/a&gt;)&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;p /&gt;&lt;br /&gt;

&lt;strong&gt;DNS Forwarding&lt;/strong&gt; &lt;br /&gt;
The output is exactly similar to Server side Forwarding but approach is different. The user is moved to NEW website and the URL on the client browser does not change. You need to set appropiate CNAME entry in your domainname record at your DNS server. Many hosting service providers or registrars provide you with this service by the name 'Domainname forwarding'. If you have your own DNS server, you can easily set CNAME entry. For example :

&lt;table class="CodeRay"&gt;&lt;tr&gt;
  &lt;td title="click to toggle" class="line_numbers"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre&gt;; my website is www.mysite.com. &lt;span class="co"&gt;I&lt;/span&gt; want to redirect blog.mysite.com to www.myblog.com&lt;tt&gt;
&lt;/tt&gt;; &lt;span class="co"&gt;I&lt;/span&gt; will add following record &lt;span class="r"&gt;in&lt;/span&gt; the &lt;span class="co"&gt;DNS&lt;/span&gt; setting of www.mysite.com&lt;tt&gt;
&lt;/tt&gt;blog       &lt;span class="co"&gt;IN&lt;/span&gt;      &lt;span class="co"&gt;CNAME&lt;/span&gt;  www.myblog.com.&lt;tt&gt;
&lt;/tt&gt;; &lt;span class="co"&gt;NOTE&lt;/span&gt; : &lt;span class="r"&gt;do&lt;/span&gt; &lt;span class="r"&gt;not&lt;/span&gt; forget to put &lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt; &lt;span class="r"&gt;in&lt;/span&gt; the &lt;span class="r"&gt;end&lt;/span&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;


For detailed information about CNAME, please refer to &lt;a href="http://www.zytrax.com/books/dns/ch8/cname.html"&gt;Canonical Name Record (CNAME)&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;

&lt;span class="header"&gt;References&lt;/span&gt;&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="http://en.wikipedia.org/wiki/URL_redirection"&gt;Wikipedia on URL Redirection&lt;/a&gt;
&lt;li&gt;&lt;a href="http://blogs.msdn.com/david.wang/archive/2005/08/01/HOWTO_Common_URL_Redirection_Techniques_for_IIS_Summary.aspx"&gt;Domain Forwarding in IIS&lt;/a&gt;
&lt;li&gt;&lt;a href="http://railsforum.com/viewtopic.php?id=1340"&gt;http://railsforum.com/viewtopic.php?id=1340&lt;/a&gt;
&lt;/ul&gt;
          </content>  <feedburner:origLink>http://www.quarkruby.com/2007/8/25/domain-forwarding-or-domain-redirection</feedburner:origLink></entry>
  <entry xml:base="http://www.quarkruby.com/">
    <author>
      <name>nakul</name>
    </author>
    <id>tag:www.quarkruby.com,2007-08-23:4</id>
    <published>2007-08-23T08:28:00Z</published>
    <updated>2007-11-05T06:14:24Z</updated>
    <category term="our tools" />
    <category term="ruby" />
    <category term="html scraping" />
    <category term="scrapi" />
    <link href="http://feedproxy.google.com/~r/Quarkruby/~3/UTZFUnSmNP4/qscraper-hpricot-interface-to-scrapi" rel="alternate" type="text/html" />
    <title>QScraper : hpricot interface to scrapi</title>
<summary type="html">&lt;p&gt;QScraper is a wrapper over &lt;a href="http://blog.labnotes.org/2006/07/11/scraping-with-style-scrapi-toolkit-for-ruby/"&gt;scrapi&lt;/a&gt; to provide Hpricot like interface.&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;Motivation&lt;/strong&gt;: Hpricot interface is simple and easy to use while scrapi is more powerful because of bundle scraping and anonymous classes. I was using hpricot for quick testing and checking but scrapi for project implementation. To avoid working with two html scrapers, I wrote this wrapper over scrapi.
&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Bundle Scraping&lt;/strong&gt;: It refers to extraction of multiple attributes of an element from a web page in a single parse. Most screen scraping tools extract only multiple elements but not multiple attributes of an element. Lets take an example of blog scraping, each blog post would be an element and I would like to extract multiple attributes of blog post like info about author, published on, title and content. Rather than making individual calls like doc.search(author_selector), doc.search(published_selector) etc., I would like to do doc.find(author_selector, date_selector, title ...). 
&lt;/p&gt;</summary><content type="html">
            &lt;p&gt;QScraper is a wrapper over &lt;a href="http://blog.labnotes.org/2006/07/11/scraping-with-style-scrapi-toolkit-for-ruby/"&gt;scrapi&lt;/a&gt; to provide Hpricot like interface.&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;Motivation&lt;/strong&gt;: Hpricot interface is simple and easy to use while scrapi is more powerful because of bundle scraping and anonymous classes. I was using hpricot for quick testing and checking but scrapi for project implementation. To avoid working with two html scrapers, I wrote this wrapper over scrapi.
&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Bundle Scraping&lt;/strong&gt;: It refers to extraction of multiple attributes of an element from a web page in a single parse. Most screen scraping tools extract only multiple elements but not multiple attributes of an element. Lets take an example of blog scraping, each blog post would be an element and I would like to extract multiple attributes of blog post like info about author, published on, title and content. Rather than making individual calls like doc.search(author_selector), doc.search(published_selector) etc., I would like to do doc.find(author_selector, date_selector, title ...). 
&lt;/p&gt;

&lt;span class="header"&gt;Here comes QScraper :)&lt;/span&gt;&lt;br /&gt;
&lt;table class="CodeRay"&gt;&lt;tr&gt;
  &lt;td title="click to toggle" class="line_numbers"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;6&lt;tt&gt;
&lt;/tt&gt;7&lt;tt&gt;
&lt;/tt&gt;8&lt;tt&gt;
&lt;/tt&gt;9&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;11&lt;tt&gt;
&lt;/tt&gt;12&lt;tt&gt;
&lt;/tt&gt;13&lt;tt&gt;
&lt;/tt&gt;14&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;15&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;16&lt;tt&gt;
&lt;/tt&gt;17&lt;tt&gt;
&lt;/tt&gt;18&lt;tt&gt;
&lt;/tt&gt;19&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;20&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;21&lt;tt&gt;
&lt;/tt&gt;22&lt;tt&gt;
&lt;/tt&gt;23&lt;tt&gt;
&lt;/tt&gt;24&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;25&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;26&lt;tt&gt;
&lt;/tt&gt;27&lt;tt&gt;
&lt;/tt&gt;28&lt;tt&gt;
&lt;/tt&gt;29&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;30&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;31&lt;tt&gt;
&lt;/tt&gt;32&lt;tt&gt;
&lt;/tt&gt;33&lt;tt&gt;
&lt;/tt&gt;34&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;35&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;36&lt;tt&gt;
&lt;/tt&gt;37&lt;tt&gt;
&lt;/tt&gt;38&lt;tt&gt;
&lt;/tt&gt;39&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;40&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;41&lt;tt&gt;
&lt;/tt&gt;42&lt;tt&gt;
&lt;/tt&gt;43&lt;tt&gt;
&lt;/tt&gt;44&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;45&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;46&lt;tt&gt;
&lt;/tt&gt;47&lt;tt&gt;
&lt;/tt&gt;48&lt;tt&gt;
&lt;/tt&gt;49&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;50&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;51&lt;tt&gt;
&lt;/tt&gt;52&lt;tt&gt;
&lt;/tt&gt;53&lt;tt&gt;
&lt;/tt&gt;54&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;55&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;56&lt;tt&gt;
&lt;/tt&gt;57&lt;tt&gt;
&lt;/tt&gt;58&lt;tt&gt;
&lt;/tt&gt;59&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;60&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;61&lt;tt&gt;
&lt;/tt&gt;62&lt;tt&gt;
&lt;/tt&gt;63&lt;tt&gt;
&lt;/tt&gt;64&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;65&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;66&lt;tt&gt;
&lt;/tt&gt;67&lt;tt&gt;
&lt;/tt&gt;68&lt;tt&gt;
&lt;/tt&gt;69&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;70&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;71&lt;tt&gt;
&lt;/tt&gt;72&lt;tt&gt;
&lt;/tt&gt;73&lt;tt&gt;
&lt;/tt&gt;74&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;75&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;76&lt;tt&gt;
&lt;/tt&gt;77&lt;tt&gt;
&lt;/tt&gt;78&lt;tt&gt;
&lt;/tt&gt;79&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;80&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;81&lt;tt&gt;
&lt;/tt&gt;82&lt;tt&gt;
&lt;/tt&gt;83&lt;tt&gt;
&lt;/tt&gt;84&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;85&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;86&lt;tt&gt;
&lt;/tt&gt;87&lt;tt&gt;
&lt;/tt&gt;88&lt;tt&gt;
&lt;/tt&gt;89&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;90&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;91&lt;tt&gt;
&lt;/tt&gt;92&lt;tt&gt;
&lt;/tt&gt;93&lt;tt&gt;
&lt;/tt&gt;94&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;95&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;96&lt;tt&gt;
&lt;/tt&gt;97&lt;tt&gt;
&lt;/tt&gt;98&lt;tt&gt;
&lt;/tt&gt;99&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;100&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;101&lt;tt&gt;
&lt;/tt&gt;102&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre&gt;require &lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;rubygems&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;require &lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;scrapi&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;require &lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;open-uri&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="r"&gt;class&lt;/span&gt; &lt;span class="cl"&gt;QScraper&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  attr_accessor &lt;span class="sy"&gt;:document&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  attr_accessor &lt;span class="sy"&gt;:rule_list&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="c"&gt;# source can be a node or file&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="c"&gt;# Constructor for this class ..&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="c"&gt;# Takes a source (file or html::node) as argument.&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="c"&gt;# Example : qScraper = QScraper.new(&amp;quot;index.html&amp;quot;)&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="r"&gt;def&lt;/span&gt; &lt;span class="fu"&gt;initialize&lt;/span&gt; source, local_file=&lt;span class="pc"&gt;true&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="r"&gt;case&lt;/span&gt; source&lt;tt&gt;
&lt;/tt&gt;      &lt;span class="r"&gt;when&lt;/span&gt; &lt;span class="co"&gt;URI&lt;/span&gt;, &lt;span class="co"&gt;HTML&lt;/span&gt;::&lt;span class="co"&gt;Node&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;        &lt;span class="iv"&gt;@document&lt;/span&gt; = source&lt;tt&gt;
&lt;/tt&gt;      &lt;span class="r"&gt;when&lt;/span&gt; &lt;span class="co"&gt;String&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;        &lt;span class="iv"&gt;@document&lt;/span&gt; = (local_file &amp;amp;&amp;amp; &lt;span class="co"&gt;File&lt;/span&gt;.exists?(source)) ?  &lt;span class="co"&gt;File&lt;/span&gt;.read(source) : source&lt;tt&gt;
&lt;/tt&gt;      &lt;span class="r"&gt;else&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;        raise &lt;span class="co"&gt;ArgumentError&lt;/span&gt;, &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;Can only scrape URI, String or HTML::Node&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="c"&gt;# search string selector in given source and &lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="c"&gt;# returns all the matching elements as HTML::Tag object&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="c"&gt;# Selector is a css selector &lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="c"&gt;# Example:&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="c"&gt;# qScraper.search(&amp;quot;div.highlight&amp;quot;)&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="r"&gt;def&lt;/span&gt; &lt;span class="fu"&gt;search&lt;/span&gt; selector&lt;tt&gt;
&lt;/tt&gt;    output = (&lt;span class="co"&gt;Scraper&lt;/span&gt;.define &lt;span class="r"&gt;do&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;      array &lt;span class="sy"&gt;:elems&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;      process selector, &lt;span class="sy"&gt;:elems&lt;/span&gt; =&amp;gt;&lt;span class="sy"&gt;:element&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;      result &lt;span class="sy"&gt;:elems&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="r"&gt;end&lt;/span&gt;).scrape(&lt;span class="iv"&gt;@document&lt;/span&gt;)&lt;tt&gt;
&lt;/tt&gt;    output&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="c"&gt;# search the first node matching this selector&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="r"&gt;def&lt;/span&gt; &lt;span class="fu"&gt;search_first&lt;/span&gt; selector&lt;tt&gt;
&lt;/tt&gt;    output = (&lt;span class="co"&gt;Scraper&lt;/span&gt;.define &lt;span class="r"&gt;do&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;      process_first selector, &lt;span class="sy"&gt;:elem&lt;/span&gt;=&amp;gt;&lt;span class="sy"&gt;:element&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;      result &lt;span class="sy"&gt;:elem&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="r"&gt;end&lt;/span&gt;).scrape(&lt;span class="iv"&gt;@document&lt;/span&gt;)&lt;tt&gt;
&lt;/tt&gt;    output&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="c"&gt;# Adds a rule for parsing, you can add many rules and &lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="c"&gt;# then parse them by making a call to parse_rules&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="c"&gt;# Example:&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="c"&gt;# q.add_rule({&amp;quot;br#lgpd&amp;quot;=&amp;gt;{:n1ame=&amp;gt;&amp;quot;@id&amp;quot;}})&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="r"&gt;def&lt;/span&gt; &lt;span class="fu"&gt;add_rule&lt;/span&gt; selector, extractors&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="iv"&gt;@rule_list&lt;/span&gt; ||= {}&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="iv"&gt;@rule_list&lt;/span&gt;.merge!({selector=&amp;gt;extractors})&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="c"&gt;# Example:&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="c"&gt;# q.add_rules({&amp;quot;table.searchResults2&amp;gt;tbody&amp;gt;tr&amp;gt;td:nth-of-type(3)&amp;gt;a&amp;quot;=&amp;gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="c"&gt;#                               {:href=&amp;gt;&amp;quot;@href&amp;quot;,:name=&amp;gt;:text},&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="c"&gt;#              &amp;quot;table.searchResults2&amp;gt;tr&amp;gt;td:nth-of-type(3)&amp;gt;a.cat&amp;quot;=&amp;gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="c"&gt;#                               {:reviewcount=&amp;gt;:text}})&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="r"&gt;def&lt;/span&gt; &lt;span class="fu"&gt;add_rules&lt;/span&gt; selector_extractors_hash&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="iv"&gt;@rule_list&lt;/span&gt; ||= {}&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="iv"&gt;@rule_list&lt;/span&gt;.merge! (selector_extractors_hash)&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="c"&gt;# parses the given rule set .. specified by add_rule methods.&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="r"&gt;def&lt;/span&gt; &lt;span class="fu"&gt;parse_rules&lt;/span&gt; parser=&lt;span class="pc"&gt;nil&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    result_string = &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;result &lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="iv"&gt;@rule_list&lt;/span&gt;.values.each &lt;span class="r"&gt;do&lt;/span&gt; |j| &lt;tt&gt;
&lt;/tt&gt;        j.keys.each {|i| &lt;tt&gt;
&lt;/tt&gt;           result_string &amp;lt;&amp;lt; &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;:&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &amp;lt;&amp;lt; i.to_s &amp;lt;&amp;lt; &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;, &lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;        }&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    result_string = result_string[&lt;span class="i"&gt;0&lt;/span&gt;..&lt;span class="i"&gt;-3&lt;/span&gt;]&lt;tt&gt;
&lt;/tt&gt;    array_string = result_string.sub(&lt;span class="rx"&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;span class="k"&gt;result&lt;/span&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;/span&gt;,&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;array&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;)&lt;tt&gt;
&lt;/tt&gt;    create_process_string = &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="iv"&gt;@rule_list&lt;/span&gt;.keys.each {|i|&lt;tt&gt;
&lt;/tt&gt;      create_process_string &amp;lt;&amp;lt; &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;process &lt;/span&gt;&lt;span class="ch"&gt;\&amp;quot;&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &amp;lt;&amp;lt; i &amp;lt;&amp;lt; &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="ch"&gt;\&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;, &lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;tt&gt;
&lt;/tt&gt;      create_process_string &amp;lt;&amp;lt; &lt;span class="iv"&gt;@rule_list&lt;/span&gt;[i].inspect.gsub(&lt;span class="rx"&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;span class="k"&gt;[{}]&lt;/span&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;/span&gt;,&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;) &amp;lt;&amp;lt; &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="ch"&gt;\n&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    }&lt;tt&gt;
&lt;/tt&gt;    res = &lt;span class="co"&gt;String&lt;/span&gt;.module_eval &lt;span class="s"&gt;&lt;span class="dl"&gt;%{&lt;/span&gt;&lt;span class="k"&gt;Scraper.define do&lt;tt&gt;
&lt;/tt&gt;      &lt;/span&gt;&lt;span class="il"&gt;&lt;span class="dl"&gt;#{&lt;/span&gt;array_string&lt;span class="dl"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="k"&gt;&lt;tt&gt;
&lt;/tt&gt;      &lt;/span&gt;&lt;span class="il"&gt;&lt;span class="dl"&gt;#{&lt;/span&gt;create_process_string&lt;span class="dl"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="k"&gt;&lt;tt&gt;
&lt;/tt&gt;      &lt;/span&gt;&lt;span class="il"&gt;&lt;span class="dl"&gt;#{&lt;/span&gt;result_string&lt;span class="dl"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="k"&gt;&lt;tt&gt;
&lt;/tt&gt;    end&lt;/span&gt;&lt;span class="dl"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    parser ||= &lt;span class="sy"&gt;:tidy&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    f = res.scrape(&lt;span class="iv"&gt;@document&lt;/span&gt;,&lt;span class="sy"&gt;:parser&lt;/span&gt;=&amp;gt;parser)&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="c"&gt;# Small extension to scrapi's HTML::Tag class &lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="c"&gt;# for &amp;quot;inner_html&amp;quot; method.&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="c"&gt;#&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="r"&gt;module&lt;/span&gt; &lt;span class="cl"&gt;HTML&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="r"&gt;class&lt;/span&gt; &lt;span class="cl"&gt;Tag&lt;/span&gt; &amp;lt; &lt;span class="co"&gt;Node&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="r"&gt;def&lt;/span&gt; &lt;span class="fu"&gt;inner_html&lt;/span&gt; &lt;tt&gt;
&lt;/tt&gt;      data = &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;      children.each {|e| data += e.to_s}&lt;tt&gt;
&lt;/tt&gt;      data&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="r"&gt;end&lt;/span&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;

&lt;span class="header"&gt;Usage&lt;/span&gt;
&lt;table class="CodeRay"&gt;&lt;tr&gt;
  &lt;td title="click to toggle" class="line_numbers"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;6&lt;tt&gt;
&lt;/tt&gt;7&lt;tt&gt;
&lt;/tt&gt;8&lt;tt&gt;
&lt;/tt&gt;9&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;11&lt;tt&gt;
&lt;/tt&gt;12&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre&gt;  &lt;span class="c"&gt;# Example page to parse : http://www.google.co.in/search?q=scrapi&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  doc = &lt;span class="co"&gt;QScraper&lt;/span&gt;.new(open(&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;http://www.google.co.in/search?q=scrapi&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;){|f| f.read})&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="c"&gt;# Extracting titles elements of search results &lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="c"&gt;# returned objects are of HTML::Tag type&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  result = doc.search(&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;a.l&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;)&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="c"&gt;# now extracting title and link for each of the search results.&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  doc.add_rules({&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;a.l&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;=&amp;gt;{&lt;span class="sy"&gt;:url&lt;/span&gt;=&amp;gt;&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;@href&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;,&lt;span class="sy"&gt;:title&lt;/span&gt;=&amp;gt;&lt;span class="sy"&gt;:text&lt;/span&gt;}})&lt;tt&gt;
&lt;/tt&gt;  result = doc.parse_rules&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="c"&gt;#=&amp;gt; result.url returns an array of 10 url links&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="c"&gt;#=&amp;gt; result.title returns the array of titles&lt;/span&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;


&lt;span class="header"&gt;Comparison of Hpricot and scrapi(+QScraper) interface&lt;/span&gt;
&lt;table width="100%"&gt;
&lt;tr&gt;&lt;th&gt;Hpricot&lt;/th&gt; &lt;th&gt;Scrapi (with Qscraper)&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;doc=Hpricot(string/file/uri)&lt;/td&gt; &lt;td&gt;doc=QScraper(string/file/uri)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;doc.search("css selector") [or doc/"css selector"]&lt;/td&gt;&lt;td&gt;doc.search("css selector")&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;doc.at("css selector")&lt;/td&gt;&lt;td&gt;doc.search_first("css selector")&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;(doc/"css selector").inner_html &lt;/td&gt; &lt;td&gt; doc.search_first("css selector").inner_html &lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;(doc/"css selector").to_html&lt;/td&gt; &lt;td&gt; doc.search_first("css selector").to_s &lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;allows html page editing&lt;/td&gt;&lt;td&gt; --N/A-- &lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;--N/A--&lt;/td&gt;&lt;td&gt;Allows bundled scraping (example below)&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
&lt;br /&gt;

&lt;p&gt;
&lt;strong&gt;TODO&lt;/strong&gt;: Add XPath support in scrapi.
&lt;/p&gt;
          </content>  <feedburner:origLink>http://www.quarkruby.com/2007/8/23/qscraper-hpricot-interface-to-scrapi</feedburner:origLink></entry>
</feed>
