<?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:openSearch="http://a9.com/-/spec/opensearch/1.1/" xmlns:georss="http://www.georss.org/georss" xmlns:gd="http://schemas.google.com/g/2005" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" gd:etag="W/&quot;AkcEQng4cSp7ImA9WxNVEUo.&quot;"><id>tag:blogger.com,1999:blog-974036606587739553</id><updated>2009-10-21T19:20:03.639-07:00</updated><title>Ibrahim Ahmed</title><subtitle type="html">web_development.lessons.map(&amp;:learned!)</subtitle><link rel="http://schemas.google.com/g/2005#feed" type="application/atom+xml" href="http://www.ibrahim-ahmed.com/feeds/posts/default" /><link rel="alternate" type="text/html" href="http://www.ibrahim-ahmed.com/" /><link rel="hub" href="http://pubsubhubbub.appspot.com/" /><author><name>Ibrahim Ahmed</name><uri>http://www.blogger.com/profile/01640528992428968621</uri><email>noreply@blogger.com</email></author><generator version="7.00" uri="http://www.blogger.com">Blogger</generator><openSearch:totalResults>15</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><link rel="self" href="http://feeds.feedburner.com/IbrahimAhmed" type="application/atom+xml" /><feedburner:emailServiceId>IbrahimAhmed</feedburner:emailServiceId><feedburner:feedburnerHostname>http://feedburner.google.com</feedburner:feedburnerHostname><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com" /><entry><title type="text">Links for 2009-01-28 [del.icio.us]</title><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/IbrahimAhmed/~3/4j1tb1-uXu8/ibrahimahmed" /><updated>2009-01-29T00:00:00-08:00</updated><id>http://del.icio.us/ibrahimahmed#2009-01-28</id><content type="html">&lt;ul&gt;
&lt;li&gt;&lt;a href="http://www.stripegenerator.com/#Zm9yZT02MkQxMDA7aD0zMDt3PTM7cD0yO2JhY2sxPURERkYwMDtiYWNrMj1mZjAwMDA7Z3Q9MDtkPTA7c2hhZG93PTA7"&gt;Stripe Generator - ajax diagonal stripes background designer&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.freshgenerator.com/"&gt;Fresh Generator - Web 2.0 boxes made easy Pages&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;img src="http://feeds.feedburner.com/~r/IbrahimAhmed/~4/4j1tb1-uXu8" height="1" width="1"/&gt;</content><feedburner:origLink>http://del.icio.us/ibrahimahmed#2009-01-28</feedburner:origLink></entry><entry><title type="text">Links for 2009-01-08 [del.icio.us]</title><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/IbrahimAhmed/~3/WxL_l8uIOFY/ibrahimahmed" /><updated>2009-01-09T00:00:00-08:00</updated><id>http://del.icio.us/ibrahimahmed#2009-01-08</id><content type="html">&lt;ul&gt;
&lt;li&gt;&lt;a href="http://github.com/rubypond/semantic_form_builder/tree/master"&gt;rubypond's semantic_form_builder at master &amp;mdash; GitHub&lt;/a&gt;&lt;br/&gt;
A custom builder (and some helper methods) for creating consistent and accessible forms in rails&lt;/li&gt;
&lt;/ul&gt;&lt;img src="http://feeds.feedburner.com/~r/IbrahimAhmed/~4/WxL_l8uIOFY" height="1" width="1"/&gt;</content><feedburner:origLink>http://del.icio.us/ibrahimahmed#2009-01-08</feedburner:origLink></entry><entry><title type="text">Links for 2009-01-07 [del.icio.us]</title><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/IbrahimAhmed/~3/i_8KBxpvPbA/ibrahimahmed" /><updated>2009-01-08T00:00:00-08:00</updated><id>http://del.icio.us/ibrahimahmed#2009-01-07</id><content type="html">&lt;ul&gt;
&lt;li&gt;&lt;a href="http://github.com/crafterm/sprinkle/tree/master"&gt;crafterm's sprinkle at master &amp;mdash; GitHub&lt;/a&gt;&lt;br/&gt;
A software provisioning software! an unclear description to a very promising tool, to make it easy for us to deploy or install software locally or remotely, and the key feature is &amp;quot;dependencies management&amp;quot;&lt;/li&gt;
&lt;/ul&gt;&lt;img src="http://feeds.feedburner.com/~r/IbrahimAhmed/~4/i_8KBxpvPbA" height="1" width="1"/&gt;</content><feedburner:origLink>http://del.icio.us/ibrahimahmed#2009-01-07</feedburner:origLink></entry><entry><title type="text">Links for 2009-01-04 [del.icio.us]</title><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/IbrahimAhmed/~3/OXA0SeqY1hE/ibrahimahmed" /><updated>2009-01-05T00:00:00-08:00</updated><id>http://del.icio.us/ibrahimahmed#2009-01-04</id><content type="html">&lt;ul&gt;
&lt;li&gt;&lt;a href="http://excess.org/article/2008/07/ogre-git-tutorial/"&gt;OGRE Git Tutorial - excess.org&lt;/a&gt;&lt;br/&gt;
This is a recording of the Git tutorial given by Bart Trojanowski for the Ottawa Group of Ruby Enthusiasts.&lt;/li&gt;
&lt;/ul&gt;&lt;img src="http://feeds.feedburner.com/~r/IbrahimAhmed/~4/OXA0SeqY1hE" height="1" width="1"/&gt;</content><feedburner:origLink>http://del.icio.us/ibrahimahmed#2009-01-04</feedburner:origLink></entry><entry><title type="text">Links for 2008-12-15 [del.icio.us]</title><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/IbrahimAhmed/~3/DMREn6XrcNM/ibrahimahmed" /><updated>2008-12-16T00:00:00-08:00</updated><id>http://del.icio.us/ibrahimahmed#2008-12-15</id><content type="html">&lt;ul&gt;
&lt;li&gt;&lt;a href="http://sifterapp.com/"&gt;Simple Bug and Issue Tracking | Sifter&lt;/a&gt;&lt;br/&gt;
Sifter is a hosted bug and issue tracking application focused on making work less tedious.&lt;/li&gt;
&lt;li&gt;&lt;a href="http://whygitisbetterthanx.com/"&gt;Why Git is Better Than X&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.ibrahim-ahmed.com/2008/12/rails-actioncontroller-facelift-using.html"&gt;Ibrahim Ahmed: Rails ActionController facelift using ResourceController and named_scope&lt;/a&gt;&lt;br/&gt;
Make Rails controller more powerful yet simpler using ResourceController plugin and ActiveRecord named_scope.&lt;/li&gt;
&lt;/ul&gt;&lt;img src="http://feeds.feedburner.com/~r/IbrahimAhmed/~4/DMREn6XrcNM" height="1" width="1"/&gt;</content><feedburner:origLink>http://del.icio.us/ibrahimahmed#2008-12-15</feedburner:origLink></entry><entry gd:etag="W/&quot;DUAFRnY4eSp7ImA9WxRaE04.&quot;"><id>tag:blogger.com,1999:blog-974036606587739553.post-7072140911154024020</id><published>2008-12-14T02:40:00.000-08:00</published><updated>2008-12-15T02:41:57.831-08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-12-15T02:41:57.831-08:00</app:edited><title>Rails ActionController facelift using ResourceController and named_scope</title><content type="html">I am pretty sure that it is not only my Rails controllers which changed appearance more than once during the past 3 or 4 years. Concepts like RESTful controllers, nested resources, ActiveRecord scoping kept on changing the way we build our Rails controller. Nowadays, my Rails controllers are barely similar to what they looked like 4 years ago.&lt;br /&gt;&lt;br /&gt;During pre REST days, my controllers were so ugly and fat. with too many actions to count and do a lot more than the controller meant to do in an MVC framework. Then came RESTful controller which was really, really a nice way to help application designer to organize and "design" the application. RESTful controllers concept is revolutionary in that it simplified or abstract away the complexity of the application plumbing and repetitive routines and made my poor little mind focus on the application design instead.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;And then came resources scaffold&lt;br /&gt;&lt;/span&gt;The scaffold generator now do us all the work to have a nice RESTful controller that can CRUD your model and responds to HTML, XML, JS. But I need to confess that I've never liked generators. Heck, it is the only reason why I don't use IDEs. They pollute my code with lines I didn't write, and that's plain ugly. It is lovely to have your controller speak REST in XML, but it was not a good feeling when I see all those respond_to lines scattered all over my controllers at the time when my application is not yet designed to be used as such.&lt;br /&gt;&lt;br /&gt;And what made it really worse is that most of the time the generated controller needed almost 80% editing, to scope my models I use in the controllers, like @site.pages, @user.posts, and to paginate results, set model attributes assignments..etc. So it was obvious that generators wouldn't cut it. We needed some help to abstract all the repetitive codes in our controller and find a solution for problems like relations aware controller that respect scoping, can deal with nested resource and namespaces. I am sure that any rails developer (or any MVC web developer) knows the kind of problem I am talking about.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;Resource Controller plugin&lt;/span&gt;&lt;br /&gt;More than a year ago I found &lt;a href="http://github.com/jnewland/resource_this/tree/master"&gt;some&lt;/a&gt; &lt;a href="http://hamptoncatlin.com/2007/make_resourceful-presentation"&gt;Rails&lt;/a&gt; plugins to do just that. But I was  too skeptical to use them in production. Time passed and there are now a really good, tested and tried solution for the kind of problem I am talking about. It is called "&lt;a href="http://www.github.com/giraffesoft/resource_controller/tree/master"&gt;Resource Controller&lt;/a&gt;".&lt;br /&gt;&lt;br /&gt;It is a fine plugin written by  &lt;a href="http://jamesgolick.com/"&gt;James Golick&lt;/a&gt;. Thank you James. The other plugins like resource_this and make_resourceful were steps in the right direction but &lt;a href="http://www.github.com/giraffesoft/resource_controller/tree/master"&gt;Resource_Controller&lt;/a&gt; is the way to go.&lt;br /&gt;&lt;span style="display: block;" id="formatbar_Buttons"&gt;&lt;span class="on down" style="display: block;" id="formatbar_CreateLink" title="Link" onmouseover="ButtonHoverOn(this);" onmouseout="ButtonHoverOff(this);" onmouseup="" onmousedown="CheckFormatting(event);FormatbarButton('richeditorframe', this, 8);ButtonMouseDown(this);"&gt;&lt;img src="http://www.blogger.com/img/blank.gif" alt="Link" class="gl_link" border="0" /&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;After months of using it I feel pretty confident with resource controller. And as all tools that abstract away repetitive noise it allowed me to focus more on my application design and actually I developed more productive patterns in developing my application.  Patterns that changed the face of my rails controllers beyond recognition. Here is a minimal Resource Controller.&lt;br /&gt;&lt;table class="CodeRay"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;br /&gt;&lt;td class="line_numbers" title="click to toggle" onclick="with (this.firstChild.style) { display = (display == '') ? 'none' : '' }"&gt;&lt;pre&gt;1&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;2&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;&lt;br /&gt;&lt;td class="code"&gt;&lt;pre ondblclick="with (this.style) { overflow = (overflow == 'auto' || overflow == '') ? 'visible' : 'auto' }"&gt;&lt;span class="r"&gt;class&lt;/span&gt; &lt;span class="cl"&gt;UsersController&lt;/span&gt; &amp;lt; &lt;span class="co"&gt;ResourceController&lt;/span&gt;::&lt;span class="co"&gt;Base&lt;/span&gt;&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;&lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;&lt;br /&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;Suddenly, I had this ActiveRecord thrill again, but with Resource Controller this time. I bet this is the skinniest controller &lt;a href="http://weblog.jamisbuck.org/2006/10/18/skinny-controller-fat-model"&gt;one could dream about&lt;/a&gt;. Come on Rails core team, when will we see Jamis' Resource controller merged!&lt;br /&gt;&lt;br /&gt;Well the next thing to do is playing around and try to see how to solve the problems I mentioned above. But only after introducing my newest love, "Named scope". which prove very  useful in DRYing my controller even more.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;Named Scopes&lt;br /&gt;&lt;/span&gt;I always thought that the best feature in ActiveRecord is scoping through associations. Like, '&lt;span style="font-family:courier new;"&gt;@user.posts.find(:all, :limit =&gt; 10)&lt;/span&gt;'. This feature alone is enough to use ActiveRecord. The next best ever feature in ActiveRecord is &lt;a href="http://guides.rails.info/finders.html#_named_scopes"&gt;named_scope&lt;/a&gt;. I couldn't recommend enough using named_scope. Just &lt;a href="http://api.rubyonrails.com/classes/ActiveRecord/NamedScope/ClassMethods.html#M001648"&gt;use&lt;/a&gt; it. It is core since Rails 2.1.&lt;br /&gt;&lt;br /&gt;Coupling named_scope with Resource Controllers really open new application design territory. Imagine the following requirement.&lt;br /&gt;&lt;ul&gt;&lt;li&gt;One pages controller that can be used to list all the pages in a portal&lt;/li&gt;&lt;li&gt;It could be used nested under users resource, so it should scope pages to user.&lt;/li&gt;&lt;li&gt;It should handle posts pending for approvals.&lt;/li&gt;&lt;li&gt;It should fetch the next and previous pages according to the context or the scope it works within, be it portal pages, users pages, or user's pending pages or portal's pending pages.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;Let's build the controller&lt;/span&gt;&lt;span style="font-size:100%;"&gt;&lt;br /&gt;First we do the routes, a simple nested routes and then the controller.&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;table class="CodeRay"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;span style="font-size:100%;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;td class="line_numbers" title="click to toggle" onclick="with (this.firstChild.style) { display = (display == '') ? 'none' : '' }"&gt;&lt;pre&gt;1&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;2&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;3&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;4&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;5&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;6&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;7&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;8&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;&lt;br /&gt;&lt;td class="code"&gt;&lt;pre ondblclick="with (this.style) { overflow = (overflow == 'auto' || overflow == '') ? 'visible' : 'auto' }"&gt;map.resources &lt;span class="sy"&gt;:users&lt;/span&gt; &lt;span class="r"&gt;do&lt;/span&gt; |user|&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;    user.resources &lt;span class="sy"&gt;:pages&lt;/span&gt;&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;&lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;map.resources &lt;span class="sy"&gt;:pages&lt;/span&gt;&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;&lt;span class="r"&gt;class&lt;/span&gt; &lt;span class="cl"&gt;PagesController&lt;/span&gt; &amp;lt; &lt;span class="co"&gt;ResourceController&lt;/span&gt;::&lt;span class="co"&gt;Base&lt;/span&gt;&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;    belongs_to &lt;span class="sy"&gt;:user&lt;/span&gt;&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;&lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;&lt;br /&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;This is the simplest form of controller to make it serve routes like /user/12/pages/new and do all the REST actions, be it scoped to user or not. But certainly life isn't that simple. What if you want to paginate results and get user by user_name instead of user_id like "/user/hany/pages".&lt;br /&gt;&lt;br /&gt;&lt;table class="CodeRay"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;br /&gt;&lt;td class="line_numbers" title="click to toggle" onclick="with (this.firstChild.style) { display = (display == '') ? 'none' : '' }"&gt;&lt;pre&gt;1&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;2&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;3&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;4&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;5&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;6&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;7&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;8&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;9&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;11&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;12&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;13&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;14&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;15&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;16&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;17&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;18&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;19&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;&lt;br /&gt;&lt;td class="code"&gt;&lt;pre ondblclick="with (this.style) { overflow = (overflow == 'auto' || overflow == '') ? 'visible' : 'auto' }"&gt;&lt;span class="r"&gt;class&lt;/span&gt; &lt;span class="cl"&gt;PagesController&lt;/span&gt; &amp;lt; &lt;span class="co"&gt;ResourceController&lt;/span&gt;::&lt;span class="co"&gt;Base&lt;/span&gt;  &lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;  before_filter &lt;span class="sy"&gt;:set_scope&lt;/span&gt; &lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;  belongs_to &lt;span class="sy"&gt;:user&lt;/span&gt; &lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;  private &lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;  &lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;  &lt;span class="r"&gt;def&lt;/span&gt; &lt;span class="fu"&gt;parent_object&lt;/span&gt; &lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;    &lt;span class="iv"&gt;@parent&lt;/span&gt; ||= &lt;span class="co"&gt;User&lt;/span&gt;.find_by_name(params[&lt;span class="sy"&gt;:user_id&lt;/span&gt;]) &lt;span class="r"&gt;if&lt;/span&gt; params[&lt;span class="sy"&gt;:user_id&lt;/span&gt;] &lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;  &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;  &lt;span class="r"&gt;def&lt;/span&gt; &lt;span class="fu"&gt;set_scope&lt;/span&gt; &lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;    &lt;span class="iv"&gt;@scope&lt;/span&gt; = &lt;span class="iv"&gt;@portal&lt;/span&gt;.pages &lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;    &lt;span class="iv"&gt;@scope&lt;/span&gt; = &lt;span class="iv"&gt;@scope&lt;/span&gt;.by_user(parent_object.id) &lt;span class="r"&gt;if&lt;/span&gt; parent_object &lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;  &lt;span class="r"&gt;end&lt;/span&gt; &lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;  &lt;span class="r"&gt;def&lt;/span&gt; &lt;span class="fu"&gt;collection&lt;/span&gt; &lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;    &lt;span class="iv"&gt;@pages&lt;/span&gt; ||= &lt;span class="iv"&gt;@scope&lt;/span&gt;.paginate(&lt;span class="sy"&gt;:all&lt;/span&gt;, &lt;span class="sy"&gt;:page&lt;/span&gt; =&amp;gt; params[&lt;span class="sy"&gt;:page&lt;/span&gt;])&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;  &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;&lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;&lt;br /&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;Here I added some private methods. The parent_object method to get the parent object by name. I introduced the set_scope method which does set the scope (or context) of the collection set of pages we need to work with. Actually, parent_object and collection are both overridden methods of resource_controller. and set_scope method is mine, and I run it in a before_filter and use it in the controller to find the pages within the set scope. I could have just do scoping inside collection method, but later I will need to have a handle for the scope in different places in the controller other than "collection".&lt;br /&gt;&lt;br /&gt;The set_scope method is interesting because I stack up the scope conditionally according to the context within which the controller is running. I mean if the controller is nested in users resource it will find params[:user_id] and the parent_object return a user object and then the @scope of users pages will be added. Which is a named scope in this case "Page.by_user()". I could have use parent_object.pages which is the natural association scoping of ActiveRecord I got with the "has_many :pages" but because my application serves several portals, and @portal got assigned according to subdomains on the application controller, I don't won't to loose the @portal scope '@portal.pages' so it was either make a named_scope for portals or users.&lt;br /&gt;&lt;br /&gt;Notice here that @scope.find(:all, :conditions =&gt; {:user_id =&gt; parent_object.id}) will not do us any good because you will not be able then to narrow down those scopes by stacking them. But sure an inline or &lt;a href="http://guides.rails.info/finders.html#_anonymous_scopes"&gt;anonymous named_scope&lt;/a&gt; will suffice instead.&lt;br /&gt;&lt;br /&gt;Now I need to make the controller serve pages pending for approvals and fetch the next and previous pages properly according to the scope. Some routes need to be set first. Changing the scope is only a matter of adding a new line to the set_scope method according to the passed params[], so all I need to do is passing non blank params[:pending]. Of course passing it hanged on the url like '/user/hany/pages?pending=1' is not an option. I need it to be clean like '/user/hany/pending_pages' and to say the truth it is not about cleanliness, it is about setting proper url automagically as I will show you later.&lt;br /&gt;&lt;br /&gt;&lt;table class="CodeRay"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;br /&gt;&lt;td class="line_numbers" title="click to toggle" onclick="with (this.firstChild.style) { display = (display == '') ? 'none' : '' }"&gt;&lt;pre&gt;1&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;2&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;3&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;4&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;5&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;6&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;7&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;&lt;br /&gt;&lt;td class="code"&gt;&lt;pre ondblclick="with (this.style) { overflow = (overflow == 'auto' || overflow == '') ? 'visible' : 'auto' }"&gt;map.resources &lt;span class="sy"&gt;:users&lt;/span&gt; &lt;span class="r"&gt;do&lt;/span&gt; |user|&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;  user.resources &lt;span class="sy"&gt;:pages&lt;/span&gt;, &lt;span class="sy"&gt;:requirements&lt;/span&gt; =&amp;gt; {&lt;span class="sy"&gt;:pending&lt;/span&gt; =&amp;gt; &lt;span class="pc"&gt;false&lt;/span&gt; }&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;  user.resources &lt;span class="sy"&gt;:pending_pages&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;pages&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;, &lt;span class="sy"&gt;:requirements&lt;/span&gt; =&amp;gt; {&lt;span class="sy"&gt;:pending&lt;/span&gt; =&amp;gt; &lt;span class="pc"&gt;true&lt;/span&gt;  }&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;&lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;map.resources &lt;span class="sy"&gt;:pages&lt;/span&gt;, &lt;span class="sy"&gt;:requirements&lt;/span&gt; =&amp;gt; {&lt;span class="sy"&gt;:pending&lt;/span&gt; =&amp;gt; &lt;span class="pc"&gt;false&lt;/span&gt; }&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;map.resources &lt;span class="sy"&gt;:pending_pages&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;pages&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;, &lt;span class="sy"&gt;:requirements&lt;/span&gt; =&amp;gt; {&lt;span class="sy"&gt;:pending&lt;/span&gt; =&amp;gt; &lt;span class="pc"&gt;true&lt;/span&gt;  }&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;&lt;br /&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;Here I added pending_pages resources and pass explicitly the controller name because I will use my same pages controller. I made the resources properly set the pending parameter to true or false. I don't believe Rails 2.2 &lt;a href="http://ryandaigle.com/articles/2008/9/7/what-s-new-in-edge-rails-shallow-routes"&gt;shallow routes&lt;/a&gt; option will spare me the pages resources repetitions. May be we need another way to make the parent resources optional?! but anyways, now that we have the routes properly set, let's see the controller.&lt;br /&gt;&lt;br /&gt;&lt;table class="CodeRay"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;br /&gt;&lt;td class="line_numbers" title="click to toggle" onclick="with (this.firstChild.style) { display = (display == '') ? 'none' : '' }"&gt;&lt;pre&gt;1&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;2&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;3&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;4&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;5&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;6&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;7&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;8&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;9&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;11&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;12&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;13&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;14&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;15&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;16&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;17&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;18&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;19&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;&lt;strong&gt;20&lt;/strong&gt;&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;21&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;22&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;23&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;24&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;25&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;&lt;br /&gt;&lt;td class="code"&gt;&lt;pre ondblclick="with (this.style) { overflow = (overflow == 'auto' || overflow == '') ? 'visible' : 'auto' }"&gt;&lt;span class="r"&gt;class&lt;/span&gt; &lt;span class="cl"&gt;PagesController&lt;/span&gt; &amp;lt; &lt;span class="co"&gt;ResourceController&lt;/span&gt;::&lt;span class="co"&gt;Base&lt;/span&gt;&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;        &lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;  before_filter &lt;span class="sy"&gt;:set_scope&lt;/span&gt;&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;  belongs_to &lt;span class="sy"&gt;:user&lt;/span&gt;&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;  private&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;  &lt;span class="r"&gt;def&lt;/span&gt; &lt;span class="fu"&gt;parent_object&lt;/span&gt;&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;    &lt;span class="iv"&gt;@parent&lt;/span&gt; ||= &lt;span class="co"&gt;User&lt;/span&gt;.find_by_name(params[&lt;span class="sy"&gt;:user_id&lt;/span&gt;]) &lt;span class="r"&gt;if&lt;/span&gt; params[&lt;span class="sy"&gt;:user_id&lt;/span&gt;]&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;  &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;  &lt;span class="r"&gt;def&lt;/span&gt; &lt;span class="fu"&gt;set_scope&lt;/span&gt;&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;    &lt;span class="iv"&gt;@scope&lt;/span&gt; = &lt;span class="iv"&gt;@portal&lt;/span&gt;.pages&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;    &lt;span class="iv"&gt;@scope&lt;/span&gt; = &lt;span class="iv"&gt;@scope&lt;/span&gt;.by_user(parent_object.id) &lt;span class="r"&gt;if&lt;/span&gt; parent_object&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;    &lt;span class="iv"&gt;@scope&lt;/span&gt; = &lt;span class="iv"&gt;@scope&lt;/span&gt;.pending(params[&lt;span class="sy"&gt;:pending&lt;/span&gt;])&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;  &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;  &lt;span class="r"&gt;def&lt;/span&gt; &lt;span class="fu"&gt;collection&lt;/span&gt;&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;    &lt;span class="iv"&gt;@pages&lt;/span&gt; ||= &lt;span class="iv"&gt;@scope&lt;/span&gt;.paginate(&lt;span class="sy"&gt;:all&lt;/span&gt;, &lt;span class="sy"&gt;:page&lt;/span&gt; =&amp;gt; params[&lt;span class="sy"&gt;:page&lt;/span&gt;])&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;  &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;  &lt;span class="r"&gt;def&lt;/span&gt; &lt;span class="fu"&gt;route_name&lt;/span&gt;&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;    params[&lt;span class="sy"&gt;:pending&lt;/span&gt;] ? &lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;pending_post&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt; : &lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;post&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;  &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;&lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;&lt;br /&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;Here I added one line to set_scope to add the pending  scope if the params[:pending] was true. But for a change I didn't check for params[:pending], instead I pass it to the named_scope which will check internally if it set or not and do the scope accordingly. Actually I did this in my real application to not be forced to make another not_pending named_scope. Because in real life you will need not to publish unpublished pages. errr.. ok, i mean the pending scope is unlike users scope, which is like, "if parent user is not set just show all the pages anyway", this will not work here, we need it to be, "if pending status is false just list only the published pages". And now it's a good chance to demonstrate how to pass arguments to named_scope.&lt;br /&gt;&lt;table class="CodeRay"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;br /&gt;&lt;td class="line_numbers" title="click to toggle" onclick="with (this.firstChild.style) { display = (display == '') ? 'none' : '' }"&gt;&lt;pre&gt;1&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;2&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;3&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;4&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;&lt;br /&gt;&lt;td class="code"&gt;&lt;pre ondblclick="with (this.style) { overflow = (overflow == 'auto' || overflow == '') ? 'visible' : 'auto' }"&gt;&lt;span class="r"&gt;class&lt;/span&gt; &lt;span class="cl"&gt;Page&lt;/span&gt; &amp;lt; &lt;span class="co"&gt;ActiveRecord&lt;/span&gt;::&lt;span class="co"&gt;Base&lt;/span&gt;&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;  named_scope &lt;span class="sy"&gt;:by_user&lt;/span&gt;, lambda{|u| {&lt;span class="sy"&gt;:conditions&lt;/span&gt; =&amp;gt; {&lt;span class="sy"&gt;:user_id&lt;/span&gt; =&amp;gt; u} } }&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;  named_scope &lt;span class="sy"&gt;:pending&lt;/span&gt;, lambda{|s| {&lt;span class="sy"&gt;:conditions&lt;/span&gt; =&amp;gt; {&lt;span class="sy"&gt;:published&lt;/span&gt; =&amp;gt; s} } }&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;&lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;&lt;br /&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;where is the next and previous links?&lt;br /&gt;&lt;/span&gt;It is a very healthy practice to provide a next and previous item links in your show item page. For many obvious reasons, for one is to spare the user going back to pages list which will stress your server as well.  Just give her the links or previous and next page. But you have to prepare the links first in the show action. In Resource controller actions are abstracted so you don't have to do the repetitive code each time, just do what is specific to each controller action. In this case I need the show action to fetch the next and previous page according to the scope within which the pages controller works. And do that just before rendering the template or to be precise just before responding.&lt;br /&gt;&lt;br /&gt;&lt;table class="CodeRay"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;br /&gt;&lt;td class="line_numbers" title="click to toggle" onclick="with (this.firstChild.style) { display = (display == '') ? 'none' : '' }"&gt;&lt;pre&gt;1&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;2&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;3&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;4&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;5&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;6&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;7&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;8&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;9&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;11&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;12&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;13&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;14&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;15&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;16&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;17&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;&lt;br /&gt;&lt;td class="code"&gt;&lt;pre ondblclick="with (this.style) { overflow = (overflow == 'auto' || overflow == '') ? 'visible' : 'auto' }"&gt;&lt;span class="r"&gt;class&lt;/span&gt; &lt;span class="cl"&gt;PagesController&lt;/span&gt; &amp;lt; &lt;span class="co"&gt;ResourceController&lt;/span&gt;::&lt;span class="co"&gt;Base&lt;/span&gt;&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;        &lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;  before_filter &lt;span class="sy"&gt;:set_scope&lt;/span&gt;&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;  belongs_to &lt;span class="sy"&gt;:user&lt;/span&gt;&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;  show &lt;span class="r"&gt;do&lt;/span&gt;&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;    before &lt;span class="r"&gt;do&lt;/span&gt;&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;      &lt;span class="iv"&gt;@next_item&lt;/span&gt; = &lt;span class="iv"&gt;@scope&lt;/span&gt;.next_to(object).first&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;      &lt;span class="iv"&gt;@previous_item&lt;/span&gt; = &lt;span class="iv"&gt;@scope&lt;/span&gt;.previous_to(object).first&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;    &lt;span class="r"&gt;end&lt;/span&gt; &lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;  &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;  private&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;  &lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;  ...&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;&lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;&lt;br /&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;This was easy, just assign your next and previous variables to the first item returned by the named scopes "next_to" and "previous_to". To be precise, named_scope are not results set (Array) so we need to do ".find(:first)" or ".first" as of Rails 2.1, to just hit the database and fetch the records. I passed 'object' to the named scopes which is a method refers to @page, you can override this method just to find your page the way you want it, say you want to find_by_premalink, for example. The following are how those named scopes were implemented.&lt;br /&gt;&lt;br /&gt;&lt;table class="CodeRay"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;br /&gt;&lt;td class="line_numbers" title="click to toggle" onclick="with (this.firstChild.style) { display = (display == '') ? 'none' : '' }"&gt;&lt;pre&gt;1&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;2&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;3&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;4&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;5&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;6&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;7&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;8&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;9&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;11&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;12&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;13&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;14&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;15&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;16&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;17&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;18&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;19&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;&lt;br /&gt;&lt;td class="code"&gt;&lt;pre ondblclick="with (this.style) { overflow = (overflow == 'auto' || overflow == '') ? 'visible' : 'auto' }"&gt;&lt;span class="r"&gt;class&lt;/span&gt; &lt;span class="cl"&gt;Page&lt;/span&gt; &amp;lt; &lt;span class="co"&gt;ActiveRecord&lt;/span&gt;::&lt;span class="co"&gt;Base&lt;/span&gt;&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;  named_scope &lt;span class="sy"&gt;:by_user&lt;/span&gt;, lambda {|u| {&lt;span class="sy"&gt;:conditions&lt;/span&gt; =&amp;gt; {&lt;span class="sy"&gt;:user_id&lt;/span&gt; =&amp;gt; u} } }&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;  named_scope &lt;span class="sy"&gt;:pending&lt;/span&gt;, lambda {|s| {&lt;span class="sy"&gt;:conditions&lt;/span&gt; =&amp;gt; {&lt;span class="sy"&gt;:published&lt;/span&gt; =&amp;gt; s} } }&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;  named_scope &lt;span class="sy"&gt;:next_to&lt;/span&gt;, lambda {|item|&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;    {&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;      &lt;span class="sy"&gt;:limit&lt;/span&gt; =&amp;gt; &lt;span class="i"&gt;1&lt;/span&gt;, &lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;      &lt;span class="sy"&gt;:conditions&lt;/span&gt; =&amp;gt; [ &lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;id &amp;gt; ?&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;,item.id] ,&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;      &lt;span class="sy"&gt;:order&lt;/span&gt; =&amp;gt; &lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;id asc&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;    }&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;  }&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;  &lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;  named_scope &lt;span class="sy"&gt;:previous_to&lt;/span&gt;, lambda {|item|&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;    {&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;      &lt;span class="sy"&gt;:limit&lt;/span&gt; =&amp;gt; &lt;span class="i"&gt;1&lt;/span&gt;, &lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;      &lt;span class="sy"&gt;:conditions&lt;/span&gt; =&amp;gt; [&lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;id &amp;lt; ?&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;, item.id] ,&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;      &lt;span class="sy"&gt;:order&lt;/span&gt; =&amp;gt; &lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;id desc&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;    }&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;  }&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;&lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;&lt;br /&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;Well, that's all well a good, but pretty DRY controllers are not the end of all our sufferings, are they? the views are always the primary cause of migraine in web development, at least they are for me. This resource controller is doing all what I asked it for. But how the views will handle such complex set of nested and or conditional scoping? When I first asked myself this question and start to figure out what may the solutions be. I found my self saying, Hell, no no, I will not make all those conditions and the ever nested loops of if/else to just decide which url routes I shall use in the new and edit forms. But Alhamdulillah, thanks God, there is this most useful piece of code that ever existed in Rails view helpers, excuse the drama but it is really that good, it is the "&lt;a href="http://jamesgolick.com/2007/10/11/rails-polymorphic-url-generation-sucks-here-s-something-better"&gt;Urligence&lt;/a&gt;" library which is a url helper that helps you generating urls! It is included in Resource Controller, so no need to download. This url helper is not only useful in views it is already used in the controller in redirect_to statements taken place deep inside resource controller, like after create for example it is by default redirect to show action. In this case which show route will it use? In our case we have at least three show routes:&lt;br /&gt;&lt;blockquote&gt;/pages/:id&lt;br /&gt;/user/:user_id/pages/:id&lt;br /&gt;/user/:user_id/pending_pages/:id&lt;br /&gt;&lt;/blockquote&gt;The surprise is that Resource Controller will know exactly which route to use according to the context. Actually it does it using Urligence url helper. The helper themselves are too easy. You will have object_url and collection_url, that's it. In Rails resources native tongue: object_url to refer to any member action, and collection_url to refer to any collection action. And of course the HTTP verb or the request method will decide which action to address, like, post to collection_url to create and put to object_url to upate and such.&lt;br /&gt;&lt;br /&gt;&lt;table class="CodeRay"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;br /&gt;&lt;td class="line_numbers" title="click to toggle" onclick="with (this.firstChild.style) { display = (display == '') ? 'none' : '' }"&gt;&lt;pre&gt;1&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;2&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;3&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;4&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;5&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;6&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;7&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;&lt;br /&gt;&lt;td class="code"&gt;&lt;pre ondblclick="with (this.style) { overflow = (overflow == 'auto' || overflow == '') ? 'visible' : 'auto' }"&gt;&lt;span class="il"&gt;&lt;span class="dl"&gt;&amp;lt;%&lt;/span&gt; form_for &lt;span class="sy"&gt;:page&lt;/span&gt;, &lt;span class="iv"&gt;@object&lt;/span&gt;, &lt;span class="sy"&gt;:url&lt;/span&gt; =&amp;gt; object_url, &lt;span class="sy"&gt;:html&lt;/span&gt; =&amp;gt; {&lt;span class="sy"&gt;:method&lt;/span&gt; =&amp;gt; &lt;span class="sy"&gt;:put&lt;/span&gt;} &lt;span class="r"&gt;do&lt;/span&gt; |f| &lt;span class="dl"&gt;%&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;   &lt;span class="il"&gt;&lt;span class="dl"&gt;&amp;lt;%=&lt;/span&gt; f.text_field &lt;span class="sy"&gt;:title&lt;/span&gt; &lt;span class="dl"&gt;%&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;   &lt;span class="il"&gt;&lt;span class="dl"&gt;&amp;lt;%=&lt;/span&gt; submit_tag &lt;span class="s"&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="k"&gt;Save&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;/span&gt; &lt;span class="dl"&gt;%&amp;gt;&lt;/span&gt;&lt;/span&gt; or &lt;span class="il"&gt;&lt;span class="dl"&gt;&amp;lt;%=&lt;/span&gt; link_to &lt;span class="s"&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="k"&gt;Cancel&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;/span&gt;, object_url &lt;span class="dl"&gt;%&amp;gt;&lt;/span&gt;&lt;/span&gt; and go back to page.&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;&lt;span class="il"&gt;&lt;span class="dl"&gt;&amp;lt;%&lt;/span&gt; &lt;span class="r"&gt;end&lt;/span&gt; &lt;span class="dl"&gt;%&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;&lt;span class="il"&gt;&lt;span class="dl"&gt;&amp;lt;%=&lt;/span&gt; link_to(&lt;span class="s"&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="k"&gt;Next&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;/span&gt;, object_url(&lt;span class="iv"&gt;@next_item&lt;/span&gt;)) &lt;span class="r"&gt;if&lt;/span&gt; &lt;span class="iv"&gt;@next_item&lt;/span&gt; &lt;span class="dl"&gt;%&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;&lt;span class="il"&gt;&lt;span class="dl"&gt;&amp;lt;%=&lt;/span&gt; link_to(&lt;span class="s"&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="k"&gt;Previous&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;/span&gt;, object_url(&lt;span class="iv"&gt;@previous_item&lt;/span&gt;)) &lt;span class="r"&gt;if&lt;/span&gt; &lt;span class="iv"&gt;@previous_item&lt;/span&gt; &lt;span class="dl"&gt;%&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;&lt;/td&gt;&lt;br /&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;These snippets from the edit and show templates are pretty much clear and amazing at the same time.&lt;br /&gt;&lt;br /&gt;What about controlling the flow of the application. What if you need to change the default flow of the resource controller and make the "delete" action redirect to the next item show page if it exists and to the pages index if there is no next page.&lt;br /&gt;&lt;br /&gt;&lt;table class="CodeRay"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;br /&gt;&lt;td class="line_numbers" title="click to toggle" onclick="with (this.firstChild.style) { display = (display == '') ? 'none' : '' }"&gt;&lt;pre&gt;1&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;2&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;3&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;4&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;5&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;6&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;7&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;8&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;9&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;11&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;12&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;&lt;br /&gt;&lt;td class="code"&gt;&lt;pre ondblclick="with (this.style) { overflow = (overflow == 'auto' || overflow == '') ? 'visible' : 'auto' }"&gt;delete &lt;span class="r"&gt;do&lt;/span&gt;&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;  before &lt;span class="r"&gt;do&lt;/span&gt;&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;    &lt;span class="iv"&gt;@next_page&lt;/span&gt; = &lt;span class="iv"&gt;@scope&lt;/span&gt;.next_to(object).first&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;  &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;  after &lt;span class="r"&gt;do&lt;/span&gt;&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;    &lt;span class="r"&gt;if&lt;/span&gt; &lt;span class="iv"&gt;@next_page&lt;/span&gt;&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;      redirect_to object_url(&lt;span class="iv"&gt;@next_page&lt;/span&gt;)&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;    &lt;span class="r"&gt;else&lt;/span&gt;&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;      redirect_to collection_url&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;    &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;  &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;&lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;&lt;br /&gt;&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;&lt;br /&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;All we need to do is to explicitly add the delete action. I tried to fetch the next item in the current @scope "before" deleting. And "after" deletion I should redirect properly as required.&lt;br /&gt;&lt;br /&gt;There are lot more in ResourceController, it lets you customize flash message for success and failure, add responds to methods, respect namespaces automagically and more.&lt;br /&gt;&lt;br /&gt;Anyway, that's  it regarding how ResourceController and Named Scopes has changed the &lt;span style="font-size:100%;"&gt;way I write Rails ActionControllers. for more information refer to the following links:&lt;/span&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://www.infoq.com/news/2008/01/rails-resource-controller"&gt;Rails: Resource_controller Plugin Puts Controllers on a Diet&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.vimeo.com/637894"&gt;Easy Restful Rails&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.github.com/giraffesoft/resource_controller/tree/master"&gt;ResourceController on GitHub&lt;/a&gt;&lt;br /&gt;&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/974036606587739553-7072140911154024020?l=www.ibrahim-ahmed.com'/&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/IbrahimAhmed/~4/m13V8ysktfw" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.ibrahim-ahmed.com/feeds/7072140911154024020/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=974036606587739553&amp;postID=7072140911154024020" title="2 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/974036606587739553/posts/default/7072140911154024020?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/974036606587739553/posts/default/7072140911154024020?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/IbrahimAhmed/~3/m13V8ysktfw/rails-actioncontroller-facelift-using.html" title="Rails ActionController facelift using ResourceController and named_scope" /><author><name>Ibrahim Ahmed</name><uri>http://www.blogger.com/profile/01640528992428968621</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="05643959196373262770" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">2</thr:total><feedburner:origLink>http://www.ibrahim-ahmed.com/2008/12/rails-actioncontroller-facelift-using.html</feedburner:origLink></entry><entry><title type="text">Links for 2008-11-30 [del.icio.us]</title><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/IbrahimAhmed/~3/_YzZwfiEhhA/ibrahimahmed" /><updated>2008-12-01T00:00:00-08:00</updated><id>http://del.icio.us/ibrahimahmed#2008-11-30</id><content type="html">&lt;ul&gt;
&lt;li&gt;&lt;a href="http://code.google.com/p/ratproxy/"&gt;ratproxy - Google Code&lt;/a&gt;&lt;br/&gt;
A semi-automated, largely passive web application security audit tool, optimized for an accurate and sensitive detection, and automatic annotation, of potential problems and security-relevant design patterns based on the observation of existing, user-initiated traffic in complex web 2.0 environments.

D&lt;/li&gt;
&lt;/ul&gt;&lt;img src="http://feeds.feedburner.com/~r/IbrahimAhmed/~4/_YzZwfiEhhA" height="1" width="1"/&gt;</content><feedburner:origLink>http://del.icio.us/ibrahimahmed#2008-11-30</feedburner:origLink></entry><entry><title type="text">Links for 2008-11-28 [del.icio.us]</title><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/IbrahimAhmed/~3/2y5J2lUJCH0/ibrahimahmed" /><updated>2008-11-29T00:00:00-08:00</updated><id>http://del.icio.us/ibrahimahmed#2008-11-28</id><content type="html">&lt;ul&gt;
&lt;li&gt;&lt;a href="http://github.com/guides/developing-with-submodules"&gt;Developing with Submodules &amp;mdash; GitHub Guides &amp;mdash; GitHub&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://snippets.aktagon.com/snippets/277-Configuring-Apache-to-be-a-forward-proxy"&gt;Configuring Apache to be a forward proxy - Apache - apache, forward, proxy&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://gusg.us/code/ruby/rails-2_2-headaches-1"&gt;GusG.us Moving to Rails 2.2 Headaches - Vol 1&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://gusg.us/code/ruby/should-making-dry-even-dryier"&gt;GusG.us Shoulda: Making DRY even DRY-ier&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://blog.danielwellman.com/2008/06/writing-rails-integration-tests-with-webrat.html"&gt;Stay on Target: Writing Rails integration tests with Webrat&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;img src="http://feeds.feedburner.com/~r/IbrahimAhmed/~4/2y5J2lUJCH0" height="1" width="1"/&gt;</content><feedburner:origLink>http://del.icio.us/ibrahimahmed#2008-11-28</feedburner:origLink></entry><entry gd:etag="W/&quot;DEEHQHw6eip7ImA9WxdXEUs.&quot;"><id>tag:blogger.com,1999:blog-974036606587739553.post-2395243680484701098</id><published>2008-06-22T11:45:00.000-07:00</published><updated>2008-06-22T13:30:31.212-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-06-22T13:30:31.212-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="git" /><title>Working with remote Git branches</title><content type="html">&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_kaErP_wP6ns/SF6pxmNDUoI/AAAAAAAAAIE/CTcEGNgqYFY/s1600-h/bonsai.jpg"&gt;&lt;img style="margin: 0pt 0pt 10px 10px; float: right; cursor: pointer;" src="http://2.bp.blogspot.com/_kaErP_wP6ns/SF6pxmNDUoI/AAAAAAAAAIE/CTcEGNgqYFY/s200/bonsai.jpg" alt="" id="BLOGGER_PHOTO_ID_5214792088075588226" border="0" /&gt;&lt;/a&gt;You are about to start a brand new module in your project. Your project is already in production. You cannot develop and test  your new module while fixing minor bugs in your production line. You need branching.&lt;br /&gt;&lt;br /&gt;So suppose we are on master branch and you have remote "origin" repository. And we need to create a new remote branch called "search" to track the development of the search module. the plan is to develop the search module on this branch  "search" locally and push updates remotely for testing on a staging server or just to share the search module code with a colleague developer without polluting the master production branch with the unfinished yet search module.&lt;br /&gt;&lt;br /&gt;First make sure your master branch are up to date.&lt;br /&gt;&lt;blockquote&gt;$ git pull origin master&lt;br /&gt;&lt;/blockquote&gt;Then push your master branch to a new remote branch, notice that you enter the destination remote repository name first "origin" then the source which is local branch "master" then a column  ":" and the path of the new remote branch we want to create "refs/heads/search"&lt;br /&gt;&lt;blockquote&gt;$ git push origin master:refs/heads/search&lt;/blockquote&gt;After pushing and creating the remote "search" branch, we will examine the remote "origin.&lt;br /&gt;&lt;blockquote&gt;$ git remote show origin&lt;br /&gt;* remote origin&lt;br /&gt;URL: ssh://ibrahim@kenana.org/git/portals.git&lt;br /&gt;Remote branch(es) merged with 'git pull' while on branch master&lt;br /&gt; master&lt;br /&gt;New remote branches (next fetch will store in remotes/origin)&lt;br /&gt; search&lt;br /&gt;Tracked remote branches&lt;br /&gt; master&lt;br /&gt;&lt;/blockquote&gt;Notice how there is a new remote branch and that next time we use "git fetch" the new remote branch "search" will be stored in remotes/origin.&lt;br /&gt;&lt;blockquote&gt;$ git fetch&lt;br /&gt;* refs/remotes/origin/search: storing branch 'search' of ssh://ibrahim-ahmed.com/git/portals&lt;br /&gt;commit: 8bd83c4&lt;br /&gt;&lt;/blockquote&gt;Now we have all the remote origin branches stored locally in "refs/remotes/origin" including "search" branch, but there is no local branch  yet to track it.&lt;br /&gt;&lt;br /&gt;To make a branch out of the remote branch which is stored locally, we will use "git checkout", the "-b" search" is the argument we use to create a local branch. "--track" parameter is used to link the local branch "search" with the remote branch "origin/search"&lt;br /&gt;&lt;blockquote&gt;$ git checkout --track  -b search  origin/search&lt;br /&gt;&lt;/blockquote&gt;Now you should be on "search" branch.&lt;br /&gt;&lt;blockquote&gt;$ git branch&lt;br /&gt;master&lt;br /&gt;* search&lt;br /&gt;&lt;/blockquote&gt;Now you can edit, commit, pull and pull to your heart content. And when you need to fix something on remote/master which is used for production server, you just use the following to fix the bug, push to the remote master and then back again to your search module.&lt;br /&gt;&lt;blockquote&gt;$ git checkout master&lt;br /&gt;$ vim files_to_be_fixed&lt;br /&gt;$ git commit -a -m "just fixed the bug"&lt;br /&gt;$ git push origin master&lt;br /&gt;$ git checkout search&lt;br /&gt;&lt;/blockquote&gt;Check &lt;a href="http://wiki.sourcemage.org/Git_Guide"&gt;SourceMage Git manual&lt;/a&gt; for further advanced usage examples.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/974036606587739553-2395243680484701098?l=www.ibrahim-ahmed.com'/&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/IbrahimAhmed/~4/FZlDnHcbun8" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.ibrahim-ahmed.com/feeds/2395243680484701098/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=974036606587739553&amp;postID=2395243680484701098" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/974036606587739553/posts/default/2395243680484701098?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/974036606587739553/posts/default/2395243680484701098?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/IbrahimAhmed/~3/FZlDnHcbun8/working-with-remote-git-branches.html" title="Working with remote Git branches" /><author><name>Ibrahim Ahmed</name><uri>http://www.blogger.com/profile/01640528992428968621</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="05643959196373262770" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://2.bp.blogspot.com/_kaErP_wP6ns/SF6pxmNDUoI/AAAAAAAAAIE/CTcEGNgqYFY/s72-c/bonsai.jpg" height="72" width="72" /><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://www.ibrahim-ahmed.com/2008/06/working-with-remote-git-branches.html</feedburner:origLink></entry><entry gd:etag="W/&quot;C08MRngzfyp7ImA9WxZUFU8.&quot;"><id>tag:blogger.com,1999:blog-974036606587739553.post-8739913489185160597</id><published>2008-04-06T15:16:00.000-07:00</published><updated>2008-04-06T15:44:47.687-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-04-06T15:44:47.687-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="CSS" /><title>Design an accessible Website using CSS</title><content type="html">Designing the web page layout is an essential step in the website development. It affects almost every aspect of the website development, from styles, content types, photos, search engine optimization SEO, and definitely the website user friendliness.&lt;br /&gt;&lt;br /&gt;There were a deep misunderstanding to the Web as a capable media for content publishing and a potent marketing tool, the graphics designer were using the Internet shamelessly as a mere brochure. I mean they were designing a brochure (a real one) and convert it to a web page using one of the web graphics application like Fireworks, or Dreamweaver. The conversion was usually done using image maps and slicing. Graphics slicing were obscenely abused, I saw many crimes where developer create or import a brochure into Photoshop and start slicing the image into small chunks of gif images, and export the whole design as an HTML. At best they export part of the design from Photoshop and integrate the dynamic parts into the body area of the layout.&lt;br /&gt;&lt;br /&gt;Leaving Photoshop and brothers to do the HTML is not a good idea. Really. It is like translating an English site to Arabic language using a machine translator. The end product is gibberish. The sliced layout with mixed Html and images, is harmful for many reasons I will try to highlight them in this post.&lt;br /&gt;&lt;br /&gt;HTML is not a presentation layer. Using HTML to design the layout is not the job of HTML. HTML is an XML format to define the data structue of the web page document. I like to describe a document in terms of paragraphs, menu list, sidebar, blockquotes, ordered list, unordered list, those elements are unsurprisingly the elements of HTML. But how you want to render or represent the menu lists, the sidebar, the blockquote, representing those elements is entirely the job of &lt;a href="http://www.w3schools.com/Css/default.asp"&gt;CSS&lt;/a&gt; (&lt;a href="http://en.wikipedia.org/wiki/Cascading_Style_Sheets"&gt;Cascading Style Sheet&lt;/a&gt;) and not the HTML.&lt;br /&gt;&lt;br /&gt;What made me a true believer of CSS layout, CSS styling and using HTML only in representing the document in its basic elements is that our eyes are not the only consumer of the web page we develop, there are others, like; search engines crawlers, blinds, mobile web browsers, printers..etc all those consumers will not see or use our graphics as we intended for it to be seen&lt;br /&gt;&lt;br /&gt;Search engines will not understand that my website is concerned about farming and agriculture if I did export the titles of the agriculture sections as images from Photoshop. So People searching Google will not find your site only because Google didn't find thesearch  keywords in your site. The same goes for blinds. There are  using the Internet in a daily basis in &lt;a href="http://www.freewebs.com/waelsyntax/myFile.htm"&gt;Egypt&lt;/a&gt;, &lt;a href="http://www.hanady.org/Artical/artical_en.htm"&gt;Arab countries&lt;/a&gt; and around the world. For blinds they use Text to speech software to convert "text" to speech, it will simply ignore images, so blinds will miss your website sections menu if it was made of a bunch of images racked into an HTML Table.&lt;br /&gt;&lt;br /&gt;Another reason for using CSS is that blinds are needlessly forced to listen to a lot of repeatable content on the top of each of our pages, for no reason but that HTML is rendering first things first, so if we want to put the site menu, contact us, about us, login, and sidebars on top of the page, you could render it on top if you want to, but there is no need to fill the blind with boredom in order for him / her to reach the body of your page content, and force him / her to read through all those content again and again in each of your website pages. We can always use CSS to render different page elements in any position regalrdless of its order as an element in the HTML document.&lt;br /&gt;&lt;br /&gt;To summarize the characteristics of a good Website design I can say;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;No style graphics are embeded in HTML, all design and decoration images located in a separated CSS file. No menu list, titles, or any content is represented only by graphics, it should be a text first and then styled and decorated with any graphics the designer decide.&lt;/li&gt;&lt;li&gt;No Tables are used to define layout columns, Tables are only for tabled data, and not for layout.&lt;/li&gt;&lt;li&gt;Web page content comes first in the order of HTML document. The title and body of the article of the web page is the first thing you see if you open the source code of the page or see the page without CSS styles, that's good, cause that's how other blinds, search engines, mobile browser will see your page.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;I am yet to see CSS developers in Egypt, job posts for CSS developer in Egypt are none. Employers do not know what they are missing, they bet on graphic designers to do the job, and usually graphic designer have no idea what CSS is all about, they will use CSS for styling at best, and not for layout. That's why I will do a small contribution and start a mini series of CSS lessons (hopefully in Arabic too), in order to implement the mentioned principles in designing a good website design.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/974036606587739553-8739913489185160597?l=www.ibrahim-ahmed.com'/&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/IbrahimAhmed/~4/oCYQQs-ORbw" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.ibrahim-ahmed.com/feeds/8739913489185160597/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=974036606587739553&amp;postID=8739913489185160597" title="1 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/974036606587739553/posts/default/8739913489185160597?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/974036606587739553/posts/default/8739913489185160597?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/IbrahimAhmed/~3/oCYQQs-ORbw/design-good-website-using-css.html" title="Design an accessible Website using CSS" /><author><name>Ibrahim Ahmed</name><uri>http://www.blogger.com/profile/01640528992428968621</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="05643959196373262770" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">1</thr:total><feedburner:origLink>http://www.ibrahim-ahmed.com/2008/04/design-good-website-using-css.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CkAGSHc_cSp7ImA9WxZUFEU.&quot;"><id>tag:blogger.com,1999:blog-974036606587739553.post-1366540491422631260</id><published>2008-04-06T03:42:00.000-07:00</published><updated>2008-04-06T04:18:49.949-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-04-06T04:18:49.949-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Tools" /><category scheme="http://www.blogger.com/atom/ns#" term="Deployment" /><title>Git the Version Control System - part one</title><content type="html">&lt;a href="http://git.or.cz/"&gt;Git&lt;/a&gt; is a &lt;a href="http://en.wikipedia.org/wiki/Revision_control"&gt;Version Control System&lt;/a&gt;, it is used to keep a history of all the changes you made into your code, manage releases, makes it easier for more than one programmer to share his/her code with the rest of the group.&lt;br /&gt;&lt;br /&gt;There are tens of good VCS out there, the most famous was &lt;a href="http://www.nongnu.org/cvs/"&gt;CVS&lt;/a&gt; Concurrent Version System, then came &lt;a href="http://subversion.tigris.org/"&gt;Subversion&lt;/a&gt; from the same team of CVS with the same concepts but cleaner than its ancestor. Both CVS and Subversion was free. There are other sophisticated VCS out there some of them are free and the other are proprietary. Linux was developed using a free license version of &lt;a href="http://www.selenic.com/mercurial/wiki/"&gt;Mercurial&lt;/a&gt; which is pretty good CVS but for more some reason Linus Torvalds was challenged enough to start writing his own VCS, and Git was born.&lt;br /&gt;&lt;br /&gt;There are two types of VCS, Central and Distributed. In central VCS like CVS and Subversion, there is always one central repository, you checkout a copy of whatever version you like from the repository, start working on it and then submit your changes into the central repository again.&lt;br /&gt;&lt;br /&gt;The Distributed type like Git, there is one or more central repository, and you clone the repository into your local machine, and then you will have a standalone repository. Which is more like forking the development of the code at certain point in its development line into another repository. You then maintain your repository and change to your heart content, and it is up to you or the original (upstream) repository maintainer to merge your changes.&lt;br /&gt;&lt;br /&gt;I will write a note on the basic operation of managing my code in GIT. For the sake of simplicity I will not write in this post about how to serve or access remote GIT repository using SSH, I will just assume that all repositories are on local machine.&lt;br /&gt;&lt;blockquote&gt;$ mkdir myapp&lt;br /&gt;$ cd myapp&lt;br /&gt;$ git init&lt;br /&gt;Initialized empty Git repository in .git/&lt;br /&gt;&lt;/blockquote&gt;I created a folder for my application, and inside the folder I make Git initialize a new repository.&lt;br /&gt;&lt;br /&gt;At this point we should have a folder  named .git inside the 'myapp' and that .git folder by itself is a repository, in this folder GIT will store all the transaction, changes, version, releases of your code. The beauty of GIT is that it does not pollute your code folder with other files like Subversion does. Subversion was creating an .svn folder inside each folder in my app folder.&lt;br /&gt;&lt;br /&gt;As I said .git is the repository and the rest of your folder is now then called the working copy. the working copy is an important concept. It is your current version files, in Git if you switch to another version of your code, all the files in the folder will be changed to reflect the real version you switched to. We can create a repository without a working copy and that's what we do in case we need to make a central repository where programmer are pulling and pushing changes into it, in that case we do not need a working copy with the repository, this is called a 'bare' repository.&lt;br /&gt;&lt;br /&gt;The .git repository folder is now empty, it has no files (or changes) in it. To start populating the repository we use the 'add' Git command. but we actually do not have any files yet, so let's make some files.&lt;br /&gt;&lt;blockquote&gt;$ echo "hello" &gt; dialog.txt&lt;br /&gt;&lt;/blockquote&gt;I created a file 'dialog.txt'. Now i will ask Git about the status, and it will answer me with the following information, which match files in three cases:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;The modified files in my working copy that needs to be committed.&lt;/li&gt;&lt;li&gt;The modified files that are marked for committing.&lt;/li&gt;&lt;li&gt;The files that are not yet tracked by Git, and they need to be added first to the repository.&lt;/li&gt;&lt;/ul&gt;Now that we only have one file in the third case.&lt;br /&gt;&lt;blockquote&gt;$ git status&lt;br /&gt;# On branch master&lt;br /&gt;#&lt;br /&gt;# Initial commit&lt;br /&gt;#&lt;br /&gt;# Untracked files:&lt;br /&gt;#   (use "git add &lt;file&gt;..." to include in what will be committed)&lt;br /&gt;#&lt;br /&gt;#       dialog.txt&lt;br /&gt;&lt;/file&gt;&lt;/blockquote&gt;Git suggest to use the add command to start tracking the file. What tracking means? Ok, in a working copy there is either tracked files that you want to keep track of, and untracked files which are either newly created and needs to be added to the repository or non source code files like log files, object and comoiled files and in this case we need to tell Git to ignore them and not notifying me about them when we use the 'status' command.&lt;br /&gt;&lt;br /&gt;To be more specific the 'add' command does not add the files to the repository here or even convert the untracked files into tracked ones, the 'add' command is actually preparing the files to be committed or added to the repository in the next time you use the commit command. Actually 'add' is adding the files, tracked or not, to an area which is called the 'index', and after you add all the files you need and you feel satisfied that your all the changes you need to commit is in the stage, then you can use the commit command to commit your changes into the repository.&lt;br /&gt;&lt;blockquote&gt;$ git add dialog.txt&lt;br /&gt;&lt;/blockquote&gt;Now that we added the dialog.txt it is now in the 'index' and will be commited by the next commit command.&lt;br /&gt;&lt;blockquote&gt;$ git status&lt;br /&gt;# On branch master&lt;br /&gt;#&lt;br /&gt;# Initial commit&lt;br /&gt;#&lt;br /&gt;# Changes to be committed:&lt;br /&gt;#   (use "git rm --cached &lt;file&gt;..." to unstage)&lt;br /&gt;#&lt;br /&gt;#       new file: dialog.txt&lt;br /&gt;#&lt;br /&gt;&lt;/file&gt;&lt;/blockquote&gt;Well, it is time of our first commit. Git is storing the name and email of the committer with each commit, so we need to identify ourselves first to Git.&lt;br /&gt;&lt;blockquote&gt;git config --global user.email "ibrahim@mymail.com"&lt;br /&gt;git config --global user.name "Ibrahim Ahmed"&lt;br /&gt;$ git commit -m "saying hello"&lt;br /&gt;&lt;/blockquote&gt;I committed the dialog.txt and notice the '-m', commit always needs a log message, try to write a message describing the changes you've done to the file.&lt;br /&gt;&lt;blockquote&gt;$ echo "what's your name" &gt;&gt; dialog.txt&lt;br /&gt;$ git status&lt;br /&gt;&lt;/blockquote&gt;I added one more line to dialog.txt, and git status to see the changes, and Git should giving me that dialog.txt is modified and  will be committed in the next comit.&lt;br /&gt;&lt;br /&gt;One more time, and excuse my boring repetition, you will need to add first the dialog.txt to the index area, before it is ready to be commit.&lt;br /&gt;&lt;blockquote&gt;$ git add dialog.txt&lt;br /&gt;$ git commit -m "asking about your name"&lt;br /&gt;&lt;/blockquote&gt;&lt;span style="font-size:130%;"&gt;Ignoring files&lt;/span&gt;&lt;br /&gt;Git status will always nag about untracked files, so we should either 'add' it or ignore it.&lt;br /&gt;&lt;br /&gt;There are always some files in your app that you do not need to track, files like logs for example.&lt;br /&gt;&lt;blockquote&gt;$ touch myapp.log&lt;br /&gt;$ git status&lt;br /&gt;# On branch master&lt;br /&gt;#&lt;br /&gt;# Untracked files:&lt;br /&gt;#   (use "git add &lt;file&gt;..." to include in what will be committed)&lt;br /&gt;#&lt;br /&gt;#       myapp.log&lt;br /&gt;$ echo "*.log" &gt;&gt; .git/info/exclude&lt;br /&gt;$ git status&lt;br /&gt;# On branch master&lt;br /&gt;nothing to commit (working directory clean)&lt;br /&gt;&lt;/file&gt;&lt;/blockquote&gt;Notice how git status listed myapp.log in untracked files, and when we add a line containing '*.log' to '.git/info/exclude', git status ignored the myapp.log file and gives the message 'working directory clean'&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;Remove files&lt;/span&gt;&lt;br /&gt;'git rm' removes files from the working directory and from the repository. But it also used to remove files from the 'index' using the following;&lt;br /&gt;&lt;blockquote&gt;$ touch delete.me&lt;br /&gt;$ git add delete.me&lt;br /&gt;$ git commit -m "adding delete.me"&lt;br /&gt;$ git rm delete.me&lt;br /&gt;$ echo "how old are you?" &gt;&gt; dialog.txt&lt;br /&gt;$ git add dialog.txt&lt;br /&gt;$ git rm --cached dialog.txt&lt;/blockquote&gt;&lt;br /&gt;That's it for the first part of my note about Git, on the second note I will write about diff, clone, pull, adding remote repository, merge, and conflict resolution.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/974036606587739553-1366540491422631260?l=www.ibrahim-ahmed.com'/&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/IbrahimAhmed/~4/0d7x3V1Jh1Y" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.ibrahim-ahmed.com/feeds/1366540491422631260/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=974036606587739553&amp;postID=1366540491422631260" title="2 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/974036606587739553/posts/default/1366540491422631260?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/974036606587739553/posts/default/1366540491422631260?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/IbrahimAhmed/~3/0d7x3V1Jh1Y/git-version-control-system-part-one.html" title="Git the Version Control System - part one" /><author><name>Ibrahim Ahmed</name><uri>http://www.blogger.com/profile/01640528992428968621</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="05643959196373262770" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">2</thr:total><feedburner:origLink>http://www.ibrahim-ahmed.com/2008/04/git-version-control-system-part-one.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DEABQnw7eSp7ImA9WxZUEUs.&quot;"><id>tag:blogger.com,1999:blog-974036606587739553.post-2228259762911141498</id><published>2008-04-02T12:43:00.000-07:00</published><updated>2008-04-02T13:05:53.201-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-04-02T13:05:53.201-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="server" /><category scheme="http://www.blogger.com/atom/ns#" term="Tools" /><title>Login to Secure Shell Using Key Authentication</title><content type="html">Secure Shell (SSH) is the industry standard encryption protocal for accessing remote server and executing commands in standard shell but in a secure way. SSH is doing a better job protecting the login account from sniffers, way better than its ancestor 'Telnet' which was transfering login account username and password in clear text for all to see. In fact SSH is not only protecting login account by encryption but it is actually encrypting the whole session so that even if sniffers spy on your session they will not be able to decrypt it.&lt;br /&gt;&lt;br /&gt;SSH login account is not the only way of authentication, there is SSH Keys authentication. Having an SSH server configured to accept key only authentication is better than server accepting passwords for authentication cause the later is vulnerable to dictionary attacks. So the most secure way to access a remote server is by using key authentication SSH. And that's what I am going to write a note about now.&lt;br /&gt;&lt;br /&gt;First we need to make sure that our local system having ssh installed.&lt;br /&gt;&lt;blockquote&gt;$ sudo apt-get install openssh-client&lt;/blockquote&gt;and make sure than ssh server is installed on the server&lt;br /&gt;&lt;blockquote&gt; sudo apt-get install openssh-server&lt;br /&gt;sudo /etc/init.d/sshd start&lt;/blockquote&gt;&lt;span style="font-weight: bold;"&gt;SSH Key generation&lt;br /&gt;&lt;/span&gt;We need to generate a pair of keys, on public for the server to encrypt the data and a private key, which is the only key that could decipher the encrypted data, and this private key is by definition should be kept private. There is many secure algorithm for encryption with different degree of encryption strength. There is DSA and RSA, as far as I know DSA is the standard encryption for the USA government, DSA keys has a 1024 size limit, whereas RSA is unlimited .I chose to use RSA key with a 2048 length, here are the steps.&lt;span style="font-weight: bold;"&gt;&lt;span style="font-weight: bold;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;blockquote&gt;&lt;span style="font-weight: bold;"&gt;$&lt;/span&gt; ssh-keygen -v -t rsa -b 2048&lt;br /&gt;Generating public/private rsa key pair.&lt;br /&gt;Enter file in which to save the key (/home/ibrahim/.ssh/id_rsa): /home/ibrahim/.ssh/ibrahim_rsa&lt;br /&gt;Enter passphrase (empty for no passphrase):&lt;br /&gt;Enter same passphrase again:&lt;br /&gt;Your identification has been saved in /home/ibrahim/.ssh/ibrahim_rsa.&lt;br /&gt;Your public key has been saved in /home/ibrahim/.ssh/ibrahim_rsa.pub.&lt;br /&gt;The key fingerprint is:&lt;br /&gt;66:d2:cc:7b:6a:62:f9:f5:c6:ef:69:fc:7b:87:0d:46 ibrahim@ibrahim&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;$&lt;/span&gt; chmod 600 /home/ibrahim/.ssh/ibrahim_rsa&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;$&lt;/span&gt; scp /home/ibrahim/.ssh/ibrahim_dsa.pub ibrahim@myremote.server.com:/home/ibrahim/.ssh&lt;br /&gt;&lt;/blockquote&gt;The latest scp command is named secure copy, which is a part of the ssh package, it is a secure remote copy command.&lt;br /&gt;&lt;br /&gt;on remote server we should do the following.&lt;br /&gt;&lt;blockquote&gt;$ cat /home/ibrahim/.ssh/ibrahim_rsa.pub &gt; /home/ibrahim/.ssh/authorized_keys&lt;br /&gt;&lt;/blockquote&gt;You will be asked for the login password on remote before the copying commences. The file will be copied to login user home directory on remote (/home/ibrahim in that case).&lt;br /&gt;&lt;br /&gt;Now, let's login to remote server using the password to configure the sshd server to disable password login and enable keys.&lt;br /&gt;&lt;blockquote&gt; PermitRootLogin no&lt;br /&gt;#Disable Login password&lt;br /&gt;#PasswordAuthentication no&lt;br /&gt;ChallengeResponseAuthentication no&lt;br /&gt;#Allow forwarding yes&lt;br /&gt;AllowTcpForwarding no&lt;/blockquote&gt;&lt;ul&gt;&lt;li&gt;Uncomment 'PasswordAuthentication no' line only after making sure that the key authentication is working properly.&lt;/li&gt;&lt;li&gt;Disabling root login is recommended anyway, though not useful after disabling login password.&lt;/li&gt;&lt;li&gt;Allow forwarding is not recommended for multi user hosting envirnoment where keys could be exposed. Anyway, we should only allow it if we intend to forward keys from server to server but keep all our keys on the local machine, which is what I exactly want to do.&lt;/li&gt;&lt;/ul&gt;Now, let's try login using the keys.&lt;br /&gt;&lt;blockquote&gt;$ ssh -i /home/ibrahim/.ssh/ibrahim_rsa ibrahim@myremote.server.com&lt;/blockquote&gt;you should be asked to approve connecting to the new server, and whither you trust it, answer yes, that's because we are connecting to the remote server to the first time.&lt;br /&gt;&lt;br /&gt;Hopefully you should now have access to the remote server shell. Now, edit the sshd config file and disable login by password by uncommenting 'PasswordAuthentication no'.&lt;br /&gt;&lt;br /&gt;It is recommended to protect the keys with a passphrase. it is straightforward to do so. In fact you will be asked to provide a passphrase to your private key during key generation and you can skip it if you want. In case you did skip it you can lock it again with a passphrase using the following.&lt;br /&gt;&lt;blockquote&gt;$ ssh-keygen -p&lt;/blockquote&gt;Then it will prompt to put the key file path and you should enter then the password which must be more than 5 chrs.&lt;br /&gt;&lt;br /&gt;Of course using keys is not only useful for security reasons, but also for not asking for password every time you use ssh. But thanks to ssh-agent we could save ourselves a few keystrokes, and more importantly use ssh in automated scripts without interrupting the script to prompt for passwords.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;SSH Agent&lt;/span&gt;&lt;br /&gt;&lt;blockquote&gt;$ eval `ssh-agent`&lt;br /&gt;$ ssh-add /home/ibrahim/.ssh/ibrahim_rsa&lt;br /&gt;$ ssh root@myremote.server.com&lt;/blockquote&gt;We first ran the ssh agent, which is actually a service. then use ssh-add to add the key, them ssh the remote server with only the user name and the remote server address, without providing the key, and if you have protected the key with passphrase you will be asked for the passphrase when you add it. The ssh-agent help in opening a session so we can use ssh to access remote server without giving any keys or password.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/974036606587739553-2228259762911141498?l=www.ibrahim-ahmed.com'/&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/IbrahimAhmed/~4/0MbZmqgEPvs" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.ibrahim-ahmed.com/feeds/2228259762911141498/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=974036606587739553&amp;postID=2228259762911141498" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/974036606587739553/posts/default/2228259762911141498?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/974036606587739553/posts/default/2228259762911141498?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/IbrahimAhmed/~3/0MbZmqgEPvs/login-to-secure-shell-with-key.html" title="Login to Secure Shell Using Key Authentication" /><author><name>Ibrahim Ahmed</name><uri>http://www.blogger.com/profile/01640528992428968621</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="05643959196373262770" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://www.ibrahim-ahmed.com/2008/04/login-to-secure-shell-with-key.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CkQCRn49cSp7ImA9WxZVEUw.&quot;"><id>tag:blogger.com,1999:blog-974036606587739553.post-3374353727817902960</id><published>2008-03-21T05:48:00.000-07:00</published><updated>2008-03-21T07:39:27.069-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-03-21T07:39:27.069-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="web2.0" /><category scheme="http://www.blogger.com/atom/ns#" term="Ruby" /><category scheme="http://www.blogger.com/atom/ns#" term="rails" /><title>Tag clouds in Ruby and Rails</title><content type="html">&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_kaErP_wP6ns/R-PIP7fVBUI/AAAAAAAAACA/-CLrMFQ6G4U/s1600-h/tagcloud.gif"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://2.bp.blogspot.com/_kaErP_wP6ns/R-PIP7fVBUI/AAAAAAAAACA/-CLrMFQ6G4U/s400/tagcloud.gif" alt="" id="BLOGGER_PHOTO_ID_5180204172398888258" border="0" /&gt;&lt;/a&gt;
&lt;br /&gt;I love tags, it's a better way to classify content, and it's trendy, at least it was back in 2005. Tagcloud also gives you good visual indication of hot topics of the site content. I will share the method I use for creating a tagcloud in my sites. The trick of tagcloud is collecting all the tags for certain model and give each tag a weight in a scale from 1 to 5 for example. and then render a tagcloud which is basically tags rendered according to their weight, the most frequent tag is much bolder than the less frequent ones.
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Tags models&lt;/span&gt;
&lt;br /&gt;Before using tags we need to create them first. I use a polymorphic relationship to tag several content types using two additional tables. The first table is the "tags" table which basically list all the tags used in the site, it is composed of a simple tag_id and name fields. The other table is the "taggings" tables. It holds all the relation ships between the content and the tags. It is actually a regular many to many association table but serve more than one content type. It may be easier to explain it in code.
&lt;br /&gt;
&lt;br /&gt;&lt;div style="background: rgb(0, 0, 0) none repeat scroll 0% 50%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; color: rgb(255, 255, 255);"&gt;&lt;span style="font-family:monospace;"&gt;
&lt;br /&gt;&lt;span style="color: rgb(255, 128, 255);"&gt;class&lt;/span&gt; &lt;span style="color: rgb(96, 255, 96);"&gt;&lt;b&gt;Book&lt;/b&gt;&lt;/span&gt; &lt; &lt;span style="color: rgb(96, 255, 96);"&gt;&lt;b&gt;ActiveRecord&lt;/b&gt;&lt;/span&gt;::&lt;span style="color: rgb(96, 255, 96);"&gt;&lt;b&gt;Base&lt;/b&gt;&lt;/span&gt;
&lt;br /&gt; has_many &lt;span style="color: rgb(255, 160, 160);"&gt;:taggings&lt;/span&gt;, &lt;span style="color: rgb(255, 160, 160);"&gt;:as&lt;/span&gt; =&gt; &lt;span style="color: rgb(255, 165, 0);"&gt;'&lt;/span&gt;&lt;span style="color: rgb(255, 160, 160);"&gt;taggable&lt;/span&gt;&lt;span style="color: rgb(255, 165, 0);"&gt;'&lt;/span&gt;
&lt;br /&gt;&lt;span style="color: rgb(255, 128, 255);"&gt;end&lt;/span&gt;
&lt;br /&gt;
&lt;br /&gt;&lt;span style="color: rgb(255, 128, 255);"&gt;class&lt;/span&gt; &lt;span style="color: rgb(96, 255, 96);"&gt;&lt;b&gt;Link&lt;/b&gt;&lt;/span&gt; &lt; &lt;span style="color: rgb(96, 255, 96);"&gt;&lt;b&gt;ActiveRecord&lt;/b&gt;&lt;/span&gt;::&lt;span style="color: rgb(96, 255, 96);"&gt;&lt;b&gt;Base&lt;/b&gt;&lt;/span&gt;
&lt;br /&gt; has_many &lt;span style="color: rgb(255, 160, 160);"&gt;:taggings&lt;/span&gt;, &lt;span style="color: rgb(255, 160, 160);"&gt;:as&lt;/span&gt; =&gt; &lt;span style="color: rgb(255, 165, 0);"&gt;'&lt;/span&gt;&lt;span style="color: rgb(255, 160, 160);"&gt;taggable&lt;/span&gt;&lt;span style="color: rgb(255, 165, 0);"&gt;'&lt;/span&gt;
&lt;br /&gt;&lt;span style="color: rgb(255, 128, 255);"&gt;end&lt;/span&gt;
&lt;br /&gt;
&lt;br /&gt;&lt;span style="color: rgb(255, 128, 255);"&gt;class&lt;/span&gt; &lt;span style="color: rgb(96, 255, 96);"&gt;&lt;b&gt;Tag&lt;/b&gt;&lt;/span&gt; &lt; &lt;span style="color: rgb(96, 255, 96);"&gt;&lt;b&gt;ActiveRecord&lt;/b&gt;&lt;/span&gt;::&lt;span style="color: rgb(96, 255, 96);"&gt;&lt;b&gt;Base&lt;/b&gt;&lt;/span&gt;
&lt;br /&gt; has_many &lt;span style="color: rgb(255, 160, 160);"&gt;:taggings&lt;/span&gt;
&lt;br /&gt;&lt;span style="color: rgb(255, 128, 255);"&gt;end&lt;/span&gt;
&lt;br /&gt;
&lt;br /&gt;&lt;span style="color: rgb(255, 128, 255);"&gt;class&lt;/span&gt; &lt;span style="color: rgb(96, 255, 96);"&gt;&lt;b&gt;Tagging&lt;/b&gt;&lt;/span&gt; &lt; &lt;span style="color: rgb(96, 255, 96);"&gt;&lt;b&gt;ActiveRecord&lt;/b&gt;&lt;/span&gt;::&lt;span style="color: rgb(96, 255, 96);"&gt;&lt;b&gt;Base&lt;/b&gt;&lt;/span&gt;
&lt;br /&gt; belongs_to &lt;span style="color: rgb(255, 160, 160);"&gt;:tag&lt;/span&gt;
&lt;br /&gt; belongs_to &lt;span style="color: rgb(255, 160, 160);"&gt;:taggable&lt;/span&gt;, &lt;span style="color: rgb(255, 160, 160);"&gt;:polymorphic&lt;/span&gt; =&gt; &lt;span style="color: rgb(255, 160, 160);"&gt;true&lt;/span&gt;
&lt;br /&gt;&lt;span style="color: rgb(255, 128, 255);"&gt;end&lt;/span&gt;
&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;In these ActiveRecord models, Link and Book are content models which have many taggings, and each Tagging by its turn belongs to one tag.  But notice in the has_many association in the Book and Link model that it we passed an "as =&gt; 'taggable'" that tell the ActiveRecord that Tagging belongs to a polymorphic model that is called 'taggable'. Taggable could be any model in your application and this pattern make your tagging mechanism support new models as you make them transparently, all you need to do is adding 'has_many as' association.
&lt;br /&gt;
&lt;br /&gt;&lt;div style="background: rgb(0, 0, 0) none repeat scroll 0% 50%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; color: rgb(255, 255, 255);"&gt;&lt;span style="font-family:monospace;"&gt;&lt;span style="color: rgb(255, 128, 255);"&gt;class&lt;/span&gt; &lt;span style="font-family:mon;"&gt;&lt;span style="font-weight: bold;"&gt;Photo&lt;/span&gt;&lt;/span&gt; &lt; &lt;span style="color: rgb(96, 255, 96);"&gt;&lt;b&gt;ActiveRecord&lt;/b&gt;&lt;/span&gt;::&lt;span style="color: rgb(96, 255, 96);"&gt;&lt;b&gt;Base&lt;/b&gt;&lt;/span&gt;
&lt;br /&gt; has_many &lt;span style="color: rgb(255, 160, 160);"&gt;:taggings&lt;/span&gt;, &lt;span style="color: rgb(255, 160, 160);"&gt;:as&lt;/span&gt; =&gt; &lt;span style="color: rgb(255, 165, 0);"&gt;'&lt;/span&gt;&lt;span style="color: rgb(255, 160, 160);"&gt;taggable&lt;/span&gt;&lt;span style="color: rgb(255, 165, 0);"&gt;'&lt;/span&gt;
&lt;br /&gt;&lt;span style="color: rgb(255, 128, 255);"&gt;end&lt;/span&gt;
&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Create the database tables&lt;/span&gt;
&lt;br /&gt;The following is a basic Mysql schema for the tags, taggings tables:
&lt;br /&gt;
&lt;br /&gt;&lt;div style="background: rgb(0, 0, 0) none repeat scroll 0% 50%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; color: rgb(255, 255, 255);"&gt;&lt;span style="font-family:monospace;"&gt;&lt;span style="color: rgb(255, 255, 96);"&gt;&lt;b&gt;
&lt;br /&gt;CREATE&lt;/b&gt;&lt;/span&gt; &lt;span style="color: rgb(255, 165, 0);"&gt;TABLE&lt;/span&gt; `tags` (
&lt;br /&gt;`id` int(&lt;span style="color: rgb(255, 160, 160);"&gt;10&lt;/span&gt;) unsigned &lt;span style="color: rgb(255, 255, 96);"&gt;&lt;b&gt;NOT&lt;/b&gt;&lt;/span&gt; &lt;span style="color: rgb(255, 165, 0);"&gt;NULL&lt;/span&gt; auto_increment,
&lt;br /&gt;`name` &lt;span style="color: rgb(96, 255, 96);"&gt;&lt;b&gt;varchar&lt;/b&gt;&lt;/span&gt;(&lt;span style="color: rgb(255, 160, 160);"&gt;255&lt;/span&gt;),
&lt;br /&gt;`created_at` datetime,
&lt;br /&gt;`updated_at` datetime,
&lt;br /&gt;PRIMARY KEY  (`id`)
&lt;br /&gt;);
&lt;br /&gt;
&lt;br /&gt;&lt;span style="color: rgb(255, 255, 96);"&gt;&lt;b&gt;CREATE&lt;/b&gt;&lt;/span&gt; &lt;span style="color: rgb(255, 165, 0);"&gt;TABLE&lt;/span&gt; `taggings` (
&lt;br /&gt;`id` int(&lt;span style="color: rgb(255, 160, 160);"&gt;10&lt;/span&gt;) unsigned &lt;span style="color: rgb(255, 255, 96);"&gt;&lt;b&gt;NOT&lt;/b&gt;&lt;/span&gt; &lt;span style="color: rgb(255, 165, 0);"&gt;NULL&lt;/span&gt; auto_increment,
&lt;br /&gt;`tag_id` int(&lt;span style="color: rgb(255, 160, 160);"&gt;11&lt;/span&gt;),
&lt;br /&gt;`taggable_type` &lt;span style="color: rgb(96, 255, 96);"&gt;&lt;b&gt;varchar&lt;/b&gt;&lt;/span&gt;(&lt;span style="color: rgb(255, 160, 160);"&gt;20&lt;/span&gt;),
&lt;br /&gt;`taggable_id` int(&lt;span style="color: rgb(255, 160, 160);"&gt;11&lt;/span&gt;),
&lt;br /&gt;`created_at` datetime,
&lt;br /&gt;PRIMARY KEY  (`id`)
&lt;br /&gt;);
&lt;br /&gt;
&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Collecting the tags&lt;/span&gt;
&lt;br /&gt;The following is a method that could be located in a model probably taggings or in a helper.
&lt;br /&gt;
&lt;br /&gt;&lt;div style="background: rgb(0, 0, 0) none repeat scroll 0% 50%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; color: rgb(255, 255, 255);"&gt;&lt;span style="font-family:monospace;"&gt;
&lt;br /&gt;&lt;span style="color: rgb(255, 128, 255);"&gt;def&lt;/span&gt; &lt;span style="color: rgb(64, 255, 255);"&gt;tags_cloud&lt;/span&gt;(model, limit=&lt;span style="color: rgb(255, 160, 160);"&gt;30&lt;/span&gt;)
&lt;br /&gt;options = {
&lt;br /&gt;&lt;span style="color: rgb(255, 160, 160);"&gt;    :select&lt;/span&gt; =&gt; &lt;span style="color: rgb(255, 165, 0);"&gt;"&lt;/span&gt;&lt;span style="color: rgb(255, 160, 160);"&gt;count(taggings.id) as count_all, tags.name as tag_name, tag_id&lt;/span&gt;&lt;span style="color: rgb(255, 165, 0);"&gt;"&lt;/span&gt;,
&lt;br /&gt;&lt;span style="color: rgb(255, 160, 160);"&gt;    :conditions&lt;/span&gt; =&gt; {&lt;span style="color: rgb(255, 160, 160);"&gt;:taggable_type&lt;/span&gt; =&gt; model.to_s },
&lt;br /&gt;&lt;span style="color: rgb(255, 160, 160);"&gt;    :joins&lt;/span&gt; =&gt; &lt;span style="color: rgb(255, 165, 0);"&gt;"&lt;/span&gt;&lt;span style="color: rgb(255, 160, 160);"&gt; left outer join tags on tags.id=taggings.tag_id&lt;/span&gt;&lt;span style="color: rgb(255, 165, 0);"&gt;"&lt;/span&gt; ,
&lt;br /&gt;&lt;span style="color: rgb(255, 160, 160);"&gt;    :group&lt;/span&gt; =&gt; &lt;span style="color: rgb(255, 165, 0);"&gt;'&lt;/span&gt;&lt;span style="color: rgb(255, 160, 160);"&gt;tag_id&lt;/span&gt;&lt;span style="color: rgb(255, 165, 0);"&gt;'&lt;/span&gt;,
&lt;br /&gt;&lt;span style="color: rgb(255, 160, 160);"&gt;    :order&lt;/span&gt; =&gt; &lt;span style="color: rgb(255, 165, 0);"&gt;'&lt;/span&gt;&lt;span style="color: rgb(255, 160, 160);"&gt;count_all desc&lt;/span&gt;&lt;span style="color: rgb(255, 165, 0);"&gt;'&lt;/span&gt;,
&lt;br /&gt;&lt;span style="color: rgb(255, 160, 160);"&gt;    :limit&lt;/span&gt; =&gt; limit
&lt;br /&gt;}
&lt;br /&gt;
&lt;br /&gt;sql = &lt;span style="color: rgb(96, 255, 96);"&gt;&lt;b&gt;Tagging&lt;/b&gt;&lt;/span&gt;.send(&lt;span style="color: rgb(255, 160, 160);"&gt;:construct_finder_sql&lt;/span&gt;, options)
&lt;br /&gt;
&lt;br /&gt;taggings = &lt;span style="color: rgb(96, 255, 96);"&gt;&lt;b&gt;ActiveRecord&lt;/b&gt;&lt;/span&gt;::&lt;span style="color: rgb(96, 255, 96);"&gt;&lt;b&gt;Base&lt;/b&gt;&lt;/span&gt;.connection.select_all(sql)
&lt;br /&gt;
&lt;br /&gt;&lt;span style="color: rgb(255, 255, 96);"&gt;&lt;b&gt;return&lt;/b&gt;&lt;/span&gt; [] &lt;span style="color: rgb(255, 255, 96);"&gt;&lt;b&gt;if&lt;/b&gt;&lt;/span&gt; taggings.blank?
&lt;br /&gt;
&lt;br /&gt;maxlog = &lt;span style="color: rgb(96, 255, 96);"&gt;&lt;b&gt;Math&lt;/b&gt;&lt;/span&gt;.log(taggings.first[&lt;span style="color: rgb(255, 165, 0);"&gt;'&lt;/span&gt;&lt;span style="color: rgb(255, 160, 160);"&gt;count_all&lt;/span&gt;&lt;span style="color: rgb(255, 165, 0);"&gt;'&lt;/span&gt;])
&lt;br /&gt;minlog = &lt;span style="color: rgb(96, 255, 96);"&gt;&lt;b&gt;Math&lt;/b&gt;&lt;/span&gt;.log(taggings.last[&lt;span style="color: rgb(255, 165, 0);"&gt;'&lt;/span&gt;&lt;span style="color: rgb(255, 160, 160);"&gt;count_all&lt;/span&gt;&lt;span style="color: rgb(255, 165, 0);"&gt;'&lt;/span&gt;])
&lt;br /&gt;rangelog = maxlog - minlog;
&lt;br /&gt;rangelog = &lt;span style="color: rgb(255, 160, 160);"&gt;1&lt;/span&gt; &lt;span style="color: rgb(255, 255, 96);"&gt;&lt;b&gt;if&lt;/b&gt;&lt;/span&gt; maxlog==minlog
&lt;br /&gt;min_font = &lt;span style="color: rgb(255, 160, 160);"&gt;1&lt;/span&gt;
&lt;br /&gt;max_font = &lt;span style="color: rgb(255, 160, 160);"&gt;5&lt;/span&gt;
&lt;br /&gt;font_range = max_font - min_font
&lt;br /&gt;cloud = []
&lt;br /&gt;taggings = taggings.sort{|&lt;span style="color: rgb(64, 255, 255);"&gt;a&lt;/span&gt;,&lt;span style="color: rgb(64, 255, 255);"&gt;b&lt;/span&gt;| a[&lt;span style="color: rgb(255, 165, 0);"&gt;'&lt;/span&gt;&lt;span style="color: rgb(255, 160, 160);"&gt;tag_name&lt;/span&gt;&lt;span style="color: rgb(255, 165, 0);"&gt;'&lt;/span&gt;] &lt;=&gt; b[&lt;span style="color: rgb(255, 165, 0);"&gt;'&lt;/span&gt;&lt;span style="color: rgb(255, 160, 160);"&gt;tag_name&lt;/span&gt;&lt;span style="color: rgb(255, 165, 0);"&gt;'&lt;/span&gt;]}
&lt;br /&gt;
&lt;br /&gt;taggings.each &lt;span style="color: rgb(255, 255, 96);"&gt;&lt;b&gt;do&lt;/b&gt;&lt;/span&gt; |&lt;span style="color: rgb(64, 255, 255);"&gt;tagging&lt;/span&gt;|
&lt;br /&gt;font_size = min_font + font_range * (&lt;span style="color: rgb(96, 255, 96);"&gt;&lt;b&gt;Math&lt;/b&gt;&lt;/span&gt;.log(tagging[&lt;span style="color: rgb(255, 165, 0);"&gt;'&lt;/span&gt;&lt;span style="color: rgb(255, 160, 160);"&gt;count_all&lt;/span&gt;&lt;span style="color: rgb(255, 165, 0);"&gt;'&lt;/span&gt;]) - minlog)/rangelog
&lt;br /&gt;cloud &lt;&lt; [tagging['tag_name'], tagging['tag_id'], font_size.to_i, tagging['count_all']]   &lt;span style="color: rgb(255, 255, 96);"&gt;&lt;b&gt;end&lt;/b&gt;&lt;/span&gt;
&lt;br /&gt;return cloud
&lt;br /&gt;&lt;span style="color: rgb(255, 128, 255);"&gt;end&lt;/span&gt;
&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;If I use active record to find the required taggings it will then return a bunch of instantiated Tagging object and that would be a waste of memory and resources. It's better to make Active Record to only construct the SQL for us and then use the SQL to query the database directly.
&lt;br /&gt;
&lt;br /&gt;I used an array with all regular select, conditions, joins and other arguments we usually use with the find method, and then use construct_finder_sql which is a private method of ActiveRecord, that's why i use send method to call it. And it returns the sql statement that i will use directly in an sql connection derived from the ActiveRecord::Base class.
&lt;br /&gt;
&lt;br /&gt;I learned a trick from one of web2.0 books from Oreilly, I don't remember it right now, the trick is to make  a contrast between the most frequent tags and less frequent ones using logarithm. Anyway you can figure it our yourself, or just use it as it is :)
&lt;br /&gt;
&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;The View&lt;/span&gt;
&lt;br /&gt;This is a sample of a view template that render the tagcloud. IT could be used as a base for a more sophisticated tagcloud.
&lt;br /&gt;
&lt;br /&gt;&lt;div style="background: rgb(0, 0, 0) none repeat scroll 0% 50%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; color: rgb(255, 255, 255);"&gt;&lt;span style="font-family:monospace;"&gt;
&lt;br /&gt;&lt;span style="color: rgb(255, 165, 0);"&gt;    &lt;%&lt;/span&gt; the_cloud = tags_cloud(model) &lt;span style="color: rgb(255, 165, 0);"&gt;%&gt;&lt;/span&gt;
&lt;br /&gt;&lt;span style="color: rgb(255, 165, 0);"&gt;    &lt;%&lt;/span&gt; &lt;span style="color: rgb(255, 255, 96);"&gt;&lt;b&gt;unless&lt;/b&gt;&lt;/span&gt; the_cloud.blank? &lt;span style="color: rgb(255, 165, 0);"&gt;%&gt;&lt;/span&gt;
&lt;br /&gt;&lt;span style="color: rgb(64, 255, 255);"&gt;            &lt;&lt;/span&gt;&lt;span style="color: rgb(255, 255, 96);"&gt;&lt;b&gt;div&lt;/b&gt;&lt;/span&gt;&lt;span style="color: rgb(64, 255, 255);"&gt; &lt;/span&gt;&lt;span style="color: rgb(96, 255, 96);"&gt;&lt;b&gt;id&lt;/b&gt;&lt;/span&gt;&lt;span style="color: rgb(64, 255, 255);"&gt;=&lt;/span&gt;&lt;span style="color: rgb(255, 160, 160);"&gt;"big_tags_cloud"&lt;/span&gt;&lt;span style="color: rgb(64, 255, 255);"&gt;&gt;&lt;/span&gt;
&lt;br /&gt;&lt;span style="color: rgb(255, 165, 0);"&gt;                    &lt;%&lt;/span&gt; the_cloud.each &lt;span style="color: rgb(255, 255, 96);"&gt;&lt;b&gt;do&lt;/b&gt;&lt;/span&gt; |&lt;span style="color: rgb(64, 255, 255);"&gt;tag&lt;/span&gt;,&lt;span style="color: rgb(64, 255, 255);"&gt;id&lt;/span&gt;,&lt;span style="color: rgb(64, 255, 255);"&gt;fsize&lt;/span&gt;,&lt;span style="color: rgb(64, 255, 255);"&gt;count&lt;/span&gt;| &lt;span style="color: rgb(255, 165, 0);"&gt;%&gt;&lt;/span&gt;
&lt;br /&gt;&lt;span style="color: rgb(64, 255, 255);"&gt;                        &lt;&lt;/span&gt;&lt;span style="color: rgb(255, 255, 96);"&gt;&lt;b&gt;span&lt;/b&gt;&lt;/span&gt;&lt;span style="color: rgb(64, 255, 255);"&gt; &lt;/span&gt;&lt;span style="color: rgb(96, 255, 96);"&gt;&lt;b&gt;class&lt;/b&gt;&lt;/span&gt;&lt;span style="color: rgb(64, 255, 255);"&gt;=&lt;/span&gt;&lt;span style="color: rgb(255, 160, 160);"&gt;"t&lt;/span&gt;&lt;span style="color: rgb(255, 165, 0);"&gt;&lt;%=&lt;/span&gt; fsize &lt;span style="color: rgb(255, 165, 0);"&gt;-%&gt;&lt;/span&gt;&lt;span style="color: rgb(255, 160, 160);"&gt;"&lt;/span&gt;&lt;span style="color: rgb(64, 255, 255);"&gt;&gt;
&lt;br /&gt;             &lt;&lt;/span&gt;&lt;span style="color: rgb(255, 255, 96);"&gt;&lt;b&gt;a&lt;/b&gt;&lt;/span&gt;  &lt;span style="color: rgb(96, 255, 96);"&gt;&lt;b&gt;title&lt;/b&gt;&lt;/span&gt;&lt;span style="color: rgb(64, 255, 255);"&gt;=&lt;/span&gt;&lt;span style="color: rgb(255, 160, 160);"&gt;"&lt;/span&gt;&lt;span style="color: rgb(255, 165, 0);"&gt;&lt;%=&lt;/span&gt; count &lt;span style="color: rgb(255, 165, 0);"&gt;%&gt;&lt;/span&gt;&lt;span style="color: rgb(255, 160, 160);"&gt;"&lt;/span&gt;&lt;span style="color: rgb(64, 255, 255);"&gt;
&lt;br /&gt;     &lt;/span&gt;&lt;span style="color: rgb(96, 255, 96);"&gt;&lt;b&gt;                                        alt&lt;/b&gt;&lt;/span&gt;&lt;span style="color: rgb(64, 255, 255);"&gt;=&lt;/span&gt;&lt;span style="color: rgb(255, 160, 160);"&gt;"&lt;/span&gt;&lt;span style="color: rgb(255, 165, 0);"&gt;&lt;%=&lt;/span&gt; count &lt;span style="color: rgb(255, 165, 0);"&gt;-%&gt;&lt;/span&gt;&lt;span style="color: rgb(255, 160, 160);"&gt;"&lt;/span&gt;&lt;span style="color: rgb(64, 255, 255);"&gt;
&lt;br /&gt;     &lt;/span&gt;&lt;span style="color: rgb(96, 255, 96);"&gt;&lt;b&gt;                                        class&lt;/b&gt;&lt;/span&gt;&lt;span style="color: rgb(64, 255, 255);"&gt;=&lt;/span&gt;&lt;span style="color: rgb(255, 160, 160);"&gt;"tag_&lt;/span&gt;&lt;span style="color: rgb(255, 165, 0);"&gt;&lt;%=&lt;/span&gt; id &lt;span style="color: rgb(255, 165, 0);"&gt;%&gt;&lt;/span&gt;&lt;span style="color: rgb(255, 160, 160);"&gt;"&lt;/span&gt;&lt;span style="color: rgb(64, 255, 255);"&gt;
&lt;br /&gt;&lt;/span&gt;&lt;span style="color: rgb(96, 255, 96);"&gt;&lt;b&gt;                                                    href&lt;/b&gt;&lt;/span&gt;&lt;span style="color: rgb(64, 255, 255);"&gt;=&lt;/span&gt;&lt;span style="color: rgb(255, 160, 160);"&gt;"/&lt;/span&gt;&lt;span style="color: rgb(255, 165, 0);"&gt;&lt;%=&lt;/span&gt; model.to_s.downcase &lt;span style="color: rgb(255, 165, 0);"&gt;%&gt;&lt;/span&gt;&lt;span style="color: rgb(255, 160, 160);"&gt;s/tag/&lt;/span&gt;&lt;span style="color: rgb(255, 165, 0);"&gt;&lt;%=&lt;/span&gt; id &lt;span style="color: rgb(255, 165, 0);"&gt;-%&gt;&lt;/span&gt;&lt;span style="color: rgb(255, 160, 160);"&gt;"&lt;/span&gt;&lt;span style="color: rgb(64, 255, 255);"&gt;&gt;&lt;/span&gt;&lt;span style="color: rgb(255, 165, 0);"&gt;
&lt;br /&gt;                                     &lt;%=&lt;/span&gt; tag &lt;span style="color: rgb(255, 165, 0);"&gt;%&gt;
&lt;br /&gt;&lt;/span&gt;&lt;span style="color: rgb(64, 255, 255);"&gt;        &lt;!--&lt;/span--&gt;&lt;span style="color: rgb(255, 255, 96);"&gt;&lt;b&gt;                &lt;/b&gt;&lt;/span&gt;&lt;span style="color: rgb(64, 255, 255);"&gt;                &lt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="font-family:monospace;"&gt;&lt;span style="color: rgb(64, 255, 255);"&gt;&lt;span style="color: rgb(255, 255, 96);"&gt;&lt;b&gt;a&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="font-family:monospace;"&gt;&lt;span style="color: rgb(64, 255, 255);"&gt;&lt;span style="color: rgb(64, 255, 255);"&gt;&gt;
&lt;br /&gt; &lt;!--&lt;/span--&gt;&lt;span style="font-family:mon;"&gt;&lt;span style="font-weight: bold;"&gt;                        &lt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="font-family:monospace;"&gt;&lt;span style="color: rgb(64, 255, 255);"&gt;&lt;span style="color: rgb(64, 255, 255);"&gt;&lt;span style="color: rgb(255, 255, 96);"&gt;&lt;b&gt;span&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="font-family:monospace;"&gt;&lt;span style="color: rgb(64, 255, 255);"&gt;&lt;span style="color: rgb(64, 255, 255);"&gt;&lt;span style="color: rgb(64, 255, 255);"&gt;&gt;&lt;/span&gt;
&lt;br /&gt;&lt;span style="color: rgb(255, 165, 0);"&gt;                    &lt;%&lt;/span&gt; &lt;span style="color: rgb(255, 255, 96);"&gt;&lt;b&gt;end&lt;/b&gt;&lt;/span&gt; &lt;span style="color: rgb(255, 165, 0);"&gt;%&gt;&lt;/span&gt;
&lt;br /&gt;&lt;span style="color: rgb(64, 255, 255);"&gt;&lt;!--&lt;/span--&gt;&lt;span style="color: rgb(64, 255, 255);"&gt;            &lt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="font-family:monospace;"&gt;&lt;span style="color: rgb(64, 255, 255);"&gt;&lt;span style="color: rgb(64, 255, 255);"&gt;&lt;span style="color: rgb(64, 255, 255);"&gt;&lt;span style="color: rgb(255, 255, 96);"&gt;&lt;b&gt;div&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="font-family:monospace;"&gt;&lt;span style="color: rgb(64, 255, 255);"&gt;&lt;span style="color: rgb(64, 255, 255);"&gt;&lt;span style="color: rgb(64, 255, 255);"&gt;&lt;span style="color: rgb(64, 255, 255);"&gt;&gt;&lt;/span&gt;
&lt;br /&gt;&lt;span style="color: rgb(255, 165, 0);"&gt;    &lt;%&lt;/span&gt; &lt;span style="color: rgb(255, 255, 96);"&gt;&lt;b&gt;end&lt;/b&gt;&lt;/span&gt; &lt;span style="color: rgb(255, 165, 0);"&gt;%&gt;
&lt;br /&gt;
&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Styling the cloud&lt;/span&gt;
&lt;br /&gt;
&lt;br /&gt;&lt;div style="background: rgb(0, 0, 0) none repeat scroll 0% 50%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; color: rgb(255, 255, 255);"&gt;&lt;span style="font-family:monospace;"&gt;
&lt;br /&gt;&lt;span style="color: rgb(64, 255, 255);"&gt;#big_tags_cloud&lt;/span&gt; &lt;span style="color: rgb(64, 255, 255);"&gt;{&lt;/span&gt;&lt;span style="color: rgb(96, 255, 96);"&gt;&lt;b&gt;padding&lt;/b&gt;&lt;/span&gt;:&lt;span style="color: rgb(255, 160, 160);"&gt;5px&lt;/span&gt;; &lt;span style="color: rgb(96, 255, 96);"&gt;&lt;b&gt;text-align&lt;/b&gt;&lt;/span&gt;:&lt;span style="color: rgb(96, 255, 96);"&gt;&lt;b&gt;justify&lt;/b&gt;&lt;/span&gt;; &lt;span style="color: rgb(64, 255, 255);"&gt;}&lt;/span&gt;
&lt;br /&gt;&lt;span style="color: rgb(64, 255, 255);"&gt;#big_tags_cloud&lt;/span&gt; &lt;span style="color: rgb(255, 255, 96);"&gt;&lt;b&gt;a&lt;/b&gt;&lt;/span&gt; &lt;span style="color: rgb(64, 255, 255);"&gt;{&lt;/span&gt;&lt;span style="color: rgb(96, 255, 96);"&gt;&lt;b&gt;font-family&lt;/b&gt;&lt;/span&gt;:&lt;span style="color: rgb(255, 160, 160);"&gt;'Times New Roman'&lt;/span&gt;; &lt;span style="color: rgb(96, 255, 96);"&gt;&lt;b&gt;line-height&lt;/b&gt;&lt;/span&gt;:&lt;span style="color: rgb(255, 160, 160);"&gt;1.7&lt;/span&gt;;&lt;span style="color: rgb(96, 255, 96);"&gt;&lt;b&gt;border-bottom&lt;/b&gt;&lt;/span&gt;:&lt;span style="color: rgb(255, 160, 160);"&gt;1px&lt;/span&gt; &lt;span style="color: rgb(96, 255, 96);"&gt;&lt;b&gt;solid&lt;/b&gt;&lt;/span&gt; &lt;span style="color: rgb(255, 160, 160);"&gt;#779944&lt;/span&gt;;&lt;span style="color: rgb(64, 255, 255);"&gt;}&lt;/span&gt;
&lt;br /&gt;&lt;span style="color: rgb(64, 255, 255);"&gt;#big_tags_cloud&lt;/span&gt; &lt;span style="color: rgb(255, 255, 96);"&gt;&lt;b&gt;span&lt;/b&gt;&lt;/span&gt;&lt;span style="color: rgb(64, 255, 255);"&gt;.t1&lt;/span&gt; &lt;span style="color: rgb(255, 255, 96);"&gt;&lt;b&gt;a&lt;/b&gt;&lt;/span&gt;&lt;span style="color: rgb(64, 255, 255);"&gt;{&lt;/span&gt; &lt;span style="color: rgb(96, 255, 96);"&gt;&lt;b&gt;color&lt;/b&gt;&lt;/span&gt;:&lt;span style="color: rgb(255, 160, 160);"&gt;#779944&lt;/span&gt;;&lt;span style="color: rgb(96, 255, 96);"&gt;&lt;b&gt;font-size&lt;/b&gt;&lt;/span&gt;:&lt;span style="color: rgb(255, 160, 160);"&gt;11pt&lt;/span&gt;;&lt;span style="color: rgb(64, 255, 255);"&gt;}&lt;/span&gt;
&lt;br /&gt;&lt;span style="color: rgb(64, 255, 255);"&gt;#big_tags_cloud&lt;/span&gt; &lt;span style="color: rgb(255, 255, 96);"&gt;&lt;b&gt;span&lt;/b&gt;&lt;/span&gt;&lt;span style="color: rgb(64, 255, 255);"&gt;.t2&lt;/span&gt; &lt;span style="color: rgb(255, 255, 96);"&gt;&lt;b&gt;a&lt;/b&gt;&lt;/span&gt;&lt;span style="color: rgb(64, 255, 255);"&gt;{&lt;/span&gt; &lt;span style="color: rgb(96, 255, 96);"&gt;&lt;b&gt;color&lt;/b&gt;&lt;/span&gt;:&lt;span style="color: rgb(255, 160, 160);"&gt;#779944&lt;/span&gt;;&lt;span style="color: rgb(96, 255, 96);"&gt;&lt;b&gt;font-size&lt;/b&gt;&lt;/span&gt;:&lt;span style="color: rgb(255, 160, 160);"&gt;12pt&lt;/span&gt;;&lt;span style="color: rgb(64, 255, 255);"&gt;}&lt;/span&gt;
&lt;br /&gt;&lt;span style="color: rgb(64, 255, 255);"&gt;#big_tags_cloud&lt;/span&gt; &lt;span style="color: rgb(255, 255, 96);"&gt;&lt;b&gt;span&lt;/b&gt;&lt;/span&gt;&lt;span style="color: rgb(64, 255, 255);"&gt;.t3&lt;/span&gt; &lt;span style="color: rgb(255, 255, 96);"&gt;&lt;b&gt;a&lt;/b&gt;&lt;/span&gt;&lt;span style="color: rgb(64, 255, 255);"&gt;{&lt;/span&gt; &lt;span style="color: rgb(96, 255, 96);"&gt;&lt;b&gt;color&lt;/b&gt;&lt;/span&gt;:&lt;span style="color: rgb(255, 160, 160);"&gt;#779944&lt;/span&gt;;&lt;span style="color: rgb(96, 255, 96);"&gt;&lt;b&gt;font-size&lt;/b&gt;&lt;/span&gt;:&lt;span style="color: rgb(255, 160, 160);"&gt;13pt&lt;/span&gt;;&lt;span style="color: rgb(64, 255, 255);"&gt;}&lt;/span&gt;
&lt;br /&gt;&lt;span style="color: rgb(64, 255, 255);"&gt;#big_tags_cloud&lt;/span&gt; &lt;span style="color: rgb(255, 255, 96);"&gt;&lt;b&gt;span&lt;/b&gt;&lt;/span&gt;&lt;span style="color: rgb(64, 255, 255);"&gt;.t4&lt;/span&gt; &lt;span style="color: rgb(255, 255, 96);"&gt;&lt;b&gt;a&lt;/b&gt;&lt;/span&gt;&lt;span style="color: rgb(64, 255, 255);"&gt;{&lt;/span&gt; &lt;span style="color: rgb(96, 255, 96);"&gt;&lt;b&gt;color&lt;/b&gt;&lt;/span&gt;:&lt;span style="color: rgb(255, 160, 160);"&gt;#558800&lt;/span&gt;;&lt;span style="color: rgb(96, 255, 96);"&gt;&lt;b&gt;font-size&lt;/b&gt;&lt;/span&gt;:&lt;span style="color: rgb(255, 160, 160);"&gt;14pt&lt;/span&gt;;&lt;span style="color: rgb(96, 255, 96);"&gt;&lt;b&gt;font-weight&lt;/b&gt;&lt;/span&gt;:&lt;span style="color: rgb(96, 255, 96);"&gt;&lt;b&gt;bold&lt;/b&gt;&lt;/span&gt;;&lt;span style="color: rgb(64, 255, 255);"&gt;}&lt;/span&gt;
&lt;br /&gt;&lt;span style="color: rgb(64, 255, 255);"&gt;#big_tags_cloud&lt;/span&gt; &lt;span style="color: rgb(255, 255, 96);"&gt;&lt;b&gt;span&lt;/b&gt;&lt;/span&gt;&lt;span style="color: rgb(64, 255, 255);"&gt;.t5&lt;/span&gt; &lt;span style="color: rgb(255, 255, 96);"&gt;&lt;b&gt;a&lt;/b&gt;&lt;/span&gt;&lt;span style="color: rgb(64, 255, 255);"&gt;{&lt;/span&gt; &lt;span style="color: rgb(96, 255, 96);"&gt;&lt;b&gt;color&lt;/b&gt;&lt;/span&gt;:&lt;span style="color: rgb(255, 160, 160);"&gt;#669900&lt;/span&gt;;&lt;span style="color: rgb(96, 255, 96);"&gt;&lt;b&gt;font-size&lt;/b&gt;&lt;/span&gt;:&lt;span style="color: rgb(255, 160, 160);"&gt;15pt&lt;/span&gt;; &lt;span style="color: rgb(96, 255, 96);"&gt;&lt;b&gt;font-weight&lt;/b&gt;&lt;/span&gt;:&lt;span style="color: rgb(96, 255, 96);"&gt;&lt;b&gt;bold&lt;/b&gt;&lt;/span&gt;;&lt;span style="color: rgb(64, 255, 255);"&gt;}&lt;/span&gt;
&lt;br /&gt;
&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/974036606587739553-3374353727817902960?l=www.ibrahim-ahmed.com'/&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/IbrahimAhmed/~4/qHlzCR2HkAs" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.ibrahim-ahmed.com/feeds/3374353727817902960/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=974036606587739553&amp;postID=3374353727817902960" title="1 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/974036606587739553/posts/default/3374353727817902960?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/974036606587739553/posts/default/3374353727817902960?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/IbrahimAhmed/~3/qHlzCR2HkAs/tag-clouds-in-ruby-and-rails.html" title="Tag clouds in Ruby and Rails" /><author><name>Ibrahim Ahmed</name><uri>http://www.blogger.com/profile/01640528992428968621</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="05643959196373262770" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://2.bp.blogspot.com/_kaErP_wP6ns/R-PIP7fVBUI/AAAAAAAAACA/-CLrMFQ6G4U/s72-c/tagcloud.gif" height="72" width="72" /><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">1</thr:total><feedburner:origLink>http://www.ibrahim-ahmed.com/2008/03/tag-clouds-in-ruby-and-rails.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DUAERHY_eyp7ImA9WxZWE0Q.&quot;"><id>tag:blogger.com,1999:blog-974036606587739553.post-2479875062800935775</id><published>2008-03-13T01:33:00.000-07:00</published><updated>2008-03-13T01:41:45.843-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-03-13T01:41:45.843-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Tools" /><title>Switch proxy settings quickly in Firefox</title><content type="html">I keep on switching back and forth proxy setting in Firefox. I am behind a proxy at work and direct connection at home. For all poor souls who suffer the same hassle go install this little firefox addon &lt;a href="https://addons.mozilla.org/en-US/firefox/addon/1557"&gt;QuickProxy&lt;/a&gt;.&lt;a href="https://addons.mozilla.org/en-US/firefox/addon/1557"&gt;&lt;br /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/974036606587739553-2479875062800935775?l=www.ibrahim-ahmed.com'/&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/IbrahimAhmed/~4/bF-t3-D_RtE" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.ibrahim-ahmed.com/feeds/2479875062800935775/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=974036606587739553&amp;postID=2479875062800935775" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/974036606587739553/posts/default/2479875062800935775?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/974036606587739553/posts/default/2479875062800935775?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/IbrahimAhmed/~3/bF-t3-D_RtE/switch-proxy-settings-with-ease-in.html" title="Switch proxy settings quickly in Firefox" /><author><name>Ibrahim Ahmed</name><uri>http://www.blogger.com/profile/01640528992428968621</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="05643959196373262770" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://www.ibrahim-ahmed.com/2008/03/switch-proxy-settings-with-ease-in.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DUcDSH4_eCp7ImA9WxZWE0Q.&quot;"><id>tag:blogger.com,1999:blog-974036606587739553.post-1160557401731482746</id><published>2008-03-12T17:17:00.000-07:00</published><updated>2008-03-13T01:31:19.040-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-03-13T01:31:19.040-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="configuration" /><title>Making GPRS Vodafone card work on Ubuntu</title><content type="html">I spent a couple of hours trying to make a GPRS Vodafone PCMCIA card to work in my Ubuntu laptop. And It's working, and here are my tips. But I believe the following instructions should be useful in other Linux distributions.&lt;br /&gt;&lt;br /&gt;Make sure the following packages are installed:&lt;br /&gt;&lt;blockquote&gt;sudo apt-get install pcmcia-cs&lt;br /&gt;sudo apt-get install gnome-ppp&lt;br /&gt;&lt;/blockquote&gt;&lt;span style="font-weight: bold;"&gt;Configuring Gnome-ppp&lt;/span&gt;&lt;br /&gt;There some Vodafone Egypt specific data needed for connection&lt;br /&gt;&lt;blockquote&gt;APN: internet.vodafone.net&lt;br /&gt;user: internet&lt;br /&gt;password: internet&lt;br /&gt;&lt;/blockquote&gt;Type on a shell  the following command and try to know the device assigned to the pcmcia GPRS card. In my laptop it was /dev/ttyS3. I noticed other blogs mentioning cards assigned to USB devices! So look carefully. You may need to eject and reinsert the card again and observe the messages on the syslog.&lt;br /&gt;&lt;blockquote&gt;tail -f /var/log/syslog&lt;br /&gt;&lt;/blockquote&gt;After knowing the device assign to GPRS card, click "Setup" and choose the device from the list.&lt;br /&gt;&lt;br /&gt;Select speed like 115200, there are bloggers mentioning 460800 so you may try it later. It doesn't work for me.&lt;br /&gt;&lt;br /&gt;Select "Tone" as the phone line type.&lt;br /&gt;&lt;br /&gt;Click on "Init Strings" and enter the following lines in Init2 and Init3 respectively.&lt;br /&gt;&lt;blockquote&gt;Init2:  ATQ0 V1 E1 S0=0 &amp;amp;C1 &amp;amp;D2 +FCLASS=0&lt;br /&gt;Init3:  AT+CGDCONT=1,"IP","internet.vodafone.net"&lt;br /&gt;&lt;/blockquote&gt;.. and uncheck "wait for dialtone"&lt;br /&gt;&lt;br /&gt;After I configured gnome-ppp  I tried to connect, I used *99***1# as the dial number, clicked connect, and see the log. And I got the pppd died unexpectedly error message, that very message traveled me back 12 years ago, trying and failing to make ppp work. My frustration didn't last more than 10 minutes, I figured out that gnome-ppp was trying and failed to open wvdial files in /etc/ppp/peers, so i searched the net and get me a bunch of wvdial conf files, put them in place and here are them.&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;# File: /etc/ppp/peers/wvdial&lt;br /&gt;# WvDial options&lt;br /&gt;#&lt;br /&gt;plugin passwordfd.so&lt;br /&gt;#&lt;br /&gt;noauth&lt;br /&gt;name wvdial&lt;br /&gt;defaultroute&lt;br /&gt;replacedefaultroute&lt;br /&gt;noipdefault&lt;br /&gt;usepeerdns&lt;br /&gt;novj&lt;br /&gt;&lt;/blockquote&gt;&lt;blockquote&gt;#File: /etc/wvdial.conf&lt;br /&gt;[Dialer Defaults]&lt;br /&gt;Modem = /dev/ttyS3&lt;br /&gt;Baud = 115200&lt;br /&gt;Init1 = ATZ&lt;br /&gt;Init2 = ATQ0 V1 E1 S0=0 &amp;amp;C1 &amp;amp;D2&lt;br /&gt;Init3 = AT+CGDCONT=1,"IP","internet.vodafone.net"&lt;br /&gt;Area Code =&lt;br /&gt;Phone = *99***1#&lt;br /&gt;Username = internet&lt;br /&gt;Password = internet&lt;br /&gt;Ask Password = 0&lt;br /&gt;Dial Command = ATDT&lt;br /&gt;Stupid Mode = 1&lt;br /&gt;Compuserve = 0&lt;br /&gt;Force Address =&lt;br /&gt;Idle Seconds = 3000&lt;br /&gt;DialMessage1 =&lt;br /&gt;DialMessage2 =&lt;br /&gt;ISDN = 0&lt;br /&gt;Auto DNS = 1&lt;br /&gt;&lt;br /&gt;[Dialer Another]&lt;br /&gt;Init3 = AT+CGDCONT=1,"IP","internet.vodafone.net"&lt;br /&gt;&lt;/blockquote&gt;And then i tried again, and it worked this time, it connects, and fetch the DNS and I browsed to google.com successfully. But for only 120 seconds. Excactly 120 secs every time i connect and then ppd dies unexpectedly, as the error keeps saying. I noticed after some more google results that two options called lcp-echo-interval and lcp-echo-failure and that one of them was set to 30 that's the interval and the other was set to 4 and that was the number of failure and then pppd should die if it didn't receive response. But when i set those options to 0 the connection get stable and didn't disconnect. Those lcp values should be (or i add them) to '/etc/ppp/options'.&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;###################&lt;br /&gt;# /etc/ppp/options&lt;br /&gt;###################&lt;br /&gt;asyncmap 0&lt;br /&gt;noauth&lt;br /&gt;crtscts&lt;br /&gt;lock&lt;br /&gt;hide-password&lt;br /&gt;modem&lt;br /&gt;proxyarp&lt;br /&gt;lcp-echo-interval 0&lt;br /&gt;lcp-echo-failure 0&lt;br /&gt;noipx&lt;br /&gt;novj&lt;br /&gt;&lt;/blockquote&gt;And that's it, now I can launch gnome-ppp and connect, but as a root. I created a gnome-ppp "gksu gnome-ppp" launcher on gnome panel.&lt;br /&gt;&lt;br /&gt;And I can launch it from command line by `wvdial`.&lt;br /&gt;&lt;br /&gt;The connection speed may not be the useful for real work, but it's faster&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Related links:&lt;/span&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://www.pharscape.org/index.php?option=content&amp;amp;task=view&amp;amp;id=29"&gt;GlobeTrotter (GPRS) Howto&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://andrewgee.org/blog/2007/08/07/vodafone-3g-card-in-ubuntu/"&gt;Vodafone 3G card in Ubuntu&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/974036606587739553-1160557401731482746?l=www.ibrahim-ahmed.com'/&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/IbrahimAhmed/~4/iWKnsM9kGjo" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.ibrahim-ahmed.com/feeds/1160557401731482746/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=974036606587739553&amp;postID=1160557401731482746" title="2 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/974036606587739553/posts/default/1160557401731482746?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/974036606587739553/posts/default/1160557401731482746?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/IbrahimAhmed/~3/iWKnsM9kGjo/making-gprs-vodafone-card-works-on.html" title="Making GPRS Vodafone card work on Ubuntu" /><author><name>Ibrahim Ahmed</name><uri>http://www.blogger.com/profile/01640528992428968621</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="05643959196373262770" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">2</thr:total><feedburner:origLink>http://www.ibrahim-ahmed.com/2008/03/making-gprs-vodafone-card-works-on.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DkAGSX05fyp7ImA9WxZWFU0.&quot;"><id>tag:blogger.com,1999:blog-974036606587739553.post-4577687379282045382</id><published>2008-03-04T00:10:00.001-08:00</published><updated>2008-03-14T07:25:28.327-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-03-14T07:25:28.327-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="web2.0" /><title>Web2.0 applications presentation</title><content type="html">I made a simple presentation to enumerate few of the web2.0 application that encourage community content contributions. There are hundreds of community driven web2.0 applications, I just named a few. I selected one applciation per content type.&lt;br /&gt;&lt;br /&gt;Blog services: &lt;a href="http://www.blogger.com/"&gt;www.blogger.com&lt;/a&gt;&lt;br /&gt;Photos: &lt;a href="http://www.flickr.com/"&gt;www.flickr.com&lt;/a&gt;&lt;br /&gt;Bookmarks:   &lt;a href="http://del.icio.us/"&gt;Del.icio.us&lt;/a&gt;&lt;br /&gt;Videos: &lt;a href="http://www.youtube.com"&gt;YouTube.com&lt;/a&gt;&lt;br /&gt;Podcasts: &lt;a href="http://www.odeo.com/"&gt;Odeo.com&lt;/a&gt;&lt;br /&gt;Presentations: &lt;a href="http://www.slideshare.net/"&gt;www.slideshare.net&lt;/a&gt;&lt;br /&gt;PDF documents: &lt;a href="http://www.scribd.com/"&gt;www.scribd.com&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;And of course the single most important web application is "Google Reader", which allows you to get the latest updates in one place.&lt;br /&gt;RSS Reader:  &lt;a href="http://www.google.com/reader"&gt;www.google.com/reader&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Two most important features in all the mentioned applications; first they all support RSS feeds so you can subscribe and get the latest updates; Second, you can embed the content you uploaded whither it's photos, links, video, presentations, or even pdf, you can embed all these type of content right into your blog. You only have to copy and paste the code from the content page.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="width: 425px; text-align: left;" id="__ss_291604"&gt;&lt;object style="margin: 0px;" height="355" width="425"&gt;&lt;param name="movie" value="http://static.slideshare.net/swf/ssplayer2.swf?doc=web2-0-1204618109656452-2"&gt;&lt;param name="allowFullScreen" value="true"&gt;&lt;param name="allowScriptAccess" value="always"&gt;&lt;embed src="http://static.slideshare.net/swf/ssplayer2.swf?doc=web2-0-1204618109656452-2" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" height="355" width="425"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;div style="font-size: 11px; font-family: tahoma,arial; height: 26px; padding-top: 2px;"&gt;&lt;a href="http://www.slideshare.net/?src=embed"&gt;&lt;img src="http://static.slideshare.net/swf/logo_embd.png" style="border: 0px none ; margin-bottom: -5px;" alt="SlideShare" /&gt;&lt;/a&gt; | &lt;a href="http://www.slideshare.net/ibrahimahmed/web2-0-291604?src=embed" title="View 'Web2 0' on SlideShare"&gt;View&lt;/a&gt; | &lt;a href="http://www.slideshare.net/upload?src=embed"&gt;Upload your own&lt;/a&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/974036606587739553-4577687379282045382?l=www.ibrahim-ahmed.com'/&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/IbrahimAhmed/~4/oDwNfQ6n25Y" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.ibrahim-ahmed.com/feeds/4577687379282045382/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=974036606587739553&amp;postID=4577687379282045382" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/974036606587739553/posts/default/4577687379282045382?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/974036606587739553/posts/default/4577687379282045382?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/IbrahimAhmed/~3/oDwNfQ6n25Y/web20-applications-presentation.html" title="Web2.0 applications presentation" /><author><name>Ibrahim Ahmed</name><uri>http://www.blogger.com/profile/01640528992428968621</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="05643959196373262770" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://www.ibrahim-ahmed.com/2008/03/web20-applications-presentation.html</feedburner:origLink></entry><entry gd:etag="W/&quot;C0MAQn84fip7ImA9WxNSEkU.&quot;"><id>tag:blogger.com,1999:blog-974036606587739553.post-6390075536706472504</id><published>2008-02-25T06:38:00.000-08:00</published><updated>2009-08-26T03:10:43.136-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-08-26T03:10:43.136-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="server" /><category scheme="http://www.blogger.com/atom/ns#" term="rails" /><title>Rails stack on Centos 5 with Nginx and memcached</title><content type="html">&lt;span&gt;This is yet another rails stack installation how to. It is useful for installing a production rails hosting environment using &lt;a href="http://nginx.net/"&gt;Nginx&lt;/a&gt; as the reverse proxy server for a mongrel cluster, using &lt;a href="http://www.danga.com/memcached"&gt;memcached&lt;/a&gt; as the caching server and mysql as the database server. Of course I am assuming that all these services will be installed in the same server for the sake of simplicity.&lt;br /&gt;&lt;/span&gt;&lt;span style="font-weight: bold;"&gt;&lt;br /&gt;Mysql&lt;/span&gt;&lt;br /&gt;Make sure that Mysql is installed correctly and ensure it is running on startup.&lt;br /&gt;&lt;blockquote&gt;sudo yum install mysql-server&lt;br /&gt;sudo yum install mysql&lt;br /&gt;sudo yum install mysql-devel&lt;br /&gt;sudo checkconfig --level 345 mysqld on&lt;br /&gt;&lt;/blockquote&gt;Note: In case you run mysql on a dedicated server then you need not to install Mysql in the application servers, but make sure you install at least mysql-devel because it contains header files needed for Mysql gem installation.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Memcached&lt;/span&gt;&lt;br /&gt;Memcache server needs livevent package as a dependency, so according to the deployment server system distribution we need to install the correct packages, in case of Centos 5 we are going to select the proper packages from Dag repositories from the following pages;&lt;br /&gt;&lt;blockquote&gt;http://dag.wieers.com/rpm/packages/libevent/&lt;br /&gt;http://dag.wieers.com/rpm/packages/memcached/&lt;br /&gt;&lt;/blockquote&gt;The following are the required steps to download and install memcached and libevent for centos 5.&lt;br /&gt;&lt;blockquote&gt;wget http://dag.wieers.com/rpm/packages/memcached/memcached-1.1.13-4.el5.rf.i386.rpm&lt;br /&gt;wget http://dag.wieers.com/rpm/packages/libevent/libevent-1.3b-1.el5.test.i386.rpm&lt;br /&gt;sudo rpm -ivh libevent-1.3b-1.el5.test.i386.rpm&lt;br /&gt;sudo rpm -ivh memcached-1.1.13-4.el5.rf.i386.rpm&lt;br /&gt;sudo /sbin/chkconfig --level 345 memcached on&lt;br /&gt;&lt;/blockquote&gt;memcached configuration could be found on /etc/sysconfig/memcached set the CACHESIZE to desired memory cache size you want.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:100%;" &gt;Nginx&lt;/span&gt;&lt;br /&gt;Get the latest nginx package tar, unpack it and configure it as follows. We need to install nginx required library first before configuring Nginx though. After compiling we need to copy nginx init script to /etc/init.d/nginx and give it execute permission.&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;sudo yum install pcre&lt;br /&gt;sudo yum install pcre-devel&lt;br /&gt;sudo yum install zlib&lt;br /&gt;sudo yum install zlib-devel&lt;br /&gt;sudo yum install openssl&lt;br /&gt;sudo yum install openssl-devel&lt;br /&gt;sudo ./configure --sbin-path=/usr/local/sbin --with-http_ssl_module --with-http_ssl_module --with-http_realip_module --with-http_addition_module --with-http_sub_module --with-http_dav_module --with-http_stub_status_module --with-mail --with-mail_ssl_module --with-cc-opt="-I /usr/include/pcre" --pid-path=/var/run/nginx.pid --lock-path=/var/lock/subsys/nginx --conf-path=/etc/nginx/nginx.conf&lt;br /&gt;make&lt;br /&gt;make install&lt;br /&gt;sudo cp nginx /etc/init.d/nginx&lt;br /&gt;sudo chmod +x /etc/init.d/nginx&lt;br /&gt;&lt;/blockquote&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-weight: bold;"&gt;Note:&lt;/span&gt; you can use this &lt;a href="http://brainspl.at/nginx.conf.txt"&gt;conf file&lt;/a&gt; as a base for nginx configuration&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Rubygems&lt;/span&gt;&lt;br /&gt;If rubygems is installed but needs update run the following&lt;br /&gt;&lt;blockquote&gt;sudo gem update --system&lt;br /&gt;&lt;/blockquote&gt;&lt;span&gt;If&lt;/span&gt;&lt;span&gt; not installed get the latest version from &lt;a href="http://rubyforge.org/frs/?group_id=126"&gt;here&lt;/a&gt;, unpack and install.&lt;br /&gt;&lt;blockquote&gt;ruby setup.rb&lt;br /&gt;&lt;/blockquote&gt;&lt;span style="font-weight: bold;"&gt;Rails, Ferret, Rake&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;blockquote&gt;&lt;span&gt;sudo gem install rails -y&lt;br /&gt;sudo gem install rake&lt;br /&gt;sudo gem install ferret&lt;/span&gt;&lt;br /&gt;&lt;/blockquote&gt;&lt;span style="font-weight: bold;"&gt;Mongrel&lt;/span&gt;&lt;br /&gt;&lt;blockquote&gt;sudo gem install mongrel&lt;br /&gt;&lt;/blockquote&gt;&lt;span style="font-weight: bold;"&gt;Mongrel Cluster&lt;/span&gt;&lt;br /&gt;Install Mongrel Cluster gem, and copy the service startup script and make sure it starts on system startup.&lt;br /&gt;&lt;blockquote&gt;sudo gem install mongrel_cluster&lt;br /&gt;sudo cp /usr/lib/ruby/gems/1.8/gems/mongrel_cluster-1.0.5/resources/mongrel_cluster /etc/init.d/&lt;br /&gt;sudo cp /usr/lib/ruby/gems/1.8/gems/mongrel_cluster-1.0.5/resources/default.yml /srv/webapp/config/mongrel_cluster.yml&lt;br /&gt;sudo /sbin/chkconfig --level 345 mongrel_cluster on&lt;br /&gt;&lt;/blockquote&gt;&lt;span&gt;You may need or should write your own mongrel_cluster configuration file, to define number of mongrel instances, user, group, port and other options. Here is an example:&lt;br /&gt;&lt;blockquote&gt;---&lt;br /&gt;cwd: /srv/webapp/&lt;br /&gt;port: "8000"&lt;br /&gt;environment: production&lt;br /&gt;address: 127.0.0.1&lt;br /&gt;pid_file: log/mongrel.pid&lt;br /&gt;servers: 8&lt;br /&gt;group: nginx&lt;br /&gt;user: nginx&lt;br /&gt;&lt;/blockquote&gt;You may need to add nginx user and group to your server&lt;br /&gt;&lt;blockquote&gt;/usr/sbin/useradd nginx&lt;br /&gt;&lt;/blockquote&gt;&lt;/span&gt;&lt;span style="font-weight: bold;"&gt;&lt;br /&gt;Mysql Ruby Driver&lt;/span&gt;&lt;br /&gt;We have to do a little more than gem install here, cause it seems that Redhat based distros are putting Mysql in a place not expected by the gem installer. So we are going to either explicitly give ‘gem install’ the location of lib headers and include for mysql, or soft linking the /usr/include/mysql and /usr/lib/mysql folders before ‘gem install’. (The soft link solution works well for me in most servers)&lt;br /&gt;&lt;blockquote&gt;sudo gem install mysql -- --with-mysql-include=/usr/include/mysql --with-mysql-lib=/usr/lib/mysql&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;update:&lt;/span&gt; New version of rubygems require double dash before the compiler configuration options.&lt;br /&gt;&lt;/blockquote&gt;OR&lt;br /&gt;&lt;blockquote&gt;sudo ln -s /usr/lib/mysql/ /usr/local/lib&lt;br /&gt;sudo ln -s /usr/include/mysql/ /usr/local/include/&lt;br /&gt;sudo gem install mysql&lt;br /&gt;&lt;/blockquote&gt;&lt;span style="font-weight: bold;"&gt;Memcached Ruby Driver&lt;/span&gt;&lt;br /&gt;&lt;blockquote&gt;sudo gem install memcache-client -y&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-weight: bold;"&gt;Related links:&lt;/span&gt;&lt;/span&gt;&lt;span style="font-weight: bold;font-size:85%;" &gt;&lt;br /&gt;&lt;/span&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://brainspl.at/articles/2006/09/12/new-nginx-conf-with-rails-caching"&gt;&lt;span style="font-size:85%;"&gt;New Nginx Conf with rails caching&lt;/span&gt;&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/974036606587739553-6390075536706472504?l=www.ibrahim-ahmed.com'/&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/IbrahimAhmed/~4/lB4emI3kG1Q" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.ibrahim-ahmed.com/feeds/6390075536706472504/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=974036606587739553&amp;postID=6390075536706472504" title="2 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/974036606587739553/posts/default/6390075536706472504?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/974036606587739553/posts/default/6390075536706472504?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/IbrahimAhmed/~3/lB4emI3kG1Q/rails-stack-on-centos-5-with-nginx-and.html" title="Rails stack on Centos 5 with Nginx and memcached" /><author><name>Ibrahim Ahmed</name><uri>http://www.blogger.com/profile/01640528992428968621</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="05643959196373262770" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">2</thr:total><feedburner:origLink>http://www.ibrahim-ahmed.com/2008/02/rails-stack-on-centos-5-with-nginx-and.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CkcASHc7eyp7ImA9WxZQGUg.&quot;"><id>tag:blogger.com,1999:blog-974036606587739553.post-1614529516399354780</id><published>2008-02-25T05:49:00.000-08:00</published><updated>2008-02-25T06:34:09.903-08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-02-25T06:34:09.903-08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="server" /><category scheme="http://www.blogger.com/atom/ns#" term="rails" /><title>Using Google to send mails from Rails</title><content type="html">I was using 'sendmail' for sending mails from my web applications. The apps was sending mails for welcome messages, comment notifications, activation mails, send to a friend and all other features depending on sending emails to the application user.  But recently, I was deploying a webapp on a server  in which sendmail is not configured correctly. I didn't have time and wouldn't like to invest any time on system administration then, so &lt;a href="http://www.igvita.com/2007/08/29/ssmtp-relay-mail-delivery-in-rails/"&gt;I searched&lt;/a&gt; for another solution for my webapps to send mails through Google. I found ssmtp.  It is a simple tool doing a simple task, sending mails. However it does not receive mail, expand aliases or manage a queue. It is just forwarding mails to the mailhost. SSMTP requires replacing 'sendmail'.&lt;br /&gt;&lt;br /&gt;There is nothing required from Rails app to use ssmtp, actually it was transparent. Just make sure that the ActionMailer is configured to use sendmail.&lt;br /&gt;&lt;blockquote&gt;ActionMailer::Base.delivery_method = :sendmail&lt;br /&gt;&lt;/blockquote&gt;&lt;span style="font-weight: bold;"&gt;SSMTP Installation&lt;/span&gt;&lt;br /&gt;In Ubuntu I use apt-get to install the package. I am enabling all the sources on my ubuntu, so you may need to do so. In RPM based distribution like Centos in my case i used &lt;a href="http://rpm.pbone.net/index.php3/stat/4/idpl/5288610/com/ssmtp-2.61-11.4.el5.i386.rpm.html"&gt;this link&lt;/a&gt; to download the required RPM.&lt;br /&gt;&lt;br /&gt;on Centos&lt;br /&gt;&lt;blockquote&gt;sudo wget ftp://mirror.switch.ch/mirror/epel/5/i386/ssmtp-2.61-11.4.el5.i386.rpm&lt;br /&gt;sudo rpm -ivh ssmtp-2.61-11.4.el5.i386.rpm&lt;br /&gt;&lt;/blockquote&gt;on Ubuntu.&lt;br /&gt;&lt;blockquote&gt;sudo apt-get install ssmtp&lt;br /&gt;&lt;/blockquote&gt;&lt;span style="font-weight: bold;"&gt;&lt;br /&gt;SSMTP Configuration&lt;/span&gt;&lt;br /&gt;SSMTP configuration files lie in /etc/ssmtp so you need to edit the conf file and fill it with the your gmail account.&lt;br /&gt;&lt;blockquote&gt;mailhub=smtp.gmail.com:587&lt;br /&gt;AuthUser=my_gmail_account@gmail.com&lt;br /&gt;AuthPass=my_gmail_password&lt;br /&gt;UseSTARTTLS=YES&lt;br /&gt;&lt;/blockquote&gt;There is one feature you will get by using Google as your SMTP server, it's its sent mail folder which archive every mail sent by your application, this feature being a bless or damn is up to your needs.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Related links:&lt;/span&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;RPM package for ssmtp from &lt;a href="http://rpm.pbone.net/index.php3/stat/4/idpl/5288610/com/ssmtp-2.61-11.4.el5.i386.rpm.html"&gt;RPM pbone.net&lt;/a&gt;&lt;/li&gt;&lt;li&gt;Igvita: &lt;a href="http://www.igvita.com/2007/08/29/ssmtp-relay-mail-delivery-in-rails/"&gt;ssmtp relay mail delivery in rails&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/974036606587739553-1614529516399354780?l=www.ibrahim-ahmed.com'/&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/IbrahimAhmed/~4/98ZtpAxQcRo" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.ibrahim-ahmed.com/feeds/1614529516399354780/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=974036606587739553&amp;postID=1614529516399354780" title="1 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/974036606587739553/posts/default/1614529516399354780?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/974036606587739553/posts/default/1614529516399354780?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/IbrahimAhmed/~3/98ZtpAxQcRo/using-google-to-send-mails-from-rails.html" title="Using Google to send mails from Rails" /><author><name>Ibrahim Ahmed</name><uri>http://www.blogger.com/profile/01640528992428968621</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="05643959196373262770" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">1</thr:total><feedburner:origLink>http://www.ibrahim-ahmed.com/2008/02/using-google-to-send-mails-from-rails.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CkMCSHw6eyp7ImA9WB9aFkg.&quot;"><id>tag:blogger.com,1999:blog-974036606587739553.post-3800563091601252604</id><published>2008-01-06T10:29:00.000-08:00</published><updated>2008-01-06T12:14:29.213-08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-01-06T12:14:29.213-08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Vim" /><title>Vim: Find and replace text across files</title><content type="html">Programmers almost always need the ability to find and replace certain text across multiple files in their projects. Most IDEs provide find and replace functionality. And there are many &lt;a href="http://www.google.com/search?hl=en&amp;amp;q=find+replace+tools"&gt;free tools online&lt;/a&gt; to just find and replace text across multiple files. Because I am using &lt;a href="http://www.vim.org/"&gt;Vim&lt;/a&gt; as my favorite editor for over 15 years now, it came natural to choose Vim for such job, and not depend on another tool.&lt;br /&gt;&lt;br /&gt;For a real life example, in one Rails project, I used caching in my view templates. I used a plugin to set an expiration time for the cache. I needed the cache function to look like:&lt;br /&gt;&lt;blockquote  style="font-family:courier new;"&gt;&lt;span style="font-size:100%;"&gt;&lt;% cache("sidebox_latest_news", :expire =&gt; 15.minutes.from_now) do %&gt;&lt;br /&gt;...&lt;br /&gt;&lt;% end %&gt;&lt;br /&gt;&lt;/span&gt;&lt;/blockquote&gt;I used this technique in about 25 of my templates. Then i decided not to use timed expiration of the cache. So I needed to remove the expire argument of the cache method. I needed to remove it from all of my 25 templates. I used Vim to find  the needed piece of text to be removed.&lt;br /&gt;&lt;br /&gt;In Vim, when we need to replace text in a file, we use the substitute command.&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;&lt;/span&gt;&lt;blockquote&gt;&lt;span style="font-family:courier new;"&gt;:s/old_text/new_text/&lt;/span&gt;&lt;br /&gt;&lt;/blockquote&gt;This should replace the first occurrence of "old_text" with "new_text" for the current cursor line. To substitute all matching occurrences in the line, just add the flag 'g' which refers to global. And to substitute all the file occurrences of the pattern, add the '%' before the substitute command.&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;&lt;blockquote&gt;:%s/old_text/new_text/g&lt;/blockquote&gt;&lt;/span&gt;Vim alerts if it didn't find the pattern, to disable the alert just append the flag 'e'.&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;&lt;blockquote&gt;:%s/old_text/new_text/ge&lt;/blockquote&gt;&lt;/span&gt;For a complete documentation for the substitute Vim command, use vim help.&lt;br /&gt;&lt;blockquote&gt;&lt;span style="font-family:courier new;"&gt;:help substitute&lt;/span&gt;&lt;/blockquote&gt;Now, after we knew how to substitute text in Vim, we need to substitute the expire argument. we cannot do without using &lt;a href="http://www.regular-expressions.info/quickstart.html"&gt;regular expressions&lt;/a&gt;. That's because the argument is not the same in all the files, it carries different time values, and may differ in spacing.&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;&lt;/span&gt;&lt;blockquote&gt;&lt;span style="font-family:courier new;"&gt;&lt;% cache("sidebox_related_reports", :expire =&gt; 1.hour.from_now) do %&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;    ...&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;&lt;% end %&gt;&lt;/span&gt;&lt;br /&gt;&lt;/blockquote&gt;So we need to match the whole argument from the comma at the start till the right parentheses and replace it with empty text. the regular expression we should use to match the argument is;&lt;br /&gt;&lt;blockquote style="font-family: courier new;"&gt;/, *:expire.+)/&lt;/blockquote&gt;I will quickly explain  the pattern above, but please refer to any of the &lt;a href="http://www.google.com/search?hl=en&amp;amp;q=regular+expression+tutorial"&gt;many tutorials online&lt;/a&gt; about Regular expression for more details. The pattern starts with a comma which is the start of the text we need to remove. Followed by a space and a '*' which means a comma followed by zero or more spaces then ':expire' followed by "one or more" "character". And finally the pattern ended with a right parentheses. So our pattern starts with a comma and ends with a right parentheses. Any text matching this pattern in all templates files should be replaced with empty text, or to be specific, with a right parentheses, as the parentheses is already part of the text to be removed.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_kaErP_wP6ns/R4EtmfZpZZI/AAAAAAAAABM/4uI94MSEUtE/s1600-h/vim_find_replace.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://2.bp.blogspot.com/_kaErP_wP6ns/R4EtmfZpZZI/AAAAAAAAABM/4uI94MSEUtE/s400/vim_find_replace.png" alt="" id="BLOGGER_PHOTO_ID_5152449587975906706" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;To apply Vim command to all the templates files, I will use the 'args' command. I will pass all the templates files in the app/views folder to 'args' using &lt;a href="http://en.wikipedia.org/wiki/Wildcard_character"&gt;wildcards&lt;/a&gt;, and because Rails store the templates files grouped in folders named after their controllers I will use double wildcard 'app/views/*/*' to list the files 2 levels deep under app/views folder.&lt;br /&gt;&lt;br /&gt;After I passed the required files to 'args', I can apply whatever command I like to all these files using the command 'argdo'. First I will apply the substitute 's' command and then 'update' which will only save the modified files.&lt;br /&gt;&lt;blockquote style="font-family: courier new;"&gt;:args app/views/*/*&lt;br /&gt;:argdo %s/, :expire.*)/)/ge | update&lt;br /&gt;&lt;/blockquote&gt;Finally, another neat option is adding the flag 'c' which will ask confirmation before each substitution.&lt;br /&gt;&lt;blockquote style="font-family: courier new;"&gt;:argdo %s/, :expire.*)/)/gec | update&lt;br /&gt;&lt;/blockquote&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/974036606587739553-3800563091601252604?l=www.ibrahim-ahmed.com'/&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/IbrahimAhmed/~4/xxuXm1IXuo0" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.ibrahim-ahmed.com/feeds/3800563091601252604/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=974036606587739553&amp;postID=3800563091601252604" title="12 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/974036606587739553/posts/default/3800563091601252604?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/974036606587739553/posts/default/3800563091601252604?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/IbrahimAhmed/~3/xxuXm1IXuo0/find-and-replace-in-multiple-files-in.html" title="Vim: Find and replace text across files" /><author><name>Ibrahim Ahmed</name><uri>http://www.blogger.com/profile/01640528992428968621</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="05643959196373262770" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://2.bp.blogspot.com/_kaErP_wP6ns/R4EtmfZpZZI/AAAAAAAAABM/4uI94MSEUtE/s72-c/vim_find_replace.png" height="72" width="72" /><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">12</thr:total><feedburner:origLink>http://www.ibrahim-ahmed.com/2008/01/find-and-replace-in-multiple-files-in.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DE8BSHo7eyp7ImA9WB9aFkk.&quot;"><id>tag:blogger.com,1999:blog-974036606587739553.post-2758791101942076285</id><published>2007-09-02T03:40:00.000-07:00</published><updated>2008-01-06T11:14:19.403-08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-01-06T11:14:19.403-08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="RubyonRails" /><category scheme="http://www.blogger.com/atom/ns#" term="Ruby" /><title>What makes Ruby better than Java and PHP?</title><content type="html">Ruby by itself is not better than Java or PHP. Ruby is just a general purpose computer language. Each Language has its advantages and disadvantages, that's why it is  according to the project you will undertake you should choose the better language that suits your needs.&lt;br /&gt;&lt;br /&gt;For myself, I use &lt;a href="http://www.ruby-lang.org/"&gt;Ruby&lt;/a&gt; in Web development. Cause the web development is very dynamic, every day you have new requirements that's why I prefer to use a language like Ruby that's make me develop more with simple code, and most important I like Ruby's elegantly clever syntax.&lt;br /&gt;&lt;br /&gt;But again without a great framework like &lt;a href="http://www.rubyonrails.org/"&gt;RubyOnRails&lt;/a&gt; I wouldn't use Ruby. Ruby on rails gives you everything you need from the begining, so you do not have to prepare all your tools just to start. I mean when you start a rails project you will have a &lt;a href="http://wiki.rubyonrails.org/rails/pages/ActiveRecord"&gt;Object&lt;/a&gt; &lt;a href="http://en.wikipedia.org/wiki/Object-relational_mapping"&gt;Relational&lt;/a&gt; &lt;a href="http://en.wikipedia.org/wiki/Active_record_pattern"&gt;Mapping&lt;/a&gt;,  &lt;a href="http://en.wikipedia.org/wiki/Unit_testing"&gt;Unit  testing&lt;/a&gt; &lt;a href="http://www.ruby-doc.org/stdlib/libdoc/test/unit/rdoc/classes/Test/Unit.html"&gt;system&lt;/a&gt;, &lt;a href="http://en.wikipedia.org/wiki/Web_application_framework#URL_mapping"&gt;URL Mapping&lt;/a&gt;, MVC structure, templating system, caching, &lt;a href="http://wiki.script.aculo.us/scriptaculous/show/Demos"&gt;Ajax&lt;/a&gt;, webservices, emailer, tasks runner, &lt;a href="http://slash7.com/articles/2006/12/21/secrets-of-the-rails-console-ninjas"&gt;command prompt console&lt;/a&gt;, and tens of other useful stuff that you otherwise spend a considerable amount of your project time trying to setup if you don't use a &lt;a href="http://en.wikipedia.org/wiki/Web_application_framework"&gt;decent framework&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;That said, there are decent frameworks in &lt;a href="http://en.wikipedia.org/wiki/Web_application_framework#Languages"&gt;Java and PHP&lt;/a&gt; that can do the same as Rails, like PHP &lt;a href="http://www.blogger.com/www.cakephp.org"&gt;CackePHP&lt;/a&gt;, and &lt;a href="http://grails.codehaus.org/"&gt;Grails&lt;/a&gt; for java. But It's &lt;a href="http://www.rubyonrails.org/"&gt;Rails&lt;/a&gt; who get all the hype because it is the one who really made it eaiser for developer to make professional websites.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/974036606587739553-2758791101942076285?l=www.ibrahim-ahmed.com'/&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/IbrahimAhmed/~4/iYBCsHyRgMs" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.ibrahim-ahmed.com/feeds/2758791101942076285/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=974036606587739553&amp;postID=2758791101942076285" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/974036606587739553/posts/default/2758791101942076285?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/974036606587739553/posts/default/2758791101942076285?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/IbrahimAhmed/~3/iYBCsHyRgMs/what-makes-ruby-better-than-java-and.html" title="What makes Ruby better than Java and PHP?" /><author><name>Ibrahim Ahmed</name><uri>http://www.blogger.com/profile/01640528992428968621</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="05643959196373262770" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://www.ibrahim-ahmed.com/2007/09/what-makes-ruby-better-than-java-and.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DE8GQ3k4eip7ImA9WB9aFkk.&quot;"><id>tag:blogger.com,1999:blog-974036606587739553.post-2775540628036037455</id><published>2007-07-05T00:22:00.000-07:00</published><updated>2008-01-06T11:13:42.732-08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-01-06T11:13:42.732-08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Tools" /><category scheme="http://www.blogger.com/atom/ns#" term="Deployment" /><title>Subversion, SSH and Capistrano for a fully automated deployment</title><content type="html">&lt;span&gt;Deployment could be defined as; uploading an application to the hosting server and make any required modification or configuration to the file system, web server, database server, or whatever for the application to run properly.&lt;br /&gt;&lt;br /&gt;For deployment, I use &lt;a href="http://manuals.rubyonrails.com/read/book/17"&gt;Capistrano&lt;/a&gt;, &lt;a href="http://subversion.tigris.org/"&gt;Subversion&lt;/a&gt; and &lt;a href="http://www.chiark.greenend.org.uk/%7Esgtatham/putty/download.html"&gt;Putty&lt;/a&gt;. Notice that I did not mention an FTP client. My minimal typical hosting environment consists of at least one instance of production web server and another instance as a staging web server, and each of them has its own file structure spanning to more than 3 levels and all the web servers are behind a reverse proxy server as the front end for web request, and I may run clusters of these instances. It could take me more than 10 minutes to do but the simplest tasks of deployment, like updating 3 files in 2 different folders, for example. As simple as it seems, but that kind of task is troublesome, especially that after uploading those files in their respective paths, and preview the updates on the staging server, and iterating a little bit in a preview, comments, fix, deploy loop, and finally redeploy in the production server, and restart the cluster instances. Well, at best, if half of your brain is actually a computer machine and you didn't make any silly overwrite or other nasty stuff to your application, your other brain half will get bored of these brain dead repetitive tasks, or you will simply screw yourself bad when you break your production hosting environment or worse destroy your production database.&lt;br /&gt;&lt;br /&gt;We have to admit it; a programmer should always train himself to automate everything repetitive and boring he does, in order to spare his brain power on otherwise useful stuff that needs his attention like application architecture design and algorithms. Or simply to spare the world the kind of destruction our minds able to do when faced with boring repetitive tasks. This is a very popular concept which is called DRY, abbreviation of &lt;a href="http://en.wikipedia.org/wiki/Don%27t_repeat_yourself"&gt;Don't Repeat Yourself&lt;/a&gt;.&lt;span style="font-size:130%;"&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Subversion&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;I believe that the centerpiece of any successful and decently automated deployment lies in the Version Control tool you use. Coupled with a decent SSH client and you're up to the deployment task. I use &lt;a href="http://subversion.tigris.org/"&gt;Subversion&lt;/a&gt;. It really makes my life easier. Imagine the following scenario;&lt;br /&gt;•    Write your application&lt;br /&gt;•    Import it to your online code repository.&lt;br /&gt;•    Continuously commit any changes you do in your application to your code repository.&lt;br /&gt;•    Need to deploy a development server; just check out a version of your application from the repository&lt;br /&gt;•    Changed anything in your application; just update your development server with any recent changes, and it will be in sync with your latest application code.&lt;br /&gt;•    Satisfied with your current development version, make a release tag in your code repository, and check out this version to a new production server.&lt;br /&gt;•    Need fixing, change the code, commit it, update your hosting server.&lt;br /&gt;•    Did a bad decision and decided to go back to a previous version; just update your application to the required version.&lt;br /&gt;&lt;br /&gt;It is even simpler than it sounds. All these steps are done using simple commands like;&lt;br /&gt;On local system:&lt;br /&gt;$ mkdir myapp&lt;br /&gt;$ cd myapp&lt;br /&gt;$ svn import http://svn.myrepository.com/myapp&lt;br /&gt;$ echo "puts 'hello'" &gt; hello.rb&lt;br /&gt;$ svn add hello.rb&lt;br /&gt;$ svn commit hello.rb -m "Added Hello module that says hello"&lt;br /&gt;On hosting server using secure shell:&lt;br /&gt;$ svn checkout hello&lt;br /&gt;$ svn update&lt;br /&gt;$ svn update –r  $required_revision_number&lt;br /&gt;&lt;br /&gt;The beauty of this process of check in, check out, commit and update, is that you do not have to keep track which files are changed and need to be uploaded, or worse upload all your application folder each time you make an update.&lt;br /&gt;&lt;br /&gt;Useful link: &lt;a href="http://www.germane-software.com/%7Eser/R_n_R/subversion.html"&gt;A Novices Tutorial on Subversion&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;Capistrano&lt;br /&gt;&lt;/span&gt;&lt;a href="http://manuals.rubyonrails.com/read/book/17"&gt;Capistrano &lt;/a&gt;is the deployment tool i use for deploying my Rails applications on the hosting server. As quoted from Capistrano manual; Application deployment is one of those things that becomes more and more complicated as the scale of your application increases. With just a single box running your database and your application, it’s quite simple. But when you start putting your database on a different server, and then separating your web servers from your app servers, and eventually splitting your database into master and slave servers… It can get to where you almost don’t want to deploy your application any more.&lt;br /&gt;&lt;br /&gt;Simply put, Capistrano makes it even easier to do tasks like fire up your ssh client, type some commands on the remote server to move, update, restart, or whatever task you would normally do by hand, you can write your commands in a script called "recipe" for Capistrano and as the next decent software, it will submit to your command and do every task you tell it to do.&lt;br /&gt;&lt;br /&gt;Tasks like; login to remote server, update your application code, migrate your database, restart your server , are very likely will be repeated over and over, and that should notify you to start a new recipe for Capistrano to cook at your command.&lt;br /&gt;&lt;br /&gt;Useful link: &lt;a href="http://manuals.rubyonrails.com/export/html/17"&gt;Capistrano: Automating Application Deployment&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;Putty&lt;/span&gt;&lt;br /&gt;I like &lt;a href="http://www.chiark.greenend.org.uk/%7Esgtatham/putty/download.html"&gt;Putty&lt;/a&gt;, it is a secure shell client. Nothing bad with openssh client, but when i use Windows, it's pathetic command prompt console leave no choice but to use Putty with its own terminal window. By the way, I wonder why for God sake, there is no any alternatives for the bloody windows command prompt console, is there any out there? And I mean terminal or console not just another shell, cause i found many (Cygwin, bash, sh). [&lt;span style="font-weight: bold;"&gt;update:&lt;/span&gt; I found a great console for Windows, it is called &lt;a href="http://sourceforge.net/projects/console/"&gt;Console&lt;/a&gt;. It is a great tool, it even support transparent background! when used with &lt;a href="http://unxutils.sourceforge.net/"&gt;unix tools&lt;/a&gt; like sh, tar, cp, rm...etc and all you unix geeks will find yourself almost at home.]&lt;br /&gt;&lt;br /&gt;Among the servers of the hosting data center we have at work, there is only one server that open a Secure Shell port to the internet. For a hosting data center, this is not a good idea. But we have to have a remote shell to login to, in case of emergencies or remote administration. My system admin collegue at work, had generated a pair key for my account on the hosting server. And that was a good idea. Because, it requires a private key for your account on the linux box for you to be able to login. No username/password login prompt anymore. &lt;a href="http://www.unixwiz.net/techtips/putty-openssh.html"&gt;This technique&lt;/a&gt; is both secure and easier than the regular login procedure.&lt;br /&gt;&lt;br /&gt;Using key authorization is very useful if you intend to use any kind of automated deployment tools. Because such tools will almost always use key authenticated secure shell for login to the deployment server. And scattering your username/password all over your deployment scripts is not something you should do if you care about your hosting server security.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/974036606587739553-2775540628036037455?l=www.ibrahim-ahmed.com'/&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/IbrahimAhmed/~4/J4PFb4Fzhy0" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.ibrahim-ahmed.com/feeds/2775540628036037455/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=974036606587739553&amp;postID=2775540628036037455" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/974036606587739553/posts/default/2775540628036037455?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/974036606587739553/posts/default/2775540628036037455?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/IbrahimAhmed/~3/J4PFb4Fzhy0/subversion-ssh-and-capistrano-for-fully.html" title="Subversion, SSH and Capistrano for a fully automated deployment" /><author><name>Ibrahim Ahmed</name><uri>http://www.blogger.com/profile/01640528992428968621</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="05643959196373262770" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://www.ibrahim-ahmed.com/2007/07/subversion-ssh-and-capistrano-for-fully.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DUUHQnk7eSp7ImA9WBFSF04.&quot;"><id>tag:blogger.com,1999:blog-974036606587739553.post-1363103060367985124</id><published>2007-02-17T10:14:00.000-08:00</published><updated>2007-02-17T10:33:53.701-08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2007-02-17T10:33:53.701-08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="notes" /><title>My first post</title><content type="html">Here is my first post. I hesitated many times before I started my blog, but it seems that you cannot avoid it, cause it will happen sooner or later. I worked as a web developer for so many years now. And I believe in specializing, so I chose to write about technologies  used in web development as my specialty. But that will not prevent some posts about my personal life,  work, habits, or whatever, to find its way into this blog. So, see you at my next post...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/974036606587739553-1363103060367985124?l=www.ibrahim-ahmed.com'/&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/IbrahimAhmed/~4/WH96KR1BGDE" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.ibrahim-ahmed.com/feeds/1363103060367985124/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=974036606587739553&amp;postID=1363103060367985124" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/974036606587739553/posts/default/1363103060367985124?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/974036606587739553/posts/default/1363103060367985124?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/IbrahimAhmed/~3/WH96KR1BGDE/my-first-post.html" title="My first post" /><author><name>Ibrahim Ahmed</name><uri>http://www.blogger.com/profile/01640528992428968621</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="05643959196373262770" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://www.ibrahim-ahmed.com/2007/02/my-first-post.html</feedburner:origLink></entry></feed>
