<?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:blogger="http://schemas.google.com/blogger/2008" xmlns:georss="http://www.georss.org/georss" xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr="http://purl.org/syndication/thread/1.0" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" gd:etag="W/&quot;DEIGQ3c5cCp7ImA9WhJQEko.&quot;"><id>tag:blogger.com,1999:blog-29550948</id><updated>2012-07-26T06:22:02.928+02:00</updated><title>Ideas on Rails</title><subtitle type="html">Yet another Ruby on Rails blog</subtitle><link rel="http://schemas.google.com/g/2005#feed" type="application/atom+xml" href="http://ideasonrails.blogspot.com/feeds/posts/default" /><link rel="alternate" type="text/html" href="http://ideasonrails.blogspot.com/" /><author><name>Miklos Hollender</name><uri>https://plus.google.com/115958585642627138981</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh6.googleusercontent.com/-2T13A4yRgsg/AAAAAAAAAAI/AAAAAAAAA40/WeFTpw1MeME/s512-c/photo.jpg" /></author><generator version="7.00" uri="http://www.blogger.com">Blogger</generator><openSearch:totalResults>1</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/atom+xml" href="http://feeds.feedburner.com/IdeasOnRails" /><feedburner:info uri="ideasonrails" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><entry gd:etag="W/&quot;DEcEQXk8eCp7ImA9WBNTEEs.&quot;"><id>tag:blogger.com,1999:blog-29550948.post-115002825546670487</id><published>2006-06-11T13:55:00.000+02:00</published><updated>2006-06-12T00:46:40.770+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2006-06-12T00:46:40.770+02:00</app:edited><title>Rewriting Reddit in Rails in less than 20 minutes</title><content type="html">&lt;div style="text-align: justify;"&gt;I recently watched Sven Van Caekenberghe's excellent &lt;a href="http://homepage.mac.com/svc/LispMovies/index.html"&gt; video &lt;/a&gt; on how to write a web app like &lt;a href="http://reddit.com"&gt;Reddit&lt;/a&gt; in LISP in 20 minutes.&lt;br /&gt;&lt;br /&gt;I'd like to demonstrate here that you can do the same thing in &lt;a href="http://rubyonrails.org"&gt;Ruby on Rails&lt;/a&gt; in a lot friendlier, lot more readable way.&lt;br /&gt;&lt;br /&gt;So, in this little tutorial, we will write an app which allows you to&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;ol style="text-align: justify;"&gt;&lt;li&gt;submit links&lt;/li&gt;&lt;li&gt;view links sorted by points voted or by date/time of submission ("hot" and "new")&lt;/li&gt;&lt;li&gt;vote links up or down (with AJAX, to avoid reloading the whole page)&lt;br /&gt;&lt;/li&gt;&lt;/ol&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;We don't add advanced features like user accounts, or checking that users should not vote on a link more than once, because that would be out of the limits of this little tutorial.&lt;br /&gt;&lt;br /&gt;Here's a screenshot of what we gonna do:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://photos1.blogger.com/blogger/7182/2506/1600/redditonrails.1.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: left; cursor: pointer;" src="http://photos1.blogger.com/blogger/7182/2506/320/redditonrails.0.jpg" alt="" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;The basics&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;I won't go into details about the basics of Rails, because there are a good number of &lt;a href="http://rubyonrails.org/docs"&gt;tutorials&lt;/a&gt; for that out there, so I'll cover the basics only in a nutshell.&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;ol style="text-align: justify;"&gt;&lt;li&gt;Install Rails&lt;/li&gt;&lt;li&gt;Install a database server&lt;/li&gt;&lt;li&gt;Start a new Rails app&lt;/li&gt;&lt;li&gt;Set up database connection&lt;/li&gt;&lt;li&gt;Generate a migration file&lt;/li&gt;&lt;li&gt;Modify it this way:&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://photos1.blogger.com/blogger/7182/2506/1600/migr.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://photos1.blogger.com/blogger/7182/2506/320/migr.jpg" alt="" border="0" /&gt;&lt;/a&gt;&lt;/li&gt;&lt;li&gt;Run the migration&lt;/li&gt;&lt;li&gt;Generate scaffold for Link&lt;/li&gt;&lt;li&gt;Start the server&lt;br /&gt;&lt;/li&gt;&lt;li&gt; Go to http://localhost:3000/links and play around with adding a few links. Note that Rails populates the created_at field automatically.&lt;br /&gt;&lt;/li&gt;&lt;/ol&gt;&lt;div style="text-align: justify;"&gt;When you are finished, let's start the real development. We will leave the generated scaffolding mostly alone, because I think that's useful as an admin interface.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;Defining the actions that will respond to the requests&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Go to &lt;span style="font-weight: bold;"&gt;links_controller.rb&lt;/span&gt; and add the following two methods:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://photos1.blogger.com/blogger/7182/2506/1600/controller.0.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://photos1.blogger.com/blogger/7182/2506/320/controller.0.jpg" alt="" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;The submissions controller shows the list of links. Either "hot" or "new" links, both are handled by the same controller, as they are only different in ordering and in header text. In the first line, we extract requested ordering from the request parameters and default it to 'hot' if not supplied.&lt;br /&gt;&lt;br /&gt;Then we create the appropriate SQL snippet for ordering, it's worhty to note that we are using case-when as an expression, instead of as a statement, LISP style.&lt;br /&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;Then we call the Rails paginator class that pulls the data from our database into the @links instance variable, each by pages of 20.&lt;br /&gt;&lt;br /&gt;In the next line we set the header text of our page and also save it in an instance variable.&lt;br /&gt;&lt;br /&gt;The modify_points method handles ranking links up and down. This method expects two request parameters. An "id" parameter for the id of the link, and the amount of points to assign in the "by". We enforce the "by" parameter to be either "1", "+1" or "-1" by a regex to protect against dirty tricks, and then update the points in the database.&lt;br /&gt;&lt;br /&gt;This is an AJAX method, therefore this method does not render a view, but sends the updated number of points back to the original (submissions) view by a render_text call.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;Defining the view&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Add &lt;span style="font-weight: bold;"&gt;submissions.rhtml&lt;/span&gt; to the link view with the following content:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://photos1.blogger.com/blogger/7182/2506/1600/view1.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://photos1.blogger.com/blogger/7182/2506/320/view1.jpg" alt="" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;In the first line, we are including the default JavaScript libraries that let us use AJAX for updating the points. Then we display the header text we set in the controller class, and add the three links for showing records ordered either by points or the date of submission, and a link fo  submitting a new link. All three links point to methods defined in our controller class, the first both of the also supplying the "order" parameter required by our submissions method.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://photos1.blogger.com/blogger/7182/2506/1600/view2.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://photos1.blogger.com/blogger/7182/2506/320/view2.jpg" alt="" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Here we are looping through the list of link objects (records) supplied by the controller class in the @links variable. For each link, we generate a table row. The first two cell contain the links for voting up or down.&lt;br /&gt;&lt;br /&gt;The link_to_remote method called here is actually the AJAX call. What we actually do is to run the modify_points method of the controller class, supply the parameters it expects, and remotely update a part of our page without reloading it by the text rendered by our method. What we are updating is the element in the page DOM whose identifier is "link" + the id of the link, such as "link1" or "link567". This element is defined later.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://photos1.blogger.com/blogger/7182/2506/1600/view3.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://photos1.blogger.com/blogger/7182/2506/320/view3.jpg" alt="" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;And here comes our link. We also extract the domain of the link with a regex and print it in parens, just like Reddit.&lt;br /&gt;&lt;br /&gt;The other half of the AJAX trick is in the next line. What we do is we define a span element, and give it the identifier "link" + the id of the link. This span contains the number of points - this is the DOM element what our link_to_remote will update.&lt;br /&gt;&lt;br /&gt;In the next line, the helpful time_ago_in_words Rails method prints how long ago the link was submitted in a user-friendly way, and then we only set the previous/next paging links and we are done.&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;&lt;br /&gt;Finishing touches&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;We only need a few touches to finish our app. Go to _form.rhtml and delete the four lines containing "points" and "created_at" - we don't want our users to be able to edit it. Go to new.rhtml and change the "Back" link to link to "submissions" instead of "list". Go to the controller and change the redirect_to in the create controller to redirect to "submissions" instead of "list".&lt;br /&gt;&lt;br /&gt;And now you are done - go to http://localhost:3000/links/submissions and try out your shining new Reddit!&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.box.net/public/7hzp473uv9"&gt;Download the source&lt;/a&gt;&lt;br /&gt;(Thanks to Box.net!)&lt;br /&gt;&lt;br /&gt;Any questions?&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/IdeasOnRails/~4/rqx6fw1NJaE" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://ideasonrails.blogspot.com/feeds/115002825546670487/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=29550948&amp;postID=115002825546670487" title="24 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/29550948/posts/default/115002825546670487?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/29550948/posts/default/115002825546670487?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/IdeasOnRails/~3/rqx6fw1NJaE/rewriting-reddit-in-rails-in-less-than.html" title="Rewriting Reddit in Rails in less than 20 minutes" /><author><name>Miklos Hollender</name><uri>https://plus.google.com/115958585642627138981</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh6.googleusercontent.com/-2T13A4yRgsg/AAAAAAAAAAI/AAAAAAAAA40/WeFTpw1MeME/s512-c/photo.jpg" /></author><thr:total>24</thr:total><feedburner:origLink>http://ideasonrails.blogspot.com/2006/06/rewriting-reddit-in-rails-in-less-than.html</feedburner:origLink></entry></feed>
