<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	xmlns:creativeCommons="http://backend.userland.com/creativeCommonsRssModule">

<channel>
	<title>Thinking Inside a Bigger Box &#187; Ruby-on-Rails</title>
	<atom:link href="http://johannesbrodwall.com/category/ruby-on-rails/feed/" rel="self" type="application/rss+xml" />
	<link>http://johannesbrodwall.com</link>
	<description>Johannes Brodwall&#039;s Musings on Software Architecture and Programming</description>
	<lastBuildDate>Mon, 03 May 2010 20:24:08 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.2</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<creativeCommons:license>http://creativecommons.org/licenses/by/3.0/</creativeCommons:license>		<item>
		<title>Rails #6: Grant edit access to select users</title>
		<link>http://johannesbrodwall.com/2008/05/31/rails-6-authorization/</link>
		<comments>http://johannesbrodwall.com/2008/05/31/rails-6-authorization/#comments</comments>
		<pubDate>Sat, 31 May 2008 15:57:33 +0000</pubDate>
		<dc:creator>Johannes Brodwall</dc:creator>
				<category><![CDATA[Ruby-on-Rails]]></category>

		<guid isPermaLink="false">http://www.brodwall.com/johannes/blog/2008/05/31/rails-6-grant-edit-access-to-select-users/</guid>
		<description><![CDATA[In my last article, I showed how to implement authentication with Ruby on Rails. But security is about more than simple login. For many applications, we want to grant permission to manipulate a resource to a set of users. In this article, I will guide you though adding functionality so that users can modify the [...]]]></description>
			<content:encoded><![CDATA[<p>In my last article, I showed how to implement authentication with Ruby on Rails. But security is about more than simple login. For many applications, we want to grant permission to manipulate a resource to a set of users. In this article, I will guide you though adding functionality so that users can modify the permissions for who gets to edit an article.</p>
<p>Before we start implementing access control, we should get our application ready by encapsulating all access control checks. First, in <code>app/helpers/login_sessions_helper.rb</code>, change <code>current_user_can_edit</code> to the following (WILL BREAK):</p>

<div class="wp_syntax"><div class="code"><pre class="rails" style="font-family:monospace;">  <span style="color:#9966CC; font-weight:bold;">def</span> current_user_can_edit article
    current_user <span style="color:#9966CC; font-weight:bold;">and</span> current_user.<span style="color:#9900CC;">can_edit</span>? article
  <span style="color:#9966CC; font-weight:bold;">end</span></pre></div></div>

<p>This means that we need to implement User.can_edit?. For now, just use the previous code from the helper:</p>

<div class="wp_syntax"><div class="code"><pre class="rails" style="font-family:monospace;"><span style="color:#9966CC; font-weight:bold;">class</span> User
  <span style="color:#008000; font-style:italic;"># ...</span>
  <span style="color:#9966CC; font-weight:bold;">def</span> can_edit? article
    article.<span style="color:#9900CC;">user_id</span> == <span style="color:#0000FF; font-weight:bold;">self</span>.<span style="color:#9900CC;">id</span>
  <span style="color:#9966CC; font-weight:bold;">end</span>
<span style="color:#9966CC; font-weight:bold;">end</span></pre></div></div>

<p>Finally, make sure we use the same access check in <code>app/controllers/articles_controller.rb</code> (notice that the filters for edit, update and delete require a user who can edit the article, but new and create only checks that the user is logged in):</p>

<div class="wp_syntax"><div class="code"><pre class="rails" style="font-family:monospace;"><span style="color:#9966CC; font-weight:bold;">class</span> ArticlesController <span style="color:#006600; font-weight:bold;">&lt;</span> ApplicationController
&nbsp;
  <span style="color:#5A0A0A; font-weight:bold;">before_filter</span> <span style="color:#ff3333; font-weight:bold;">:can_edit</span>, <span style="color:#ff3333; font-weight:bold;">:only</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#006600; font-weight:bold;">&#91;</span> <span style="color:#ff3333; font-weight:bold;">:edit</span>, <span style="color:#ff3333; font-weight:bold;">:update</span>, <span style="color:#ff3333; font-weight:bold;">:delete</span> <span style="color:#006600; font-weight:bold;">&#93;</span>
  <span style="color:#5A0A0A; font-weight:bold;">before_filter</span> <span style="color:#ff3333; font-weight:bold;">:verify_logged_in</span>, <span style="color:#ff3333; font-weight:bold;">:only</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#006600; font-weight:bold;">&#91;</span> <span style="color:#ff3333; font-weight:bold;">:new</span>, <span style="color:#ff3333; font-weight:bold;">:create</span> <span style="color:#006600; font-weight:bold;">&#93;</span>
&nbsp;
  <span style="color:#008000; font-style:italic;"># ...</span>
  <span style="color:#008000; font-style:italic;"># All actions go here</span>
&nbsp;
private
  <span style="color:#9966CC; font-weight:bold;">def</span> can_edit
    <span style="color:#0066ff; font-weight:bold;">@article</span> = Article.<span style="color:#9900CC;">find</span><span style="color:#006600; font-weight:bold;">&#40;</span>params<span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#ff3333; font-weight:bold;">:id</span><span style="color:#006600; font-weight:bold;">&#93;</span><span style="color:#006600; font-weight:bold;">&#41;</span>
    <span style="color:#9966CC; font-weight:bold;">unless</span> <span style="color:#0066ff; font-weight:bold;">@article</span> <span style="color:#9966CC; font-weight:bold;">and</span> current_user <span style="color:#9966CC; font-weight:bold;">and</span> current_user.<span style="color:#9900CC;">can_edit</span>? <span style="color:#0066ff; font-weight:bold;">@article</span>
      redirect_to_login
    <span style="color:#9966CC; font-weight:bold;">end</span>
  <span style="color:#9966CC; font-weight:bold;">end</span>
<span style="color:#9966CC; font-weight:bold;">end</span></pre></div></div>

<p>Implement <code>redirect_to_login</code in <code>app/controllers/application.rb</code>:</p>

<div class="wp_syntax"><div class="code"><pre class="rails" style="font-family:monospace;"><span style="color:#9966CC; font-weight:bold;">class</span> ApplicationController <span style="color:#006600; font-weight:bold;">&lt;</span> <span style="color:#6666ff; font-weight:bold;">ActionController::Base</span>
  <span style="color:#008000; font-style:italic;"># ...</span>
&nbsp;
  <span style="color:#9966CC; font-weight:bold;">def</span> redirect_to_login
    <span style="color:#5A0A0A; font-weight:bold;">flash</span><span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#ff3333; font-weight:bold;">:notice</span><span style="color:#006600; font-weight:bold;">&#93;</span> = <span style="color:#996600;">&quot;You must login in to do this&quot;</span>
    <span style="color:#5A0A0A; font-weight:bold;">session</span><span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#ff3333; font-weight:bold;">:redirect_after_login</span><span style="color:#006600; font-weight:bold;">&#93;</span> = request.<span style="color:#9900CC;">request_uri</span>
    <span style="color:#5A0A0A; font-weight:bold;">redirect_to</span> new_login_session_path
  <span style="color:#9966CC; font-weight:bold;">end</span>
&nbsp;
<span style="color:#9966CC; font-weight:bold;">end</span></pre></div></div>

<p>Finally, changes all places in <code>app/controllers/articles_controller.rb</code> where we fetch articles through the current user. The security check that these provided is now obsolete. Search for <code>current_user.articles</code> and replace with <code>Article</code> (if you oode reads <code>current_user.articles.build</code>, the new code must say <code>Article.new</code>).</p>
<p>Our application logic is now ready for custom permissions.</p>
<h2>Creating a permissions model</h2>
<p>I like to think of permissions as resources, just like articles, comments and users. However, since we may potentially want to add many permissions at the same time, we need a custom controller. This will be a basic lesson on creating a somewhat strange controller to edit a many-to-many relationship. Here are the steps needed:</p>
<ol>
<li>We start by creating the model for the permissions: <code>ruby script/generate model permission editable_article_id:integer editor_id:integer</code></li>
<li>Enter the migration into the database: <code>rake db:migrate</code></li>
<li>Create the controller. Let&#8217;s just give it a few actions: <code>ruby script/generate controller permissions show edit create</code>.</li>
<li>Make the controller a nested resource of the articles. In <code>config/routes.rb</code>, add the following inside the <code>map.resources :articles</code> section: <code>article.resource :permissions, :name_prefix => nil</code> (notice the singular form for &#8220;resource&#8221;)</li>
<li><code>http://localhost:3000/articles/<i>article_id</i>/permissions/</code> should now take us to the show page for the permissions of an article. It&#8217;s currently empty. This is how we want it to look (THIS WILL FAIL):

<div class="wp_syntax"><div class="code"><pre class="rails" style="font-family:monospace;">&lt;h2&gt;Users who can edit <span style="color:#006600; font-weight:bold;">&lt;%</span>= <span style="color:#0066ff; font-weight:bold;">@article</span>.<span style="color:#9900CC;">title</span> <span style="color:#006600; font-weight:bold;">%&gt;</span>&lt;/h2&gt;
&nbsp;
&lt;ul&gt;
<span style="color:#006600; font-weight:bold;">&lt;%</span> <span style="color:#9966CC; font-weight:bold;">for</span> editor <span style="color:#9966CC; font-weight:bold;">in</span> <span style="color:#0066ff; font-weight:bold;">@article</span>.<span style="color:#9900CC;">editors</span> <span style="color:#006600; font-weight:bold;">-</span> <span style="color:#006600; font-weight:bold;">&#91;</span>@article.<span style="color:#9900CC;">user</span><span style="color:#006600; font-weight:bold;">&#93;</span> <span style="color:#006600; font-weight:bold;">%&gt;</span>
  &lt;li&gt;<span style="color:#006600; font-weight:bold;">&lt;%</span>= editor.<span style="color:#9900CC;">username</span> <span style="color:#006600; font-weight:bold;">%&gt;</span> (<span style="color:#006600; font-weight:bold;">&lt;%</span>= editor.<span style="color:#9900CC;">full_name</span> <span style="color:#006600; font-weight:bold;">%&gt;</span>)&lt;/li&gt;
<span style="color:#006600; font-weight:bold;">&lt;%</span> <span style="color:#9966CC; font-weight:bold;">end</span> <span style="color:#006600; font-weight:bold;">%&gt;</span>
&lt;/ul&gt;
&nbsp;
<span style="color:#006600; font-weight:bold;">&lt;%</span>= <span style="color:#5A0A0A; font-weight:bold;">link_to</span> <span style="color:#996600;">&quot;Edit&quot;</span>, edit_permissions_path<span style="color:#006600; font-weight:bold;">&#40;</span>@article<span style="color:#006600; font-weight:bold;">&#41;</span> <span style="color:#006600; font-weight:bold;">%&gt;</span>&lt;/small&gt;</pre></div></div>

</li>
<li>In order to get the <code>@article</code> object, put the following in <code>app/controllers/permissions_controller.rb</code>&#8217;s definition of <code>show</code>: <code>@article = Article.find(params[:article_id])</code>.</li>
<li>For this to work, Article.editors must be implemented. First, associate articles with permissions: <code>has_many :permissions,  :foreign_key => 'editable_article_id'</code> (notice that the foreign_key option matches what we put in the migration). Second, make the permission know about editors: In <code>app/model/permission.rb</code>: <code>belongs_to :editor, :class_name => "User"</code> (Notice that we have to specify the class name, as it is not the same as the association). Lastly, make articles associated with editors through the permission association: <code>has_many :editors, :through => :permissions</code>. If you refresh the permissions page, it should now give an empty list, as expected.</li>
<li>For the edit page, we want to display all users with a checkbox that shows whether that user has a permission to edit the article or not. Here&#8217;s my code for <code>app/views/permissions/edit.html.erb</code>:

<div class="wp_syntax"><div class="code"><pre class="rails" style="font-family:monospace;">&lt;h1&gt;Permissions for <span style="color:#006600; font-weight:bold;">&lt;%</span>= <span style="color:#0066ff; font-weight:bold;">@article</span>.<span style="color:#9900CC;">title</span> <span style="color:#006600; font-weight:bold;">%&gt;</span>&lt;/h1&gt;
&nbsp;
<span style="color:#006600; font-weight:bold;">&lt;%</span> <span style="color:#5A0A0A; font-weight:bold;">form_for</span> <span style="color:#ff3333; font-weight:bold;">:article</span>, <span style="color:#ff3333; font-weight:bold;">:url</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#006600; font-weight:bold;">&#123;</span> <span style="color:#ff3333; font-weight:bold;">:article_id</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#0066ff; font-weight:bold;">@article</span>, 
                                <span style="color:#ff3333; font-weight:bold;">:action</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#ff3333; font-weight:bold;">:update</span> <span style="color:#006600; font-weight:bold;">&#125;</span> <span style="color:#9966CC; font-weight:bold;">do</span> <span style="color:#006600; font-weight:bold;">|</span>f<span style="color:#006600; font-weight:bold;">|</span> <span style="color:#006600; font-weight:bold;">%&gt;</span>
  <span style="color:#006600; font-weight:bold;">&lt;%</span> <span style="color:#9966CC; font-weight:bold;">for</span> user <span style="color:#9966CC; font-weight:bold;">in</span> User.<span style="color:#9900CC;">find</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#ff3333; font-weight:bold;">:all</span><span style="color:#006600; font-weight:bold;">&#41;</span> <span style="color:#006600; font-weight:bold;">-</span> <span style="color:#006600; font-weight:bold;">&#91;</span>@article.<span style="color:#9900CC;">user</span><span style="color:#006600; font-weight:bold;">&#93;</span> <span style="color:#006600; font-weight:bold;">%&gt;</span>
    &lt;div&gt;
      <span style="color:#006600; font-weight:bold;">&lt;%</span>= check_box_tag <span style="color:#996600;">&quot;article[editor_ids][]&quot;</span>, user.<span style="color:#9900CC;">id</span>, 
                        <span style="color:#0066ff; font-weight:bold;">@article</span>.<span style="color:#9900CC;">editors</span>.<span style="color:#9966CC; font-weight:bold;">include</span>?<span style="color:#006600; font-weight:bold;">&#40;</span>user<span style="color:#006600; font-weight:bold;">&#41;</span> <span style="color:#006600; font-weight:bold;">%&gt;</span>
      <span style="color:#006600; font-weight:bold;">&lt;%</span>= user.<span style="color:#9900CC;">username</span> <span style="color:#006600; font-weight:bold;">%&gt;</span> (<span style="color:#006600; font-weight:bold;">&lt;%</span>= user.<span style="color:#9900CC;">full_name</span> <span style="color:#006600; font-weight:bold;">%&gt;</span>)
    &lt;/div&gt;
  <span style="color:#006600; font-weight:bold;">&lt;%</span> <span style="color:#9966CC; font-weight:bold;">end</span> <span style="color:#006600; font-weight:bold;">%&gt;</span>
  &lt;p&gt;
    <span style="color:#006600; font-weight:bold;">&lt;%</span>= f.<span style="color:#9900CC;">submit</span> <span style="color:#996600;">&quot;Update&quot;</span> <span style="color:#006600; font-weight:bold;">%&gt;</span>
  &lt;/p&gt;
<span style="color:#006600; font-weight:bold;">&lt;%</span> <span style="color:#9966CC; font-weight:bold;">end</span> <span style="color:#006600; font-weight:bold;">%&gt;</span></pre></div></div>

</li>
<li>To get the code to display correctly, implement <code>app/controllers/permissions_controllers.rb</code> <code>edit</code> as follows: <code>@article = Article.find(params[:article_id])</code>.</li>
<li>So far, so good. Now comes the hard part: Updating the association on the post. The following is inspired from Ryan Bates&#8217; excellent <a href="">screencast on many-to-many associations with checkboxes</a>. First, notice how the name of the <code>check_box_tag</code> ends with &#8220;[]&#8220;? This is to let ail know that we intend for all &#8220;article[editor_ids]&#8221; values to come in as an array. If you take a look at the application log, you will see something like this: <code>Parameters: {"article"=>{"editor_ids"=>["618895042", "618895044", ....</code>. Second, a <code>has_many :editors</code> association will generate an attribute for <code>editor_ids</code>, as well an attribute for <code>editor</code>. Put these to facts together, and you get the following simplified implementation of <code>PermissionsController.update</code>:

<div class="wp_syntax"><div class="code"><pre class="rails" style="font-family:monospace;">  <span style="color:#9966CC; font-weight:bold;">def</span> create
    <span style="color:#0066ff; font-weight:bold;">@article</span> = Article.<span style="color:#9900CC;">find</span><span style="color:#006600; font-weight:bold;">&#40;</span>params<span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#ff3333; font-weight:bold;">:article_id</span><span style="color:#006600; font-weight:bold;">&#93;</span><span style="color:#006600; font-weight:bold;">&#41;</span>
    <span style="color:#0066ff; font-weight:bold;">@article</span>.<span style="color:#9900CC;">editor_ids</span> = params<span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#ff3333; font-weight:bold;">:article</span><span style="color:#006600; font-weight:bold;">&#93;</span><span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#ff3333; font-weight:bold;">:editor_ids</span><span style="color:#006600; font-weight:bold;">&#93;</span>
    <span style="color:#9966CC; font-weight:bold;">if</span> <span style="color:#0066ff; font-weight:bold;">@article</span>.<span style="color:#5A0A0A; font-weight:bold;">save</span>
      <span style="color:#5A0A0A; font-weight:bold;">flash</span><span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#ff3333; font-weight:bold;">:notice</span><span style="color:#006600; font-weight:bold;">&#93;</span> = <span style="color:#996600;">'Permission was successfully created.'</span>
      <span style="color:#5A0A0A; font-weight:bold;">redirect_to</span><span style="color:#006600; font-weight:bold;">&#40;</span>permissions_path<span style="color:#006600; font-weight:bold;">&#40;</span>@article<span style="color:#006600; font-weight:bold;">&#41;</span><span style="color:#006600; font-weight:bold;">&#41;</span>
    <span style="color:#9966CC; font-weight:bold;">else</span>
      <span style="color:#5A0A0A; font-weight:bold;">render</span> <span style="color:#ff3333; font-weight:bold;">:action</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#996600;">&quot;edit&quot;</span>
    <span style="color:#9966CC; font-weight:bold;">end</span>
  <span style="color:#9966CC; font-weight:bold;">end</span></pre></div></div>

<li>Aaaaand, we're done!</li>
<li>Well, not quite - there's a gaping security hole. Can you see it? If not, don't worry, we'll get back to it.</li>
</ol>
<h2>Using the new security features</h2>
<p>Since we prepared our application for the new security implementation, getting it to take effect is extremely simple, just update <code>app/model/user.rb</code>'s <code>can_edit?</code> method to the following: <code>article.user_id == self.id or editable_articles.include? article</code>. In order for this to work, we need to create a relationship from user to articles, like we did for the other direction:</p>
<ol>
<li>class User <code>has_many :permissions, :foreign_key => :editor_id</code></li>
<li>class Permission <code>belongs_to :editable_article, :class_name => 'Article'</code></li>
<li>And class User <code>has_many :editable_articles, :through => :permissions</code></li>
</ol>
<p>That's it. We're ready to test:</p>
<ol>
<li>Log in as a user who owns an article</li>
<li>Navigate to the article. The edit link should be visible.</li>
<li>Add <code>permissions</code> to the URL (you might want to create a <code>link_to</code> this page!)</li>
<li>Click the <code>Edit</code> link</li>
<li>Give a few users permission to edit the article by checking their names and clicking submit</li>
<li>Log in as a different user who now should have edit permissions for the article</li>
<li>Navigate to the article. The edit link should now be visible.</li>
<li>Outstanding</li>
</ol>
<h2>Who watches the watchmen?</h2>
<p>Have you found the security hole yet? The problem is simply that any user can modify the permissions for an article, giving themselves access to edit the article. We could fix this by protecting the permissions like we protect the articles, but instead, I want to demonstrate how to use multiple permission schemes.</p>
<ol>
<li>We start by adding a much wanted link. In <code>app/views/articles/edit.html.erb</code>, add the following (WILL BREAK): <code><% if current_user.can_admin? @article %><%= link_to 'Change editors', edit_permissions_path(@article) %><% end %></code>.</li>
<li>This will break, because we need to let <code>app/model/user.rb</code> implement the <code>can_admin?</code> method. Here's a possible implementation: <code>def can_admin? article; article.user_id == self.id; end</code>. We could imagine other rules for this, for example with a different set of permissions for administrating an article, or a field on the permissions that determined the access level.</li>
<li>To avoid the user from manually entering the URL, make sure to protect <code>app/controllers/permissions_controller.rb</code> as well:

<div class="wp_syntax"><div class="code"><pre class="rails" style="font-family:monospace;"><span style="color:#9966CC; font-weight:bold;">class</span> PermissionsController <span style="color:#006600; font-weight:bold;">&lt;</span> ApplicationController
  <span style="color:#5A0A0A; font-weight:bold;">before_filter</span> <span style="color:#ff3333; font-weight:bold;">:can_admin</span>, <span style="color:#ff3333; font-weight:bold;">:except</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#006600; font-weight:bold;">&#91;</span> <span style="color:#ff3333; font-weight:bold;">:show</span> <span style="color:#006600; font-weight:bold;">&#93;</span>
  <span style="color:#008000; font-style:italic;"># ...</span>
private
  <span style="color:#9966CC; font-weight:bold;">def</span> can_admin
    <span style="color:#0066ff; font-weight:bold;">@article</span> = Article.<span style="color:#9900CC;">find</span><span style="color:#006600; font-weight:bold;">&#40;</span>params<span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#ff3333; font-weight:bold;">:article_id</span><span style="color:#006600; font-weight:bold;">&#93;</span><span style="color:#006600; font-weight:bold;">&#41;</span>
    <span style="color:#9966CC; font-weight:bold;">unless</span> <span style="color:#0066ff; font-weight:bold;">@article</span> <span style="color:#9966CC; font-weight:bold;">and</span> current_user <span style="color:#9966CC; font-weight:bold;">and</span> current_user.<span style="color:#9900CC;">can_admin</span>? <span style="color:#0066ff; font-weight:bold;">@article</span>
      redirect_to_login
    <span style="color:#9966CC; font-weight:bold;">end</span>
  <span style="color:#9966CC; font-weight:bold;">end</span>
<span style="color:#9966CC; font-weight:bold;">end</span></pre></div></div>

</li>
<li>Protect the edit link in <code>app/views/permissions/show.html.erb</code> as well: <code><% if current_user and current_user.can_admin? @article %><%= link_to "Edit", edit_permissions_path(@article) %><% end %></code></li>
<li>This effectively protects the permissions from being edited by anyone except the original author of the article</li>
</ol>
<h2>A detour to increase our speed</h2>
<p>When you start creating more Rails applications, you will quickly notice that the place where performance bottlenecks occur is with the access to the database. In our example, changing the permissions is particularly prone to being slow, as it currently fetches the user for every checked line it displays.</p>
<p>In order to prevent this, we can include the user information when looking for the permissions. The way to do this is to specify the extra information to be fetched right away on the <code>Article.find</code>. It basically looks like this: <code>Article.find(params[:article_id], :include => :editors)</code>. <code>:include</code> is a powerful feature with lots of options. Make sure you understand it, or your applications will be slow.</p>
<h2>A the end of our journey?</h2>
<p>This article completes the construction of our blog application. Along the course of the set of articles, we have implemented one-to-many relationships, RSS, AJAX, learned about sessions and authentication, looked at many-to-many relationships in order to implement access control.</p>
<p>These articles show you much of the power of Rails as a web framework. However, we haven&#8217;t touched any of subjects needed to have an effective development process with Rails. Rails is often used together with Capistrano, which gives support for actually deploying applications to a server. In addition, we have only scratched the surface of the test options that exist for Rails.</p>
<p>This series of articles is at an end, but I am considering writing a few article on practical testing and deployment with Rails. Stay tuned for more Rails goodness.</p>
]]></content:encoded>
			<wfw:commentRss>http://johannesbrodwall.com/2008/05/31/rails-6-authorization/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Rails #5: Security</title>
		<link>http://johannesbrodwall.com/2008/03/23/rails-5-security/</link>
		<comments>http://johannesbrodwall.com/2008/03/23/rails-5-security/#comments</comments>
		<pubDate>Sun, 23 Mar 2008 19:53:12 +0000</pubDate>
		<dc:creator>Johannes Brodwall</dc:creator>
				<category><![CDATA[Ruby-on-Rails]]></category>

		<guid isPermaLink="false">http://www.brodwall.com/johannes/blog/2008/03/23/rails-5-security/</guid>
		<description><![CDATA[In my previous articles, I have showed you how to create a simple blog application with articles, comments, rss feeds and formatting. However, as it is currently written, the application allows for anyone to create or edit an article. This is a serious security issue, and we better fix it.
In this tutorial, I will show [...]]]></description>
			<content:encoded><![CDATA[<p>In my <a href="http://www.brodwall.com/johannes/blog/category/ruby-on-rails/">previous articles</a>, I have showed you how to create a simple blog application with articles, comments, rss feeds and formatting. However, as it is currently written, the application allows for anyone to create or edit an article. This is a serious security issue, and we better fix it.</p>
<p>In this tutorial, I will show you how to make sure that only logged in users can create articles, and that nobody else can edit an article that you created.</p>
<h3>The task at hand</h3>
<p>This is basically what I want to say:</p>

<div class="wp_syntax"><div class="code"><pre class="rails" style="font-family:monospace;"><span style="color:#9966CC; font-weight:bold;">class</span> ArticlesController <span style="color:#006600; font-weight:bold;">&lt;</span> ApplicationController
&nbsp;
  <span style="color:#5A0A0A; font-weight:bold;">before_filter</span> <span style="color:#ff3333; font-weight:bold;">:verify_logged_in</span>, <span style="color:#ff3333; font-weight:bold;">:except</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#006600; font-weight:bold;">&#91;</span> <span style="color:#ff3333; font-weight:bold;">:index</span>, <span style="color:#ff3333; font-weight:bold;">:show</span> <span style="color:#006600; font-weight:bold;">&#93;</span>
&nbsp;
  <span style="color:#9966CC; font-weight:bold;">def</span> <span style="color:#5A0A0A; font-weight:bold;">new</span>
    <span style="color:#0066ff; font-weight:bold;">@article</span> = current_user.<span style="color:#9900CC;">articles</span>.<span style="color:#9900CC;">build</span>
  <span style="color:#9966CC; font-weight:bold;">end</span>
&nbsp;
  <span style="color:#9966CC; font-weight:bold;">def</span> edit
    <span style="color:#0066ff; font-weight:bold;">@article</span> = current_user.<span style="color:#9900CC;">articles</span>.<span style="color:#9900CC;">find</span><span style="color:#006600; font-weight:bold;">&#40;</span>params<span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#ff3333; font-weight:bold;">:id</span><span style="color:#006600; font-weight:bold;">&#93;</span><span style="color:#006600; font-weight:bold;">&#41;</span>
  <span style="color:#9966CC; font-weight:bold;">end</span>
&nbsp;
  <span style="color:#9966CC; font-weight:bold;">def</span> create
    <span style="color:#0066ff; font-weight:bold;">@article</span> = current_user.<span style="color:#9900CC;">articles</span>.<span style="color:#9900CC;">build</span><span style="color:#006600; font-weight:bold;">&#40;</span>params<span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#ff3333; font-weight:bold;">:article</span><span style="color:#006600; font-weight:bold;">&#93;</span><span style="color:#006600; font-weight:bold;">&#41;</span>
    <span style="color:#008000; font-style:italic;"># save it...</span>
  <span style="color:#9966CC; font-weight:bold;">end</span>
&nbsp;
  <span style="color:#9966CC; font-weight:bold;">def</span> <span style="color:#5A0A0A; font-weight:bold;">update</span>
    <span style="color:#0066ff; font-weight:bold;">@article</span> = current_user.<span style="color:#9900CC;">articles</span>.<span style="color:#9900CC;">find</span><span style="color:#006600; font-weight:bold;">&#40;</span>params<span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#ff3333; font-weight:bold;">:id</span><span style="color:#006600; font-weight:bold;">&#93;</span><span style="color:#006600; font-weight:bold;">&#41;</span>
    <span style="color:#008000; font-style:italic;"># save it...</span>
  <span style="color:#9966CC; font-weight:bold;">end</span>
&nbsp;
  <span style="color:#9966CC; font-weight:bold;">def</span> <span style="color:#5A0A0A; font-weight:bold;">destroy</span>
    <span style="color:#0066ff; font-weight:bold;">@article</span> = current_user.<span style="color:#9900CC;">articles</span>.<span style="color:#9900CC;">find</span><span style="color:#006600; font-weight:bold;">&#40;</span>params<span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#ff3333; font-weight:bold;">:id</span><span style="color:#006600; font-weight:bold;">&#93;</span><span style="color:#006600; font-weight:bold;">&#41;</span>
    <span style="color:#008000; font-style:italic;"># delete it...</span>
  <span style="color:#9966CC; font-weight:bold;">end</span>
&nbsp;
private
&nbsp;
  <span style="color:#9966CC; font-weight:bold;">def</span> verify_logged_in
    <span style="color:#9966CC; font-weight:bold;">unless</span> current_user
      <span style="color:#008000; font-style:italic;"># redirect to login dialogue</span>
    <span style="color:#9966CC; font-weight:bold;">end</span>
  <span style="color:#9966CC; font-weight:bold;">end</span>
<span style="color:#9966CC; font-weight:bold;">end</span></pre></div></div>

<p>In plain English: Verify that the user is logged in before any other actions than index and show are performed. This boils down to the method current_user returning a non-nil result. Use the current_user as starting point when creating or updating articles.</p>
<p>Now we just need to create the login functionality. This means some way of creating users and making these users log in. There is actually a plugin called <a href="http://agilewebdevelopment.com/plugins/restful_authentication">restful_authentication</a> that does this for you, but it&#8217;s not that hard, so I though we could do it on our own.</p>
<h3>The users model</h3>
<p>The key to this business is obviously the <code>verify_logged_in</code> method. Let&#8217;s try this:</p>

<div class="wp_syntax"><div class="code"><pre class="rails" style="font-family:monospace;">  <span style="color:#9966CC; font-weight:bold;">def</span> verify_logged_in
    <span style="color:#9966CC; font-weight:bold;">unless</span> current_user
      <span style="color:#5A0A0A; font-weight:bold;">redirect_to</span> new_login_session_path
    <span style="color:#9966CC; font-weight:bold;">end</span>
  <span style="color:#9966CC; font-weight:bold;">end</span></pre></div></div>

<p>What is this <code>current_user</code> thing?</p>

<div class="wp_syntax"><div class="code"><pre class="rails" style="font-family:monospace;">  <span style="color:#9966CC; font-weight:bold;">def</span> current_user
    User.<span style="color:#9900CC;">find</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#5A0A0A; font-weight:bold;">session</span><span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#ff3333; font-weight:bold;">:user_id</span><span style="color:#006600; font-weight:bold;">&#93;</span><span style="color:#006600; font-weight:bold;">&#41;</span> <span style="color:#9966CC; font-weight:bold;">if</span> <span style="color:#5A0A0A; font-weight:bold;">session</span><span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#ff3333; font-weight:bold;">:user_id</span><span style="color:#006600; font-weight:bold;">&#93;</span>
  <span style="color:#9966CC; font-weight:bold;">end</span></pre></div></div>

<p>Here, we use a session variable to store the user_id, and look up the a User model using this session variable. You should never store ActiveRecord objects in session variables.</p>
<p>By now, it is becoming blindingly obvious that we need a User model. Let&#8217;s use the generator:</p>
<p><code>ruby script/generate model User username:string password:string</code></p>
<p>We also want to associate the articles with users. Add <code>has_many :articles</code> in <code>app/models/user.rb</code>, and <code>belongs_to :user</code> in <code>app/models/article.rb</code>. Also add the following to your newly generated migration in <code>db/migrate/003_create_users.rb</code>:</p>

<div class="wp_syntax"><div class="code"><pre class="rails" style="font-family:monospace;"><span style="color:#9966CC; font-weight:bold;">class</span> CreateUsers <span style="color:#006600; font-weight:bold;">&lt;</span> <span style="color:#6666ff; font-weight:bold;">ActiveRecord::Migration</span>
  <span style="color:#9966CC; font-weight:bold;">def</span> <span style="color:#0000FF; font-weight:bold;">self</span>.<span style="color:#9900CC;">up</span>
    <span style="color:#008000; font-style:italic;"># ...</span>
    add_column <span style="color:#ff3333; font-weight:bold;">:articles</span>, <span style="color:#ff3333; font-weight:bold;">:user_id</span>, <span style="color:#ff3333; font-weight:bold;">:integer</span>
  <span style="color:#9966CC; font-weight:bold;">end</span>
&nbsp;
  <span style="color:#9966CC; font-weight:bold;">def</span> <span style="color:#0000FF; font-weight:bold;">self</span>.<span style="color:#9900CC;">down</span>
    remove_column <span style="color:#ff3333; font-weight:bold;">:articles</span>, <span style="color:#ff3333; font-weight:bold;">:user_id</span>
    <span style="color:#008000; font-style:italic;"># ...</span>
  <span style="color:#9966CC; font-weight:bold;">end</span>
<span style="color:#9966CC; font-weight:bold;">end</span></pre></div></div>

<p>You can now execute <code>rake db:migrate</code> to update the database structure.</p>
<h3>Logging in</h3>
<p>Next order of business: <code>verify_logged_in</code> contained the line <code>redirect_to new_login_session_path</code>. If you guessed that we are going to have a resource called &#8220;login_session&#8221;, and that this is just like when we said &#8220;new_comment_path&#8221;, you guessed right! This means we have to add the following to <code>config/routes.rb</code>: <code>map.resource :login_session</code>.</p>
<p>A user should only be aware of one login_session, so we say <code>map.resource</code> (singular) instead of <code>map.resources</code> plural. A typo here can be very confusing.</p>
<p>Now, create the LoginSessionsController by executing <code>ruby script/generate controller LoginSessions new create show destroy</code> on the command line. We can now update our new <code>app/controllers/login_sessions_controller.rb</code>. Notice how we use the conventions from other restful controllers of standardized action names for new, create, show and destroy, even though there is no login_session model:</p>
</pre>

<div class="wp_syntax"><div class="code"><pre class="rails" style="font-family:monospace;"><span style="color:#9966CC; font-weight:bold;">class</span> LoginSessionsController <span style="color:#006600; font-weight:bold;">&lt;</span> ApplicationController
&nbsp;
  <span style="color:#9966CC; font-weight:bold;">def</span> <span style="color:#5A0A0A; font-weight:bold;">new</span>
  <span style="color:#9966CC; font-weight:bold;">end</span>
&nbsp;
  <span style="color:#9966CC; font-weight:bold;">def</span> create
    <span style="color:#0066ff; font-weight:bold;">@user</span> = User.<span style="color:#9900CC;">authenticate</span><span style="color:#006600; font-weight:bold;">&#40;</span>params<span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#ff3333; font-weight:bold;">:login</span><span style="color:#006600; font-weight:bold;">&#93;</span><span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#ff3333; font-weight:bold;">:username</span><span style="color:#006600; font-weight:bold;">&#93;</span>, params<span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#ff3333; font-weight:bold;">:login</span><span style="color:#006600; font-weight:bold;">&#93;</span><span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#ff3333; font-weight:bold;">:password</span><span style="color:#006600; font-weight:bold;">&#93;</span><span style="color:#006600; font-weight:bold;">&#41;</span>
    <span style="color:#9966CC; font-weight:bold;">if</span> <span style="color:#0066ff; font-weight:bold;">@user</span>
      <span style="color:#5A0A0A; font-weight:bold;">session</span><span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#ff3333; font-weight:bold;">:user_id</span><span style="color:#006600; font-weight:bold;">&#93;</span> = <span style="color:#0066ff; font-weight:bold;">@user</span>.<span style="color:#9900CC;">id</span>
      <span style="color:#5A0A0A; font-weight:bold;">redirect_to</span> <span style="color:#ff3333; font-weight:bold;">:action</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#996600;">&quot;show&quot;</span>
    <span style="color:#9966CC; font-weight:bold;">else</span>
      <span style="color:#5A0A0A; font-weight:bold;">render</span> <span style="color:#ff3333; font-weight:bold;">:action</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#996600;">&quot;new&quot;</span>
    <span style="color:#9966CC; font-weight:bold;">end</span>
  <span style="color:#9966CC; font-weight:bold;">end</span>
&nbsp;
  <span style="color:#9966CC; font-weight:bold;">def</span> <span style="color:#5A0A0A; font-weight:bold;">show</span>
    <span style="color:#0066ff; font-weight:bold;">@user</span> = current_user
    <span style="color:#9966CC; font-weight:bold;">if</span> !@user
      <span style="color:#5A0A0A; font-weight:bold;">redirect_to</span> <span style="color:#ff3333; font-weight:bold;">:action</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#ff3333; font-weight:bold;">:new</span>
    <span style="color:#9966CC; font-weight:bold;">end</span>
  <span style="color:#9966CC; font-weight:bold;">end</span>
&nbsp;
  <span style="color:#9966CC; font-weight:bold;">def</span> <span style="color:#5A0A0A; font-weight:bold;">destroy</span>
    <span style="color:#5A0A0A; font-weight:bold;">session</span><span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#ff3333; font-weight:bold;">:user_id</span><span style="color:#006600; font-weight:bold;">&#93;</span> = <span style="color:#0000FF; font-weight:bold;">nil</span>
    <span style="color:#5A0A0A; font-weight:bold;">redirect_to</span> <span style="color:#ff3333; font-weight:bold;">:action</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#ff3333; font-weight:bold;">:new</span>
  <span style="color:#9966CC; font-weight:bold;">end</span>
&nbsp;
private
&nbsp;
  <span style="color:#9966CC; font-weight:bold;">def</span> current_user
    User.<span style="color:#9900CC;">find</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#5A0A0A; font-weight:bold;">session</span><span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#ff3333; font-weight:bold;">:user_id</span><span style="color:#006600; font-weight:bold;">&#93;</span><span style="color:#006600; font-weight:bold;">&#41;</span> <span style="color:#9966CC; font-weight:bold;">if</span> <span style="color:#5A0A0A; font-weight:bold;">session</span><span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#ff3333; font-weight:bold;">:user_id</span><span style="color:#006600; font-weight:bold;">&#93;</span>
  <span style="color:#9966CC; font-weight:bold;">end</span>
&nbsp;
<span style="color:#9966CC; font-weight:bold;">end</span></pre></div></div>

<p>The form for logging in is located in <code>app/views/login_sessions/new.html.erb</code> and looks like this:</p>

<div class="wp_syntax"><div class="code"><pre class="rails" style="font-family:monospace;"><span style="color:#006600; font-weight:bold;">&lt;</span>h1<span style="color:#006600; font-weight:bold;">&gt;</span>Log in<span style="color:#006600; font-weight:bold;">&lt;/</span>h1<span style="color:#006600; font-weight:bold;">&gt;</span>
&nbsp;
<span style="color:#006600; font-weight:bold;">&lt;</span> <span style="color:#006600; font-weight:bold;">%</span> <span style="color:#5A0A0A; font-weight:bold;">form_for</span> <span style="color:#ff3333; font-weight:bold;">:login</span>, <span style="color:#ff3333; font-weight:bold;">:url</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#006600; font-weight:bold;">&#123;</span> <span style="color:#ff3333; font-weight:bold;">:action</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#ff3333; font-weight:bold;">:create</span> <span style="color:#006600; font-weight:bold;">&#125;</span> <span style="color:#9966CC; font-weight:bold;">do</span> <span style="color:#006600; font-weight:bold;">|</span>f<span style="color:#006600; font-weight:bold;">|</span> <span style="color:#006600; font-weight:bold;">%&gt;</span>
&nbsp;
<span style="color:#006600; font-weight:bold;">&lt;</span>p<span style="color:#006600; font-weight:bold;">&gt;&lt;</span> <span style="color:#006600; font-weight:bold;">%</span>= f.<span style="color:#9900CC;">label</span> <span style="color:#ff3333; font-weight:bold;">:username</span> <span style="color:#006600; font-weight:bold;">%&gt;</span>: <span style="color:#006600; font-weight:bold;">&lt;</span> <span style="color:#006600; font-weight:bold;">%</span>= f.<span style="color:#9900CC;">text_field</span> <span style="color:#ff3333; font-weight:bold;">:username</span> <span style="color:#006600; font-weight:bold;">%&gt;&lt;/</span>p<span style="color:#006600; font-weight:bold;">&gt;</span>
<span style="color:#006600; font-weight:bold;">&lt;</span>p<span style="color:#006600; font-weight:bold;">&gt;&lt;</span> <span style="color:#006600; font-weight:bold;">%</span>= f.<span style="color:#9900CC;">label</span> <span style="color:#ff3333; font-weight:bold;">:password</span> <span style="color:#006600; font-weight:bold;">%&gt;</span>: <span style="color:#006600; font-weight:bold;">&lt;</span> <span style="color:#006600; font-weight:bold;">%</span>= f.<span style="color:#5A0A0A; font-weight:bold;">password_field</span> <span style="color:#ff3333; font-weight:bold;">:password</span> <span style="color:#006600; font-weight:bold;">%&gt;&lt;/</span>p<span style="color:#006600; font-weight:bold;">&gt;</span>
&nbsp;
<span style="color:#006600; font-weight:bold;">&lt;</span>p<span style="color:#006600; font-weight:bold;">&gt;&lt;</span> <span style="color:#006600; font-weight:bold;">%</span>= f.<span style="color:#9900CC;">submit</span> <span style="color:#996600;">&quot;Log in&quot;</span> <span style="color:#006600; font-weight:bold;">%&gt;&lt;/</span>p<span style="color:#006600; font-weight:bold;">&gt;</span>
<span style="color:#006600; font-weight:bold;">&lt;</span> <span style="color:#006600; font-weight:bold;">%</span> <span style="color:#9966CC; font-weight:bold;">end</span> <span style="color:#006600; font-weight:bold;">%&gt;</span></pre></div></div>

<p>I have also made it possible to log out from the show-view by having a logout "form" in <code>app/views/login_sessions/show.html.erb</code>:</p>

<div class="wp_syntax"><div class="code"><pre class="rails" style="font-family:monospace;"><span style="color:#006600; font-weight:bold;">&lt;</span>h1<span style="color:#006600; font-weight:bold;">&gt;</span>Current session<span style="color:#006600; font-weight:bold;">&lt;/</span>h1<span style="color:#006600; font-weight:bold;">&gt;</span>
<span style="color:#006600; font-weight:bold;">&lt;</span>p<span style="color:#006600; font-weight:bold;">&gt;</span>You are logged <span style="color:#9966CC; font-weight:bold;">in</span> as <span style="color:#006600; font-weight:bold;">&lt;</span> <span style="color:#006600; font-weight:bold;">%</span>= <span style="color:#0066ff; font-weight:bold;">@user</span>.<span style="color:#9900CC;">username</span> <span style="color:#006600; font-weight:bold;">%&gt;&lt;/</span>p<span style="color:#006600; font-weight:bold;">&gt;</span>
&nbsp;
<span style="color:#006600; font-weight:bold;">&lt;</span> <span style="color:#006600; font-weight:bold;">%</span> form_tag <span style="color:#996600;">'/login_session'</span>, <span style="color:#ff3333; font-weight:bold;">:method</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#ff3333; font-weight:bold;">:delete</span> <span style="color:#9966CC; font-weight:bold;">do</span> <span style="color:#006600; font-weight:bold;">%&gt;</span>
  <span style="color:#006600; font-weight:bold;">&lt;</span> <span style="color:#006600; font-weight:bold;">%</span>= submit_tag <span style="color:#996600;">&quot;Log out&quot;</span> <span style="color:#006600; font-weight:bold;">%&gt;</span>
<span style="color:#006600; font-weight:bold;">&lt;</span> <span style="color:#006600; font-weight:bold;">%</span> <span style="color:#9966CC; font-weight:bold;">end</span> <span style="color:#006600; font-weight:bold;">%&gt;</span></pre></div></div>

<p>(I'm not totally happy with this - suggestions for improvements are welcome!)</p>
<p>Everything now works - trust me!</p>
<h3>Testing the code</h3>
<p>Okay, don't trust me. God knows I wouldn't trust me. You should obviously test your code. Normally, you would test this sort of logic using test classes, but I haven't covered this yet, so we'll have to be satisfied with manual testing for now.</p>
<p>In <a href="http://www.brodwall.com/johannes/blog/2008/02/21/rails-4-a-real-blog/">article 4 in this series</a>, I introduced fixtures. Fixtures are located under <code>test/fixtures</code>, and when you used the generator to create the user model, a fixture was generated for you as well in <code>test/fixtures/users.yml</code>. Update this to contain two test users with passwords. I use the following:</p>

<div class="wp_syntax"><div class="code"><pre class="yaml" style="font-family:monospace;">user1:
  username: user1
  password: password
&nbsp;
user2:
  username: user2
  password: password</pre></div></div>

<p>Also, make sure that the article fixtures in <code>test/fixtures/articles.yml</code> contain reference to the users. Here is one of my articles:</p>

<div class="wp_syntax"><div class="code"><pre class="yaml" style="font-family:monospace;">two:
  user: user1
  title: Romans, Brothers, Fellowmen
  author: Marcus Aurelius
  content: I stand here before you bearing witness of a &lt;b&gt;miracle&lt;/b&gt;</pre></div></div>

<p>You can now reload the fixtures with <code>rake db:fixtures:load</code>. Then test as follows:</p>
<ol>
<li>Go to an article and press the "edit" link. You should now be redirected to the login page</li>
<li>Enter the username and password to your user who own the article from <code>test/fixtures/users.yml</code> and press "Log in". You should now be taken to a page that shows your login status</li>
<li>Navigate back to the article edit page. You should now be able to edit the article.</li>
<li>Navigate back to the login status page (http://localhost:3000/login_session) and press "Log out". You should now be returned to the login form.</li>
<li>Log in as a user who does <em>not</em> own the article.</li>
<li>Navigate back to the article edit page. You should now be presented with an error message stating that there is no article with this id and user_id.</li>
</ol>
<p>Our rudimentary security now works correctly, and we can rest soundly. Or we can polish it to make it nicer. Which one is it going to be? You know me by now: Let's get out the belt sander.</p>
<h3>Making it nice</h3>
<p>There are many things we need to do to make this actually usable. We have our work cut out for us. Let's get started:</p>
<ol>
<li>Show current login status on all pages. In <code>app/views/layouts/articles.html.erb</code>, add <code>&lt;% if current_user %>&lt;p>Logged in as &lt;%= link_to current_user.username, :controller => :login_sessions, :action => :show %>&lt;/p>&lt;% end %></code>, and copy <code>current_user</code> from the articles_controller to <code>app/helpers/login_sessions_helper.rb</code></li>
<li>Most importantly: Let's remove the "edit" link when the user can't edit the current article. This avoid confusion, and means that we don't have to fix the ugly error message for people trying to edit other people's articles. Here's how: In <code>app/views/articles/show.html.erb</code>, put the following around the edit link: <code>&#038;lt% if current_user_can_edit @article %> ... &lt;% end %></code>. Define the <code>current_user_can_edit</code> method in <code>app/helpers/login_sessions_helper.rb</code> as follows: <code>article.user == current_user</code></li>
<li>Give a friendly message when we redirect someone to log in. We do this using <a href="http://api.rubyonrails.com/classes/ActionController/Flash.html">the flash</a>. The flash is a special session which is cleared after a the next request. We use it when we're redirecting, and normally would put something in "@" instance variables, as instance variables don't survive a redirect. In <code>app/controllers/articles_controller.rb</code>, add the following in <code>verify_logged_in</code> before redirecting: <code>flash[:notice] = "You must login in to do this"</code>. In <code>app/views/login_sessions/new.html.erb</code>, add the following to the top of the page: <code>&lt;p style="color: green">&lt;%= flash[:notice] %>&lt;/p></code></li>
<li>Add a message if login failed. In <code>app/controllers/login_sessions_controller.rb</code>, add the following to the <code>else</code> block of <code>create</code>: <code>flash[:error] = "Login failed"</code>. In <code>app/views/login_sessions/new.html.erb</code>, add the following to the top of the page: <code>&lt;p style="color: red">&lt;%= flash[:error] %>&lt;/p></code>. As an extra exercise: Can you create a generic construct to list all items in the flash (use <code>flash.each_pair</code>) and display them with proper formatting (update <code>public/stylesheet/scaffold.css</code>)?</li>
<li>If a user was diverted to the login page, redirect the user back to the page he wanted to go to after a successful login. In <code>app/controllers/articles_controller.rb</code>, add the following in <code>verify_logged_in</code> before the redirect: <code>session[:redirect_after_login] = request.request_uri</code>. In <code>app/controllers/login_sessions_controller.rb</code>, change the redirect in <code>create</code> to the following: <code>redirect_to(session[:redirect_after_login] || { :action => 'show'})</code></li>
<li>Allow for http authentication to allow web service clients to access restricted operations without having to simulate a login dialog. If you have Cygwin, or you're working on a UNIX platform, you can test this by using the command line tool "curl": <code>curl http://localhost:3000/articles/<em>id</em>/edit</code> will redirect, but <code>curl --user <em>username</em>:<em>password</em> http://localhost:3000/articles/<em>id</em>/edit</code> will work if we make the following change: In <code>app/controllers/articles_controller.rb</code>, add the following to the start of <code>current_user</code>: <code>if !session[:user_id] &#038;&#038; user = authenticate_with_http_basic { |u, p| User.authenticate(u,p) };  session[:user_id] = user.id; end</code></li>
<li>Never store clear text passwords in the database. We can hash the passwords first. In <code>app/models/user.rb</code>, make the following changes:

<div class="wp_syntax"><div class="code"><pre class="rails" style="font-family:monospace;"><span style="color:#9966CC; font-weight:bold;">class</span> User <span style="color:#006600; font-weight:bold;">&lt;</span> <span style="color:#6666ff; font-weight:bold;">ActiveRecord::Base</span>
  <span style="color:#5A0A0A; font-weight:bold;">has_many</span> <span style="color:#ff3333; font-weight:bold;">:articles</span>
&nbsp;
  <span style="color:#9966CC; font-weight:bold;">def</span> password=<span style="color:#006600; font-weight:bold;">&#40;</span>value<span style="color:#006600; font-weight:bold;">&#41;</span>
    write_attribute <span style="color:#ff3333; font-weight:bold;">:hashed_password</span>, User.<span style="color:#9900CC;">hash_string</span><span style="color:#006600; font-weight:bold;">&#40;</span>value<span style="color:#006600; font-weight:bold;">&#41;</span>
  <span style="color:#9966CC; font-weight:bold;">end</span>
&nbsp;
  <span style="color:#9966CC; font-weight:bold;">def</span> password
    <span style="color:#996600;">&quot;&quot;</span>
  <span style="color:#9966CC; font-weight:bold;">end</span>
&nbsp;
  <span style="color:#9966CC; font-weight:bold;">def</span> <span style="color:#0000FF; font-weight:bold;">self</span>.<span style="color:#9900CC;">authenticate</span><span style="color:#006600; font-weight:bold;">&#40;</span>username, password<span style="color:#006600; font-weight:bold;">&#41;</span>
    find_by_username_and_hashed_password<span style="color:#006600; font-weight:bold;">&#40;</span>username, hash_string<span style="color:#006600; font-weight:bold;">&#40;</span>password<span style="color:#006600; font-weight:bold;">&#41;</span><span style="color:#006600; font-weight:bold;">&#41;</span>
  <span style="color:#9966CC; font-weight:bold;">end</span>
&nbsp;
  PASSWORD_SALT = <span style="color:#996600;">&quot;slgn3woihtrwoe1902&quot;</span>
&nbsp;
  <span style="color:#9966CC; font-weight:bold;">def</span> <span style="color:#0000FF; font-weight:bold;">self</span>.<span style="color:#9900CC;">hash_string</span><span style="color:#006600; font-weight:bold;">&#40;</span>string<span style="color:#006600; font-weight:bold;">&#41;</span>
    <span style="color:#6666ff; font-weight:bold;">Digest::SHA1</span>.<span style="color:#9900CC;">hexdigest</span><span style="color:#006600; font-weight:bold;">&#40;</span>string <span style="color:#006600; font-weight:bold;">+</span> PASSWORD_SALT<span style="color:#006600; font-weight:bold;">&#41;</span>
  <span style="color:#9966CC; font-weight:bold;">end</span>
<span style="color:#9966CC; font-weight:bold;">end</span></pre></div></div>

<p>Also update the migration by replacing the <code>password</code> column with <code>hashed_password</code>, and rerun the last migration with <code>rake db:migrate:redo</code>. Finally update the <code>test/fixture/users.yml</code> and replace the password lines with the following: <code>hashed_password: &lt;%= User.hash_string "password" %></code>. Reload the fixtures with <code>rake db:fixtures:load</code>. Everything will behave as before, but the passwords are no longer stored in clear text.</pre>
</li>
<li>Fix the tests: All the tests in <code>test/functional/articles_controller_test.rb</code> of methods that require login will now fail. The <code>get</code>, <code>put</code>, <code>post</code> and <code>delete</code> methods that the tests use are all designed with this problem in mind. They all take up to three parameters: The action, the arguments, and the current session. So, for example, in <code>test_should_create_article</code> the line <code>post :create, :article => { }</code> should be replaced by <code>post :create, { :article => { } }, { :user_id => users(:user1).id }</code>, and the first line in <code>test_should_update_article</code> should be <code>put :update, { :id => articles(:one).id, :article => { } }, { :user_id => articles(:one).user_id }</code>. You can find more information about <a href="http://manuals.rubyonrails.com/read/chapter/28">testing controllers</a> in <a href="http://manuals.rubyonrails.com/read/book/5">A Guide to Testing the Rails</a>, by Steve Kellock and Chris Carter.</li>
<li>Allow for the creation of new users. Whoops! Currently, only the users already in the database are available. That won't really work, will it? First, let's add a few details to the user model: <code>ruby script/generate migration AddDetailsToUser email:string full_name:string bio:text</code> and <code>rake db:migrate</code>. Then, create the controller and views for the user scaffold: <code>ruby script/generate scaffold --skip-migration user username:string password:string email:string full_name:string bio:text</code>. You will need to make a few simple changes: Remove <code>password</code> from <code>show.html.erb</code> and <code>index.html.erb</code>, and replace <code>text_field</code> for password in <code>edit.html.erb</code> and <code>new.html.erb</code> with <code>password_field</code>. You will probably also want to have a <code>before_filter :verify_logged_in, :only => [ :edit, :update, :destroy ]</code> in <code>app/controllers/users_controller.rb</code>. Move <code>verify_logged_in</code> and <code>current_user</code> to <code>app/controllers/application.rb</code> to reuse these methods between the different controllers.</li>
<li>There are still many things left to do with the users to make them secure and well-functioning. But that's going to be the subject of a future post.</li>
</ol>
<h3>Don't mess with my articles!</h3>
<p>We have implemented functionality for logging in, and for restricting access to an article. It turns out that using the relationships between the user object and articles is a good way to ensure that a user is only allowed to edit his own articles. Using ActiveRecord to execute <code>find</code> on an association instead of a class minimizes the risk of leaving security holes open by accident. There's still a lot to learn about security however. In my next post, I will show you how you can let users grant access for other users to edit their posts. I might also touch on a few odds and ends regarding validation. Stay turned.</p>
]]></content:encoded>
			<wfw:commentRss>http://johannesbrodwall.com/2008/03/23/rails-5-security/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Rails #1b: Heroku</title>
		<link>http://johannesbrodwall.com/2008/02/21/rails-1b-heroku/</link>
		<comments>http://johannesbrodwall.com/2008/02/21/rails-1b-heroku/#comments</comments>
		<pubDate>Fri, 22 Feb 2008 02:25:10 +0000</pubDate>
		<dc:creator>Johannes Brodwall</dc:creator>
				<category><![CDATA[Ruby-on-Rails]]></category>
		<category><![CDATA[Technology]]></category>

		<guid isPermaLink="false">http://www.brodwall.com/johannes/blog/2008/02/21/rails-1b-heroku/</guid>
		<description><![CDATA[If you though getting started with Rails seemed easy from my first post, you haven&#8217;t tried out Heroku yet. Heroku is a hosted solution for Rails that comes with a browser based IDE. There&#8217;s nothing to install. It is so easy that it&#8217;s almost ridiculous. To me, this is the future of application hosting.
One of [...]]]></description>
			<content:encoded><![CDATA[<p>If you though getting started with Rails seemed easy from <a href="http://www.brodwall.com/johannes/blog/2008/01/26/rails-intro-1-a-data-management-application-in-five-easy-steps/">my first post</a>, you haven&#8217;t tried out Heroku yet. <a href="http://heroku.com/">Heroku</a> is a hosted solution for Rails that comes with a browser based IDE. There&#8217;s nothing to install. It is so easy that it&#8217;s almost ridiculous. To me, this is the future of application hosting.</p>
<p>One of the remarkable things about Rails is that it lets you get up and running very quickly. Here is what you need to do to get your first application up and running on Heroku.</p>
<ol>
<li>Apply for an account on <a href="http://heroku.com/beta">heroku</a> (or mail me for an invitation)</li>
<li>When you have gotten your account set up, go to <a href="http://heroku.com/myapps">the heroku page for your applications</a> and log in.</li>
<li>Press the big button labeled &#8220;Create New App&#8221;</li>
<li>Click the button that look like a gear in the lower left hand corner and choose &#8220;generate&#8221; from the pop-up menu.</li>
<li>Enter <code>scaffold article title:string author:string content:text</code> and click &#8220;run&#8221;</li>
<li>Press the yellow text labeled &#8220;Migrate now&#8221; to create the articles table in the database</li>
<li>(Optional) Select &#8220;rake&#8221; from the gear pop-up menu and type <code>test</code></li>
<li>(Optional) In the &#8220;rake&#8221; window, type <code>db:fixtures:load</code> to populate the database with test data</li>
<li>Press the button with two right arrows (&#8220;>>&#8221;) on the top right corner and you will be taken to your application, done being installed on the heroku server. Add <code>/articles</code> to the url to see your newly generated application</li>
<li>You can now play around with creating, retrieving, updating and deleting articles</li>
<li>Click the button with two left arrows (&#8220;<<") on the bottom of the screen to return to the IDE</li>
<li>(Optional) Make the application publicly available. Click the name of the application (&#8220;unnamed-xxxx&#8221; on the top left corner). Pick a name for your application, select &#8220;Public&#8221; to have it deployed to the net, and press rename</li>
</ol>
<p>You now have a fully working, running, deployed Rails application. It requires no installation on your part. From here, you can follow the rest of my articles on Rails pretty much straightforward. Welcome aboard.</p>
]]></content:encoded>
			<wfw:commentRss>http://johannesbrodwall.com/2008/02/21/rails-1b-heroku/feed/</wfw:commentRss>
		<slash:comments>13</slash:comments>
		</item>
		<item>
		<title>Rails #4: A real blog</title>
		<link>http://johannesbrodwall.com/2008/02/21/rails-4-a-real-blog/</link>
		<comments>http://johannesbrodwall.com/2008/02/21/rails-4-a-real-blog/#comments</comments>
		<pubDate>Fri, 22 Feb 2008 02:06:03 +0000</pubDate>
		<dc:creator>Johannes Brodwall</dc:creator>
				<category><![CDATA[Ruby-on-Rails]]></category>

		<guid isPermaLink="false">http://www.brodwall.com/johannes/blog/2008/02/21/rails-4-a-real-blog/</guid>
		<description><![CDATA[This is the fourth article in my introduction to Rails. In the previous articles, we created a web application that let us edit articles, added support for comments to our articles, and added some nice AJAX effects. But a real blog needs feeds, a decent front page and some article formatting. In this article we [...]]]></description>
			<content:encoded><![CDATA[<p>This is the fourth article in my introduction to Rails. In the previous articles, we <a href="http://www.brodwall.com/johannes/blog/2008/01/26/rails-intro-1-a-data-management-application-in-five-easy-steps/">created a web application that let us edit articles</a>, <a href="http://www.brodwall.com/johannes/blog/2008/01/28/rails-intro-2-one-to-many-relationships/">added support for comments to our articles</a>, and <a href="http://www.brodwall.com/johannes/blog/2008/02/16/rails-3-ajax/">added some nice AJAX effects</a>. But a real blog needs feeds, a decent front page and some article formatting. In this article we will add all these. The article contains no groundbreaking features, but mostly dots a few i&#8217;s and crosses a few t&#8217;s both when it comes to the blog we&#8217;re building, and details in Rails.</p>
<h3>My pretty, pretty articles</h3>
<p>Our articles are currently not formatted. We want to support a simple markup language. As it turns out <a href="http://hobix.com/textile/">textile</a> is perfect for the job. It transforms stuff &#8220;*like* _this_&#8221; to stuff &#8220;<b>like</b> <i>this</i>&#8220;. Let&#8217;s add textile support:</p>
<ol>
<li>Ruby support for textile is available in the <a href="http://whytheluckystiff.net/ruby/redcloth/">RedCloth</a> gem. Install it by typing <code>gem install RedCloth</code> on the command line.</li>
<li>Import RedCloth in your Rails application. In <code>config/environment.rb</code> add the line <code>require 'RedCloth'</code> (after the other line that starts with &#8216;require&#8217;).</li>
<li>Let&#8217;s add a helper for textile for all views. In <code>app/helper/application_helper.rb</code>, add the following:

<div class="wp_syntax"><div class="code"><pre class="rails" style="font-family:monospace;"><span style="color:#9966CC; font-weight:bold;">def</span> textile<span style="color:#006600; font-weight:bold;">&#40;</span>text<span style="color:#006600; font-weight:bold;">&#41;</span>
  RedCloth.<span style="color:#5A0A0A; font-weight:bold;">new</span><span style="color:#006600; font-weight:bold;">&#40;</span>html_escape<span style="color:#006600; font-weight:bold;">&#40;</span>text<span style="color:#006600; font-weight:bold;">&#41;</span><span style="color:#006600; font-weight:bold;">&#41;</span>.<span style="color:#9900CC;">to_html</span>
<span style="color:#9966CC; font-weight:bold;">end</span>
<span style="color:#9966CC; font-weight:bold;">def</span> intro<span style="color:#006600; font-weight:bold;">&#40;</span>text<span style="color:#006600; font-weight:bold;">&#41;</span>
  paras = text.<span style="color:#CC0066; font-weight:bold;">split</span> <span style="color:#006600; font-weight:bold;">/</span>\n\n<span style="color:#006600; font-weight:bold;">/</span>
  textile paras<span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#006666;">0</span><span style="color:#006600; font-weight:bold;">&#93;</span>
<span style="color:#9966CC; font-weight:bold;">end</span></pre></div></div>

</li>
<li>Update the views: In <code>app/view/articles/show.html.erb</code> change <code>&lt;%=h article.content %></code> (&#8220;h&#8221; is short for <code>html_escape</code>) and replace with <code>&lt;=textile article.content %></code>. Similarly change <code>app/view/comments/_comment.hml.erb</code> and replace <code>&lt;%=h comment.body %></code> with <code>&#038;l;%= textile comment.body %></code>. (We will deal with the article index later)</li>
<li>Try adding some textile markup to your articles and test out the effect. You can put your test data in <code>test/fixtures/articles.yml</code> and load it with <code>rake db:fixtures:load</code> if you&#8217;re too lazy to type it in the forms.</li>
</ol>
<h3>A good first impression</h3>
<p>If you&#8217;ve followed the article series, when you go to <a href="http://localhost:3000/">http://localhost:3000</a>, you are presented with the default Rails-constructed start page. Lets make a more inviting web page and start at the articles page instead:</p>
<ol>
<li>In <code>config/routes.rb</code>, add a root route: <code>map.root :controller => 'articles'</code>. The comments in the file describes this further.</li>
<li>Files in the <code>public/</code> folder will take precedence over the routes, so you also need to delete <code>public/index.html</code>.</li>
<li>If you go the <a href="http://localhost:3000">http://localhost:3000</a>, you will now be presented with the articles list. It looks horrible. Let&#8217;s clean up <code>app/views/articles/index.html.erb</code>. Here is my final version (the <code>intro</code> function was defined earlier in this blog post):

<div class="wp_syntax"><div class="code"><pre class="rails" style="font-family:monospace;">&lt;h1&gt;Welcome to my blog&lt;/h1&gt;
&nbsp;
&lt; % for article in @articles %&gt;
  &lt;div class=&quot;article&quot; id=&quot;<span style="color:#006600; font-weight:bold;">&lt;%</span>= dom_id<span style="color:#006600; font-weight:bold;">&#40;</span>article<span style="color:#006600; font-weight:bold;">&#41;</span> <span style="color:#006600; font-weight:bold;">%&gt;</span>&quot;&gt;
    &lt;h2&gt;
        &lt; %= link_to h(article.title), article %&gt;
        &lt;small&gt;(by &lt; %= article.author %&gt;)&lt;/small&gt;
    &lt;/h2&gt;
    &lt;div class=&quot;body&quot;&gt;&lt; %= intro article.content %&gt;&lt;/div&gt;
  &lt;/div&gt;
&lt; % end %&gt;
&nbsp;
&lt;br /&gt;
&nbsp;
&lt; %= link_to 'New article', new_article_path %&gt;</pre></div></div>

</li>
<li>We also need rss feeds for all our pages. Luckily, Rails comes with lots of built in support for this. First: We want to add auto discovery of the link in browsers that support this. <code>app/view/layouts/articles.html.erb</code> is applied around each page from the articles-controller, with the contents being displayed where the layout says <code>&lt;%= yield %></code>. Add the following to the &lt;head> in <code>app/view/layouts/articles.html.erb</code>:  <code>&lt;%= <a href="http://api.rubyonrails.org/classes/ActionView/Helpers/AssetTagHelper.html#M001021">auto_discovery_link_tag</a> :rss, { :controller => 'articles', :format => :rss } %></code>. If you refresh the page, you may notice a small RSS icon in the address bar of your browser! If you want to make the blog look nicer, the layout is also a good place to start.</li>
<li>Clicking the RSS icon lets you go to the RSS action. However, this just takes you to a blank page. You have to go to <code>app/controllers/articles_controller.rb</code> add a line to the <code>index</code> action&#8217;s <code>respond_to</code> block with <code>format.rss</code>. Refreshing will now give you a proper error message: &#8220;Missing template articles/index.rss.erb&#8221;</li>
<li>Create a file named <code>app/views/articles/index.rss.builder</code>. Files with &#8220;.builder&#8221; extensions are regular Ruby files, but in these files, a special object named <a href="http://api.rubyonrails.org/classes/Builder/XmlMarkup.html">xml</a> is available (much like the <a href="http://www.brodwall.com/johannes/blog/2008/02/16/rails-3-ajax/">&#8220;rjs&#8221; files we worked with earlier</a>). We can use this to create RSS feeds. (w3schools have a <a href="http://www.w3schools.com/rss/rss_syntax.asp">useful RSS syntax reference</a>). Here is mine:

<div class="wp_syntax"><div class="code"><pre class="rails" style="font-family:monospace;">xml.<span style="color:#9900CC;">rss</span> <span style="color:#ff3333; font-weight:bold;">:version</span><span style="color:#006600; font-weight:bold;">=&gt;</span><span style="color:#996600;">&quot;2.0&quot;</span> <span style="color:#9966CC; font-weight:bold;">do</span>
  xml.<span style="color:#9900CC;">channel</span> <span style="color:#9966CC; font-weight:bold;">do</span>
    xml.<span style="color:#9900CC;">title</span> <span style="color:#996600;">&quot;My cool blog&quot;</span>
    xml.<span style="color:#9900CC;">link</span> articles_url
    xml.<span style="color:#9900CC;">description</span> <span style="color:#996600;">&quot;I have made a blog - take a look&quot;</span>
    <span style="color:#9966CC; font-weight:bold;">for</span> article <span style="color:#9966CC; font-weight:bold;">in</span> <span style="color:#0066ff; font-weight:bold;">@articles</span>
      xml.<span style="color:#9900CC;">item</span> <span style="color:#9966CC; font-weight:bold;">do</span>
        xml.<span style="color:#9900CC;">title</span> article.<span style="color:#9900CC;">title</span>
        xml.<span style="color:#9900CC;">link</span> article_url<span style="color:#006600; font-weight:bold;">&#40;</span>article<span style="color:#006600; font-weight:bold;">&#41;</span>
        xml.<span style="color:#9900CC;">description</span> intro<span style="color:#006600; font-weight:bold;">&#40;</span>article.<span style="color:#9900CC;">content</span><span style="color:#006600; font-weight:bold;">&#41;</span>
      <span style="color:#9966CC; font-weight:bold;">end</span>
    <span style="color:#9966CC; font-weight:bold;">end</span>
  <span style="color:#9966CC; font-weight:bold;">end</span>
<span style="color:#9966CC; font-weight:bold;">end</span></pre></div></div>

</li>
<li>Refreshing the feed will now give you a complete RSS feed and the option to subscribe to it if your browser supports this.</li>
</ol>
<h3>Did they respond to my comment?</h3>
<p>Many blogs lack a RSS for comments. This means that you&#8217;ll have a hard time keeping track of whether someone responded to our comment. We want to do better, and learn some more about routing at the same time:</p>
<ol>
<li>Add another auto discovery link to <code>app/views/layouts/articles.html.erb</code> after the first one: <code>&lt;%= auto_discovery_link_tag :rss, { :controller => 'comments', :article_id => @article, :format => :rss }, { :title => 'Comments' } %></code>.</li>
<li>Go to an article that has some comments, and click the RSS icon by the address bar. In Firefox, this will how a menu of the two feeds, both labeled &#8220;Subscribe to &#8216;Comments&#8217;&#8221;. Click the link to view the comments feed.</li>
<li>Creating the feed will be just like the article feed: You have to add <code>format.rss</code> to the <code>respond_to block</code> for the <code>index</code> action of <code>app/controllers/comments_controller.rb</code> and add <code>app/view/comments/index.rss.builder</code>. Go ahead and do that now.</li>
<li>In <code>app/view/comments/index.rss.builder</code>, I made the item link point to <code>xml.link comment_url(comment)</code>. You will have to define comment_url in <code>app/helpers/comments_helper.rb</code> (pay attention to the <code>:only_path</code> parameter):

<div class="wp_syntax"><div class="code"><pre class="rails" style="font-family:monospace;"><span style="color:#9966CC; font-weight:bold;">def</span> comment_url<span style="color:#006600; font-weight:bold;">&#40;</span>comment<span style="color:#006600; font-weight:bold;">&#41;</span>
  <span style="color:#5A0A0A; font-weight:bold;">url_for</span> <span style="color:#ff3333; font-weight:bold;">:controller</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#996600;">'comments'</span>, <span style="color:#ff3333; font-weight:bold;">:action</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#996600;">'show'</span>, 
      <span style="color:#ff3333; font-weight:bold;">:article_id</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> comment.<span style="color:#9900CC;">article</span>, <span style="color:#ff3333; font-weight:bold;">:id</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> comment, 
      <span style="color:#ff3333; font-weight:bold;">:only_path</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#0000FF; font-weight:bold;">false</span>
<span style="color:#9966CC; font-weight:bold;">end</span></pre></div></div>

</li>
<li>We have let <code>comment_url</code> and <code>comment_path</code> in both <code>app/controllers/comments_controller.rb</code> and <code>app/helpers/comments_helper.rb</code> point to the comments view. This is a pretty lame page, and we don&#8217;t want to make separate pages for the comments anyway. Instead: Hyperlink to an anchor to the comments: <code>:controller => 'articles', :action => 'show', :id => comment.article, :anchor => dom_id(comment)</code> in both the helper and the controller. Now all our links are fixed with one fell swoop! Delete <code>app/views/comments/show.html.erb</code> while you&#8217;re at it. This will break your tests in <code>test/functional/comments_controller_test.rb</code> so make sure you fix them. Both <code>test_should_create_comment</code> and <code>test_should_update_comment</code> should redirect to <code>assert_redirected_to article_path(:id => assigns(:article), :anchor => @controller.dom_id(assigns(:comment)))</code>. <code>test_should_show</code> is no longer valid and can be deleted.</li>
</ol>
<p>We now have a nice feed for the articles and comments, with hyperlinks that take us to the right place. However, we have opened a problem: If you try to subscribe to comments from the front page, you will get angry error messages about the fact that you can&#8217;t find the related article to search for comments for. We could avoid displaying this link when there&#8217;s no active article by doing something like <code>&lt;%= auto_discovery_link_tag .... if @article %></code>, but instead, we&#8217;ll use the chance to learn how to create a route for all comments.</p>
<ol>
<li>The problem starts with <code>app/controllers/comments_controller.rb</code> in the method <code>find_article</code>. Change the contents of the method to <code>@article = Article.find(params[:article_id]) if params[:article_id]</code>. This moves the problem to the <code>index</code> action. Change the first line to use <code>Comment.find</code> if there&#8217;s no article: <code>@comments = @article ? @article.comments.find(:all) : Comment.find(:all)</code> (For extremists, this could be written: <code>(@article ? @article.comments : Comment).find(:all)</code>).</li>
<li>You will also have to update <code>app/views/comments/index.rss.builder</code> to deal with @article being nil. For the channel link, I did: <code>xml.link @article ? article_url(@article) : all_comments_url</code>. But what is <code>all_comments_url</code>?</li>
<li>Enter <code>config/routes.rb</code>. Add the following route: <code>map.resources :comments, :name_prefix => 'all_'</code>. Your view now works. And what is more, you can even go directly to <a href="http://localhost:3000/comments">http://localhost:3000/comments</a> to view all comments. But in order for this to work, you will have to update <code>app/views/comments/index.html.erb</code> and remove the link to create a new comment.</li>
</ol>
<h3>An issue of trust</h3>
<p>We have created a blog with quite a few nice features: Comments, AJAX-support, RSS feeds and formatting. If you have been following along, I hope you have been impressed with the speed with which you can create an application in Ruby-on-Rails.</p>
<p>However, if you&#8217;ve been working with development for any time, you have probably seen quite a few examples of technology which starts of promising, but then falls apart when you try to create something that could actually be usable in the real world. So the next time, I plan to do the responsible thing and add security and authentication, so that not just anybody can create and edit articles! In the process, we will get to use sessions and more advanced active record relationships.</p>
]]></content:encoded>
			<wfw:commentRss>http://johannesbrodwall.com/2008/02/21/rails-4-a-real-blog/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Rails #3: AJAX</title>
		<link>http://johannesbrodwall.com/2008/02/16/rails-3-ajax/</link>
		<comments>http://johannesbrodwall.com/2008/02/16/rails-3-ajax/#comments</comments>
		<pubDate>Sun, 17 Feb 2008 02:41:15 +0000</pubDate>
		<dc:creator>Johannes Brodwall</dc:creator>
				<category><![CDATA[Ruby-on-Rails]]></category>

		<guid isPermaLink="false">http://www.brodwall.com/johannes/blog/2008/02/16/rails-3-ajax/</guid>
		<description><![CDATA[In my previous articles, I showed you how to get started using Rails, and how to create model objects that are associated with each other. In this article, we will clean up the way that information is displayed and add support for dynamic HTML, or as the cool kids are calling it these days, AJAX.
A [...]]]></description>
			<content:encoded><![CDATA[<p>In my previous articles, I showed you <a href="http://www.brodwall.com/johannes/blog/2008/01/26/rails-intro-1-a-data-management-application-in-five-easy-steps/">how to get started using Rails</a>, and <a href="http://www.brodwall.com/johannes/blog/2008/01/28/rails-intro-2-one-to-many-relationships/">how to create model objects that are associated with each other</a>. In this article, we will clean up the way that information is displayed and add support for dynamic HTML, or as the cool kids are calling it these days, AJAX.</p>
<h3>A view to die for</h3>
<p>First, clean up <code>app/views/articles/show.hml.erb</code>. I am assuming you know enough HTML to be able to make it look reasonably blog like. Following is a suggested starting point. The only thing that is critical to follow allow the text of this tutorial, is the id of the &#8220;new_comment&#8221; div. This will be used as a target for our AJAX code.</p>

<div class="wp_syntax"><div class="code"><pre class="rails" style="font-family:monospace;">&lt;div class=&quot;article&quot;&gt;
  &lt;h2&gt;<span style="color:#006600; font-weight:bold;">&lt;%</span>=h <span style="color:#0066ff; font-weight:bold;">@article</span>.<span style="color:#9900CC;">title</span> <span style="color:#006600; font-weight:bold;">%&gt;</span>&lt;/h2&gt;
  &lt;h3&gt;
    By <span style="color:#006600; font-weight:bold;">&lt;%</span>=h <span style="color:#0066ff; font-weight:bold;">@article</span>.<span style="color:#9900CC;">author</span> <span style="color:#006600; font-weight:bold;">%&gt;</span>
    &lt;small&gt;<span style="color:#006600; font-weight:bold;">&lt;%</span>= <span style="color:#5A0A0A; font-weight:bold;">link_to</span> <span style="color:#996600;">&quot;[ edit ]&quot;</span>, edit_article_path<span style="color:#006600; font-weight:bold;">&#40;</span>@article<span style="color:#006600; font-weight:bold;">&#41;</span> <span style="color:#006600; font-weight:bold;">%&gt;</span>&lt;/small&gt;	
  &lt;/h3&gt;
&nbsp;
  <span style="color:#006600; font-weight:bold;">&lt;%</span>=h <span style="color:#0066ff; font-weight:bold;">@article</span>.<span style="color:#9900CC;">content</span> <span style="color:#006600; font-weight:bold;">%&gt;</span>
&lt;/div&gt;
&nbsp;
&lt;div id=&quot;comments&quot;&gt;
  &lt;h2&gt;Comments&lt;/h2&gt;
&nbsp;
  <span style="color:#006600; font-weight:bold;">&lt;%</span> <span style="color:#9966CC; font-weight:bold;">for</span> comment <span style="color:#9966CC; font-weight:bold;">in</span> <span style="color:#0066ff; font-weight:bold;">@article</span>.<span style="color:#9900CC;">comments</span> <span style="color:#006600; font-weight:bold;">%&gt;</span>
    &lt;div id=&quot;<span style="color:#006600; font-weight:bold;">&lt;%</span>= dom_id<span style="color:#006600; font-weight:bold;">&#40;</span>comment<span style="color:#006600; font-weight:bold;">&#41;</span> <span style="color:#006600; font-weight:bold;">%&gt;</span>&quot; class=&quot;comment&quot;&gt;
      &lt;h3&gt;<span style="color:#006600; font-weight:bold;">&lt;%</span>=h comment.<span style="color:#9900CC;">title</span> <span style="color:#006600; font-weight:bold;">%&gt;</span> (by <span style="color:#006600; font-weight:bold;">&lt;%</span>=h comment.<span style="color:#9900CC;">author</span> <span style="color:#006600; font-weight:bold;">%&gt;</span>)&lt;/h3&gt;
      &lt;p&gt;<span style="color:#006600; font-weight:bold;">&lt;%</span>=h comment.<span style="color:#9900CC;">body</span> <span style="color:#006600; font-weight:bold;">%&gt;</span>&lt;/p&gt;
    &lt;/div&gt;
  <span style="color:#006600; font-weight:bold;">&lt;%</span> <span style="color:#9966CC; font-weight:bold;">end</span> <span style="color:#006600; font-weight:bold;">%&gt;</span>
&nbsp;
  &lt;div id=&quot;new_comment&quot;&gt;
    &lt;h2&gt;Add your comment&lt;/h2&gt;
    <span style="color:#006600; font-weight:bold;">&lt;%</span>= <span style="color:#5A0A0A; font-weight:bold;">error_messages_for</span> <span style="color:#ff3333; font-weight:bold;">:comment</span> <span style="color:#006600; font-weight:bold;">%&gt;</span>
    <span style="color:#006600; font-weight:bold;">&lt;%</span> <span style="color:#5A0A0A; font-weight:bold;">form_for</span> <span style="color:#ff3333; font-weight:bold;">:comment</span>, <span style="color:#ff3333; font-weight:bold;">:url</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> comments_url<span style="color:#006600; font-weight:bold;">&#40;</span>@article<span style="color:#006600; font-weight:bold;">&#41;</span> <span style="color:#9966CC; font-weight:bold;">do</span> <span style="color:#006600; font-weight:bold;">|</span>f<span style="color:#006600; font-weight:bold;">|</span> <span style="color:#006600; font-weight:bold;">%&gt;</span>
      &lt;p&gt;<span style="color:#006600; font-weight:bold;">&lt;%</span>= f.<span style="color:#9900CC;">label</span> <span style="color:#ff3333; font-weight:bold;">:title</span> <span style="color:#006600; font-weight:bold;">%&gt;</span> <span style="color:#006600; font-weight:bold;">&lt;%</span>= f.<span style="color:#9900CC;">text_field</span> <span style="color:#ff3333; font-weight:bold;">:title</span> <span style="color:#006600; font-weight:bold;">%&gt;</span>&lt;/p&gt;
      &lt;p&gt;<span style="color:#006600; font-weight:bold;">&lt;%</span>= f.<span style="color:#9900CC;">label</span> <span style="color:#ff3333; font-weight:bold;">:author</span> <span style="color:#006600; font-weight:bold;">%&gt;</span> <span style="color:#006600; font-weight:bold;">&lt;%</span>= f.<span style="color:#9900CC;">text_field</span> <span style="color:#ff3333; font-weight:bold;">:author</span> <span style="color:#006600; font-weight:bold;">%&gt;</span>&lt;/p&gt;
      &lt;p&gt;<span style="color:#006600; font-weight:bold;">&lt;%</span>= f.<span style="color:#9900CC;">label</span> <span style="color:#ff3333; font-weight:bold;">:body</span> <span style="color:#006600; font-weight:bold;">%&gt;</span> &lt;br /&gt;<span style="color:#006600; font-weight:bold;">&lt;%</span>= f.<span style="color:#5A0A0A; font-weight:bold;">text_area</span> <span style="color:#ff3333; font-weight:bold;">:body</span>, <span style="color:#ff3333; font-weight:bold;">:rows</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#006666;">5</span> <span style="color:#006600; font-weight:bold;">%&gt;</span>&lt;/p&gt;
      &lt;p&gt;<span style="color:#006600; font-weight:bold;">&lt;%</span>= f.<span style="color:#9900CC;">submit</span> <span style="color:#996600;">&quot;Create&quot;</span> <span style="color:#006600; font-weight:bold;">%&gt;</span>&lt;/p&gt;	
    <span style="color:#006600; font-weight:bold;">&lt;%</span> <span style="color:#9966CC; font-weight:bold;">end</span> <span style="color:#006600; font-weight:bold;">%&gt;</span>
  &lt;/div&gt;
&lt;/div&gt;</pre></div></div>

<h3>Partially better</h3>
<p>The easiest way to use Rails AJAX support is to redraw parts of the view from the server. You can remove many sources of error by making sure that you&#8217;re using exactly the same HTML + ERb code to render the new views from the AJAX requests. This is a good place to introduce another Rails technique: Partials.</p>
<ol>
<li>Replace the code from <code>&lt;% for comment %&gt;</code> to the corresponding <code>&lt;% end %&gt;</code> section with a call to <a href="http://api.rubyonrails.org/classes/ActionController/Base.html#M000452"><code>render</code></a> method like so: <code>&lt;%= render :partial => 'comments/comment', :collection => @article.comments %></code></li>
<li>Move the <code>&lt;div&gt;</code> used for the comment to a new file, <code>app/views/comments/_comment.html.erb</code></li>
<li>The call to <a href="http://api.rubyonrails.org/classes/ActionView/TemplateHandler.html#M001084"><code>render :partial</code></a> means to call the file <code>app/views/comments/_comment.html.erb</code> for each comment in @article.comment. Each comment will be assigned to the variable <code>comment</code> in turn.</li>
<li>That&#8217;s it &#8211; your comment code is refactored out</li>
</ol>
<p>Second, we do the same with the form for adding new comments:</p>
<ol>
<li>Replace the <code>&lt;div id="new_comment"&gt;</code> for new comments with a call to another partial: <code>&lt;%= render :partial => 'comments/new' %&gt;</code></li>
<li>Move the code for the new comment unchanged into a new file called <code>app/views/comments/_new.html.erb</code>.</li>
</ol>
<p>The view still looks the same in the browser, but we&#8217;re now posed to awe the world with our mad AJAX skills.</p>
<h3>AJAX</h3>
<p>Using AJAX is very easy, so I will just jump straight into it:</p>
<ol>
<li>Make the client loads the necessary Javascript files: Add the line <code>&lt;%= javascript_include_tag :defaults %&gt;</code> to the <code>&lt;head&gt;</code> section in <code>app/views/layout/articles.html.erb</code>.  I bet you wondered where the title on the pages came from. Now you know.</li>
<li>In <code>app/views/comments/_new.html.erb</code>, replace the call to <code>form_for</code> with an identical call to <a href="http://api.rubyonrails.org/classes/ActionView/Helpers/PrototypeHelper.html#M000961"><code>remote_form_for</code></a>.</li>
<li>In theory, this is all you need to do, and your form is now AJAX enabled, but we also have to specify what actions should be performed when the submit button is pushed. Right now, if you fill in a form and press submit, it will look as if nothing is happening. But if you refresh the page, you will see that the comment was indeed added to the database.</li>
<li>Declare that creating a comment should support AJAX: In <code>app/controllers/comments_controller.rb</code>, find the method <code>create</code> and add <code>format.js</code> in the &#8220;if&#8221; block of method. Notice that no {} or anything is needed for this line (just like with most format.html calls in the other controller methods).</li>
<li>Add the file <code>app/views/comments/create.js.rjs</code>. This will contain the code for what should be rendered when the user submits the form.</li>
<li>RJS files are plain Ruby files, with a special object called <a href="http://api.rubyonrails.org/classes/ActionView/Helpers/PrototypeHelper/JavaScriptGenerator/GeneratorMethods.html">page</a> available. In <code>app/views/comments/create.js.rjs</code>, just enter a single line: <code>page.insert_html :before, 'new_comment', :partial => "comments/comment"</code></li>
<li>That&#8217;s it, if you post a comment, after some delay, it is displayed right before the new comment form.</li>
</ol>
<h3>Make it good</h3>
<p>The AJAX now works, but it leaves a lot to be desired. Here are some improvements:</p>
<ol>
<li>Make the new comment stand out visually after it is created. Add the following to <code>app/views/comments/create.js.rjs</code>: <code>page[dom_id(@comment)].visual_effect :highlight</code>. (Or pick another effect from the <a href="http://wiki.script.aculo.us/scriptaculous/show/CombinationEffectsDemo">script.acol.us</a> webpage)</li>
<li>Clear the form. Add the following to <code>app/views/comments/create.js.rjs</code>:

<div class="wp_syntax"><div class="code"><pre class="rails" style="font-family:monospace;"><span style="color:#0066ff; font-weight:bold;">@comment</span> = Comment.<span style="color:#5A0A0A; font-weight:bold;">new</span>
page<span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#996600;">'new_comment'</span><span style="color:#006600; font-weight:bold;">&#93;</span>.<span style="color:#5A0A0A; font-weight:bold;">replace</span> <span style="color:#ff3333; font-weight:bold;">:partial</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#996600;">&quot;comments/new&quot;</span>
page<span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#996600;">'new_comment'</span><span style="color:#006600; font-weight:bold;">&#93;</span>.<span style="color:#5A0A0A; font-weight:bold;">visual_effect</span> <span style="color:#ff3333; font-weight:bold;">:slide_down</span></pre></div></div>

</li>
<li>Add a progress indicator: In <code>app/views/comments/_new.html.erb</code>, add the following line inside the &#8220;new_comment&#8221; div: <code>&lt;div id="progress" style="display: none">Saving...&lt;/div></code> and the <a href="http://api.rubyonrails.org/classes/ActionView/Helpers/PrototypeHelper.html#M000958">:loading</a> option to the call to remote_form_for: <code>:loading => "Element.show('progress')"</code>.</li>
<li>Even better, create a progress indicator at <a href="http://ajaxload.info">ajaxload.info</a>. Download the image as <code>public/images/ajax-loader.gif</code>, and replace the contents of the progress div with <code>&lt;%= image_tag "ajax-loader.gif", :alt => "saving..." %></code>.</li>
<li>Error handling doesn&#8217;t work. If you add some validation to the model, you will notice that the page behaves very poorly when the validation fails. Add the <a href="http://api.rubyonrails.org/classes/ActiveRecord/Validations/ClassMethods.html#M001327">following line</a> to <code>app/models/comment.rb</code>: <code>validates_presence_of :title, :author, :body</code>. If you try to submit a form that is missing one of these fields, the page will never update and the progress indicator will just keep going. To fix this, you can add the following line to the &#8220;else&#8221; block of the <code>create</code> method of <code>app/controllers/comments_controller.rb</code>: <code>format.js { render :update do |page| page['new_comment'].replace :partial => 'new'; end }</code>. This acts just as the RJS template from before, but without using a separate file (if you make this change, you will have to update your tests).</li>
<li>You might also want to do something about the &#8220;flash&#8221;, but explaining that requires too much details, so I will leave that for another day.</li>
</ol>
<h3>AJAX goodness</h3>
<p>We&#8217;ve covered the basics of AJAX: Using partials to make your views flexible, using remote_form_for to make the form submit asynchronously using JavaScript, and using RJS templates to generate JavaScript using Ruby.</p>
<p>There are many other options for using AJAX out there, and you might want to explore the field further. Ultimately, nothing beats JavaScript for JavaScript. That being said, built-in AJAX support in Rails is my favorite way to get started.</p>
<p>I hope you&#8217;ve enjoyed this tutorial. Some of the topics I am considering covering now are: Sessions, XML and RSS, development howtos like deployment, testing and application structure, or something completely different. Thanks a lot your for comments to my previous articles via the blog or email. Let me know what you want next.</p>
]]></content:encoded>
			<wfw:commentRss>http://johannesbrodwall.com/2008/02/16/rails-3-ajax/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Rails intro #2: One-to-many relationships</title>
		<link>http://johannesbrodwall.com/2008/01/28/rails-intro-2-one-to-many-relationships/</link>
		<comments>http://johannesbrodwall.com/2008/01/28/rails-intro-2-one-to-many-relationships/#comments</comments>
		<pubDate>Tue, 29 Jan 2008 01:29:23 +0000</pubDate>
		<dc:creator>Johannes Brodwall</dc:creator>
				<category><![CDATA[Ruby-on-Rails]]></category>

		<guid isPermaLink="false">http://www.brodwall.com/johannes/blog/2008/01/28/rails-intro-2-one-to-many-relationships/</guid>
		<description><![CDATA[In my last article, I showed you how to get started with your Rails application. The result of the simple commands, rails blogdemo; cd blogdemo; ruby script/generate scaffold article title:string author:string content:text; rake db:migrate; ruby script/server was that you had your own simple blog up and running. The blog support articles each of which have [...]]]></description>
			<content:encoded><![CDATA[<p>In my <a href="http://www.brodwall.com/johannes/blog/2008/01/26/rails-intro-1-a-data-management-application-in-five-easy-steps/">last article</a>, I showed you how to get started with your Rails application. The result of the simple commands, <code>rails blogdemo; cd blogdemo; ruby script/generate scaffold article title:string author:string content:text; rake db:migrate; ruby script/server</code> was that you had your own simple blog up and running. The blog support articles each of which have a title, an author, and text content. This initial model was generated for us with no editing on our part.</p>
<p>In this second article, I will expand the blog to allow comments to our articles. This will require us to get our hands a bit more dirty with the Rails code, but it won&#8217;t be too bad. And even better: If you complete the instructions in this article, you can call yourself a Rails programmer!</p>
<p>Are you ready to dive in head first?</p>
<h3>The initial structure</h3>
<ol>
<li>Like in the example with the article model class, we create a comment model. <code>ruby script/generate scaffold comment article_id:integer title:string author:string body:text</code>. Notice the article_id column, which will be our foreign key to the article.</li>
<li>rake db:migrate db:fixtures:load test</li>
<li>You can now see the comments at <a href="http://localhost:3000/comments/">http://localhost:3000/comments/</a></li>
</ol>
<h3>Connecting the comments to articles</h3>
<p>To get the articles and comments connected, we need to do four things. I will take you thought the process in detail.</p>
<ol>
<li>We have to update the <em>routes</em> for URLs to let Rails know how to connect articles to comments</li>
<li>We have to update the <em>model</em> classes for the two classes, to let them know about the relationship</li>
<li>We have to update the Comments<em>Controller</em> to refer to the correct article when it finds, creates or modifies a comment.</li>
<li>We have to include the information about the comments in the article <em>views</em>.</li>
</ol>
<p>Here we go:</p>
<ol>
<li>Lets start with routing. The file <code>config/routes.rb</code> tells us how our application URLs are structured. Remove <code>map.resource :comments</code>, and add <code>comments</code> as a &#8220;<a href="http://api.rubyonrails.org/classes/ActionController/Resources.html#M000308">nested route</a>&#8221; instead:

<div class="wp_syntax"><div class="code"><pre class="rails" style="font-family:monospace;"> map.<span style="color:#9900CC;">resources</span> <span style="color:#ff3333; font-weight:bold;">:articles</span> <span style="color:#9966CC; font-weight:bold;">do</span> <span style="color:#006600; font-weight:bold;">|</span>article<span style="color:#006600; font-weight:bold;">|</span>
    article.<span style="color:#9900CC;">resources</span> <span style="color:#ff3333; font-weight:bold;">:comments</span>, <span style="color:#ff3333; font-weight:bold;">:name_prefix</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#0000FF; font-weight:bold;">nil</span>
  <span style="color:#9966CC; font-weight:bold;">end</span></pre></div></div>

<p>  This change means that you will find the comments like this: http://localhost:3000/articles/<i>article-id</i>/comments/</li>
<li>Update <code>app/view/articles/show.html.erb</code> so we can get the comments related to an article. Add the following code:<code>&lt;%= link_to "Comments", comments_path(@article) %&gt;</code></li>
<li>http://localhost:3000/comments/ no longer works. Instead: Select an article, and click the new Comments link. This gives an error, because the routes we generated don&#8217;t take the relationship between articles and comments into consideration.</li>
<li>The best way to fix this is to change the methods we use to find comments. We can do this by updating the view helper in <code>app/helpers/comments_helper.rb</code>

<div class="wp_syntax"><div class="code"><pre class="rails" style="font-family:monospace;"><span style="color:#9966CC; font-weight:bold;">def</span> comment_path<span style="color:#006600; font-weight:bold;">&#40;</span>comment<span style="color:#006600; font-weight:bold;">&#41;</span>
  <span style="color:#5A0A0A; font-weight:bold;">url_for</span> <span style="color:#ff3333; font-weight:bold;">:controller</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#996600;">&quot;comments&quot;</span>, <span style="color:#ff3333; font-weight:bold;">:action</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#996600;">&quot;show&quot;</span>,
      <span style="color:#ff3333; font-weight:bold;">:article_id</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> comment.<span style="color:#9900CC;">article</span>, <span style="color:#ff3333; font-weight:bold;">:id</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> comment
<span style="color:#9966CC; font-weight:bold;">end</span>
<span style="color:#9966CC; font-weight:bold;">def</span> edit_comment_path<span style="color:#006600; font-weight:bold;">&#40;</span>comment<span style="color:#006600; font-weight:bold;">&#41;</span>
  <span style="color:#5A0A0A; font-weight:bold;">url_for</span> <span style="color:#ff3333; font-weight:bold;">:controller</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#996600;">&quot;comments&quot;</span>, <span style="color:#ff3333; font-weight:bold;">:action</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#996600;">&quot;edit&quot;</span>, 
      <span style="color:#ff3333; font-weight:bold;">:article_id</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> comment.<span style="color:#9900CC;">article</span>, <span style="color:#ff3333; font-weight:bold;">:id</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> comment
<span style="color:#9966CC; font-weight:bold;">end</span></pre></div></div>

</li>
<li>You now need to inform the model classes about each other via <a href="http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html#M001105">belongs_to</a> and <a href="http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html#M001103">has_many</a> associations. Update <code>app/models/article.rb</code> and <code>app/models/comment.rb</code>:

<div class="wp_syntax"><div class="code"><pre class="rails" style="font-family:monospace;"><span style="color:#9966CC; font-weight:bold;">class</span> Comment <span style="color:#006600; font-weight:bold;">&lt;</span> <span style="color:#6666ff; font-weight:bold;">ActiveRecord::Base</span>
  <span style="color:#5A0A0A; font-weight:bold;">belongs_to</span> <span style="color:#ff3333; font-weight:bold;">:article</span>
<span style="color:#9966CC; font-weight:bold;">end</span>
<span style="color:#9966CC; font-weight:bold;">class</span> Article <span style="color:#006600; font-weight:bold;">&lt;</span> <span style="color:#6666ff; font-weight:bold;">ActiveRecord::Base</span>
  <span style="color:#5A0A0A; font-weight:bold;">has_many</span> <span style="color:#ff3333; font-weight:bold;">:comments</span>
<span style="color:#9966CC; font-weight:bold;">end</span></pre></div></div>

</pre>
</li>
</ol>
<h3>Updating the controller</h3>
<p>If you click on the Comments link, you will now be rewarded with a seemingly meaningful set of comments for the current article. But appearances can be deceiving. We have still not made the controllers aware of the fact that only the comments for the current article should be displayed. If you click around in the application, it will soon become apparent that all comments are displayed under all articles! We need to update the controller to restrict to only comments for the current article.</p>
<ol>
<li>Update <code>app/controllers/comments_controller.rb</code>, and make sure we always have an article available. This is usually done through a "<a href="http://api.rubyonrails.org/classes/ActionController/Filters/ClassMethods.html#M000310">before_filter</a>". Add the following line to the beginning of the file: <code>before_filter :find_article</code>, right after the <code>class</code> line.</li>
<li>Implement the filter. Add the following to the very end of the class file, just before the final "end":

<div class="wp_syntax"><div class="code"><pre class="rails" style="font-family:monospace;">protected
  <span style="color:#9966CC; font-weight:bold;">def</span> find_article
      <span style="color:#0066ff; font-weight:bold;">@article</span> = Article.<span style="color:#9900CC;">find</span><span style="color:#006600; font-weight:bold;">&#40;</span>params<span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#ff3333; font-weight:bold;">:article_id</span><span style="color:#006600; font-weight:bold;">&#93;</span><span style="color:#006600; font-weight:bold;">&#41;</span>
  <span style="color:#9966CC; font-weight:bold;">end</span></pre></div></div>

</li>
<li>You can now replace every <code>find</code> and <code>new</code> on the Comment class with similar code in the article model. Replace every place where the code says <code>Comment.find(...)</code> with <code>@article.comments.find(...)</code>, and every place the code says <code>Comment.new(...)</code> with <code>@article.comments.new(...)</code></li>
<li>We also need to let the controller know how to redirect to a created or updated view. Add the following right after the end of the find_article code above.

<div class="wp_syntax"><div class="code"><pre class="rails" style="font-family:monospace;"> <span style="color:#9966CC; font-weight:bold;">def</span> comment_url<span style="color:#006600; font-weight:bold;">&#40;</span>comment<span style="color:#006600; font-weight:bold;">&#41;</span>
    <span style="color:#5A0A0A; font-weight:bold;">url_for</span> <span style="color:#ff3333; font-weight:bold;">:controller</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#996600;">&quot;comments&quot;</span>, <span style="color:#ff3333; font-weight:bold;">:action</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#996600;">&quot;show&quot;</span>,
        <span style="color:#ff3333; font-weight:bold;">:article_id</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> comment.<span style="color:#9900CC;">article</span>, <span style="color:#ff3333; font-weight:bold;">:id</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> comment
  <span style="color:#9966CC; font-weight:bold;">end</span></pre></div></div>

</li>
<li>Finally, we should never let the user give <code>article_id</code> in the input forms. To avoid this, you can add the line <code><a href="http://api.rubyonrails.org/classes/ActiveRecord/Base.html#M001390">attr_protected</a> :article_id</code> to <code>app/model/comment.rb</code></li>
</ol>
<p>At this stage, creating, viewing, updating and deleting comments should all work as expected. However, before we turn to the view, you might have noticed a strange thing with our test data. The comments generated by running <code>rake db:fixtures:load</code> are not connected to the correct articles. The place to fix this is in <code>test/fixtures/comments.yml</code>, and the way to fix it is <a href="http://railscasts.com/episodes/81">a new feature with Rails 2.0</a>:</p>
<p>In <code>test/fixtures/comments.yml</code>, change the lines that read <code>article_id: 1</code> into <code>article: one</code>. Regenerate the test data by running <code>rake db:fixtures:load</code>. Both articles should now be attached to your first article.</p>
<h3>Integrating the views</h3>
<p>Finally, we want to improve the way all this looks. Polishing the view will be the topic of my next article, so for now, let's just mash the information together.</p>
<ol>
<li>We want to display all the comments in the details view for an article. Replace the link we created to the comments in <code>app/view/articles/show.html.erb</code> with the full contents of <code>app/view/comments/index.html.erb</code></li>
<li>Still in <code>app/view/articles/show.html.erb</code>, replace <code>&lt;% for comment in @comments %&gt;</code> with <code>&lt;% for comment in @article.comments %&lt;</code> and <code>&lt;%= link_to 'New comment', new_comment_path %&gt;</code> with <code>&lt;%= link_to "New comment", new_comment_path(@article) %&gt;</code>. Your articles should now display the corresponding comments.</li>
<li>We also want our users to be able to add new comments when they view the article. Still in <code>app/view/articles/show.html.erb</code>, replace the "New comment" link with the full contents of <code>app/view/comments/index.html.erb</code>.</li>
<li>Replace <code>&lt;% form_for(@comment) do |f| %&gt;</code> with <code>&lt;% form_for :comment, :url => comments_path(@article) do |f| %&gt;</code> and remove the link <code>&lt;%= link_to 'Back', comments_path %&gt;</code></li>
<li>If you look at the page for an article now, you will be rewarded with a functional, but ugly page that despite its appearance displays the article, all comments for the article, and allows the users to add new comments.</li>
</ol>
<h3>Fixing the tests</h3>
<p>Before we leave, lets make sure that our tests still pass. Run <code>rake test</code>. You tests should fail at this point. This is because the tests don't supply the article_id attribute CommentsController now requires.</p>
<ol>
<li>All post and get requests in <code>test/functional/comments_controller_test.rb</code> need have an argument <code>:article_id => articles(:one)</code> added to them. For example: <code>get :index, :article_id => articles(:one)</code>. Do this for all the get and post requests in the test.</li>
<li>One test still doesn't run. In <code>test_should_create_comment</code> <code>assert_redirected_to comment_path(assigns(:comment))</code> should be changed to <code>assert_redirected_to comment_path(:id => assigns(:comment), :article_id => assigns(:article))</code></li>
<li>The tests should now pass.</li>
</ol>
<h3>Conclusion</h3>
<p>This more lengthy post takes you through all the steps that are needed to create a web application that displays a one-to-many relationship, namely that of one article having many comments. We had to update both the URL routing to make comments a nested resource, the model class to associate the comments and articles, the controller to only find comments on the current articles and the article views to include the comment data, but every change is fairly simple.</p>
<p>Until this point, I have assumed that you as a reader don't know much about Rails. After completing this article, you have touched quite a few of the core concepts of Rails already. If you found the ride too confusing because I didn't provide a lot of details about the way a Rails application works, I would very much like to know it.</p>
<p><a href="http://www.brodwall.com/johannes/blog/2008/02/16/rails-3-ajax/">The next article</a> in this series will clean up the view and add AJAX support.</p>
<p>Stay tuned, we are just getting started!</p>
]]></content:encoded>
			<wfw:commentRss>http://johannesbrodwall.com/2008/01/28/rails-intro-2-one-to-many-relationships/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Rails Intro #1: A data management application in five easy steps</title>
		<link>http://johannesbrodwall.com/2008/01/26/rails-intro-1-a-data-management-application-in-five-easy-steps/</link>
		<comments>http://johannesbrodwall.com/2008/01/26/rails-intro-1-a-data-management-application-in-five-easy-steps/#comments</comments>
		<pubDate>Sat, 26 Jan 2008 18:49:50 +0000</pubDate>
		<dc:creator>Johannes Brodwall</dc:creator>
				<category><![CDATA[Ruby-on-Rails]]></category>

		<guid isPermaLink="false">http://www.brodwall.com/johannes/blog/2008/01/26/rails-intro-1-a-data-management-application-in-five-easy-steps/</guid>
		<description><![CDATA[I am planning to write a series of articles on how to get started with Ruby on Rails. One of the remarkable things about Rails is that it lets you get up and running very quickly. Here is what you need to do to get your first application up and running.
Before you start, you need [...]]]></description>
			<content:encoded><![CDATA[<p>I am planning to write a series of articles on how to get started with Ruby on Rails. One of the remarkable things about Rails is that it lets you get up and running very quickly. Here is what you need to do to get your first application up and running.</p>
<p>Before you start, you need to install Ruby on Rails: On Macs, Rails is already available and you can type the following commands in a normal terminal window. On Windows, you can get everything you need from <a href="http://rubyforge.org/frs/?group_id=904">InstantRails</a>. Once you have unpacked InstantRails to a subfolder, start the &#8220;InstantRails.exe&#8221;. From the GUI that comes up, click the &#8220;I&#8221; button in the top left corner and select &#8220;Rails Applications&#8221; -> &#8220;Open Ruby Console Window&#8221; from the menu. The following commands should be typed in the command line window that shows up.</p>
<ol>
<li><code>rails blogdemo</code></li>
<li><code>cd blogdemo</code></li>
<li><small>(Optional: Look at how generators work &#8211; read the documentation that is printed)</small> <code>ruby script/generate</code></li>
<li><small>(Optional: Look at how generators work &#8211; read the documentation that is printed)</small> <code>ruby script/generate scaffold</code></li>
<li><code>ruby script/generate scaffold article title:string author:string content:text</code></li>
<li><small>(Optional: Look for the documentation on the &#8220;rake&#8221; command)</small> <code>rake --tasks</code></li>
<li><small>(Optional: Look for the documentation on the &#8220;rake&#8221; command)</small> <code>rake -T db</code></li>
<li><code>rake db:create:all</code></li>
<li><code>rake db:migrate</code></li>
<li><small>(Optional: Load generated test data into the database)</small> <code>rake db:fixtures:load</code></li>
<li><small>(Optional: Run the generated tests)</small> <code>rake test</code></li>
<li><code>ruby script/server</code></li>
<li>You should now be able to view your wonderful application at <a href="http://localhost:3000/articles">http://localhost:3000/articles</a></li>
<li>Be sure to read the documentation at <a href="http://localhost:3000/">http://localhost:3000/</a> as well</li>
</ol>
<p>Enjoy your first rails application!</p>
<p><a href='http://www.brodwall.com/johannes/blog/wp-content/uploads/2008/01/articles-list.PNG' title='Generated article list'><img src='http://www.brodwall.com/johannes/blog/wp-content/uploads/2008/01/articles-list.PNG' alt='Generated article list' width="300" /></a></p>
<p>If you find the results satisfying, you should start by exploring the directory structure of the files generated by Rails. In my next article, I will tell you how to generate more advanced data structures, so that we can add comments to our blog articles. (Still to come future: How to setup a server and deploy to it, tips on working with your code, exploring the rails structure, AJAX, and RSS feeds)</p>
]]></content:encoded>
			<wfw:commentRss>http://johannesbrodwall.com/2008/01/26/rails-intro-1-a-data-management-application-in-five-easy-steps/feed/</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
		<item>
		<title>&#8220;Smidig 2007&#8243;: A conference for the community</title>
		<link>http://johannesbrodwall.com/2007/10/13/smidig-2007-a-conference-for-the-community/</link>
		<comments>http://johannesbrodwall.com/2007/10/13/smidig-2007-a-conference-for-the-community/#comments</comments>
		<pubDate>Sat, 13 Oct 2007 16:06:29 +0000</pubDate>
		<dc:creator>Johannes Brodwall</dc:creator>
				<category><![CDATA[Communities]]></category>
		<category><![CDATA[Ruby-on-Rails]]></category>
		<category><![CDATA[Software Development]]></category>

		<guid isPermaLink="false">http://www.brodwall.com/johannes/blog/2007/10/13/smidig-2007-a-conference-for-the-community/</guid>
		<description><![CDATA[The Norwegian word &#8220;smidig&#8221; means &#8220;agile&#8221;. So when we wanted to make a Norwegian conference for the Oslo Agile community, &#8220;smidig 2007&#8221; (November 26th and 27th) was a natural choice for a title.
The seed of the conference was idea by Nils Christian Haugen and Aslak Hellesøy to have a whole day devoted to open spaces. [...]]]></description>
			<content:encoded><![CDATA[<p>The Norwegian word &#8220;smidig&#8221; means &#8220;agile&#8221;. So when we wanted to make a Norwegian conference for the Oslo Agile community, &#8220;<a href="http://smidig.no/smidig2007">smidig 2007</a>&#8221; (November 26th and 27th) was a natural choice for a title.</p>
<p>The seed of the conference was idea by <a href="http://smidig.no/smidig2007/static/contact_us">Nils Christian Haugen</a> and <a href="http://blog.aslakhellesoy.com/">Aslak Hellesøy</a> to have a whole day devoted to open spaces. Meanwhile, I had been experimenting with &#8220;lightning talks&#8221; on <a href="http://xp.meetup.com/13/">Oslo XP meetup</a>, a user group that meets in Oslo every month. The inception of the open spaces conference was delayed over the summer, and towards the end of the summer, <a href="http://smidig.no/smidig2007/static/contact_us">Trond Pedersen</a> and myself were discussing the success of the Oslo XP meetup lightning talks over a beer. The more we thought about it, the more it seemed natural: We need a whole day devoted to lighting talks. Meanwhile, Simen Fure Jørgensen decided to start up <a href="http://agile.meetup.com/31/">Oslo Lean Meetup</a>.</p>
<p>We tossed the ideas around on the smidig.no forum for a while, and Christian Hauknes noticed how disorganized we all were about it, and decided to make it all come together. Along the way, many enthusiasts have contributed. Without them, it would all still be a fantasy in the minds of a few people.</p>
<p>Finally, we all came together with a single vision: A two day conference for the community, by the community. We know that there are a lot of people with extremely valuable experience who seldom get heard. Instead, conferences focus on big names that tend to overshadow the participants.</p>
<p>We hope that <a href="http://smidig.no/smidig2007/">Smidig 2007</a> will be different. Both days of the conference are devoted to ways to get the participants to learn from each other. Open spaces workshops allows for in depth exploration of topics and experiences, while Lightning Talks, a presentation form that limits all talks to 10 minutes, allows for a wide range of point of view and experience.</p>
<p>Over 50 speakers have already signed up. For a conference where we expect a total of not much more than 200 participants, this is great. I&#8217;m overwhelmed by the great support of the business community. Over 20 sponsors have signed up, ensuring that we won&#8217;t go broke in the process of pulling together this conference. We have the budget to pull of a spectacular conference dinner, video recording of the whole event, and the most interesting venue in all of Oslo.</p>
<p>There are still a lot of things that could be improved. If you read this blog, and you would like to play around with the Rails-based conference application, organize a conference dinner, organize an open space conference, write about the conference, discuss experiences using agile principles on the forum, or help move chairs and table around during the conference, we would like your help. Or even better: If you yourself see room for improvement. Send an email to <a href="mailto:conference@smidig.no">the conference mailing list</a> to get in touch with us.</p>
<p>I have always been impressed by the insights of Oslo software professionals. I am looking forward to hearing a dozens of them speak in November.</p>
]]></content:encoded>
			<wfw:commentRss>http://johannesbrodwall.com/2007/10/13/smidig-2007-a-conference-for-the-community/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>&#8220;Hi, I&#8217;m Ruby-on-Rails&#8221;</title>
		<link>http://johannesbrodwall.com/2007/05/19/hi-im-ruby-on-rails/</link>
		<comments>http://johannesbrodwall.com/2007/05/19/hi-im-ruby-on-rails/#comments</comments>
		<pubDate>Sat, 19 May 2007 13:55:47 +0000</pubDate>
		<dc:creator>Johannes Brodwall</dc:creator>
				<category><![CDATA[Links]]></category>
		<category><![CDATA[Ruby-on-Rails]]></category>
		<category><![CDATA[Software Development]]></category>

		<guid isPermaLink="false">http://www.brodwall.com/johannes/blog/2007/05/19/hi-im-ruby-on-rails/</guid>
		<description><![CDATA[Inspired by the &#8220;Hi, I&#8217;m a Mac&#8221; ads of Apple, Gregg Pollack and Jason Seifer has made these cute Ruby-on-Rails ads (featuring Ruby-on-Rails versus Java and Ruby-on-Rails versus PHP):

Click here to view on YouTube
]]></description>
			<content:encoded><![CDATA[<p>Inspired by the &#8220;Hi, I&#8217;m a Mac&#8221; ads of Apple, <a href="http://railsenvy.com/">Gregg Pollack and Jason Seifer</a> has made these cute Ruby-on-Rails ads (featuring Ruby-on-Rails versus Java and Ruby-on-Rails versus PHP):</p>
<p><object width="425" height="350"><param name="movie" value="http://www.youtube.com/v/PQbuyKUaKFo"></param><param name="wmode" value="transparent"></param><embed src="http://www.youtube.com/v/PQbuyKUaKFo" type="application/x-shockwave-flash" wmode="transparent" width="425" height="350"></embed></object><br />
<a target="_new" href="http://www.youtube.com/watch?v=PQbuyKUaKFo" title="Ruby On Rails vs Java Commercial">Click here to view on YouTube</a></p>
]]></content:encoded>
			<wfw:commentRss>http://johannesbrodwall.com/2007/05/19/hi-im-ruby-on-rails/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Rails: The Demonstration</title>
		<link>http://johannesbrodwall.com/2007/04/21/rails-the-demonstration/</link>
		<comments>http://johannesbrodwall.com/2007/04/21/rails-the-demonstration/#comments</comments>
		<pubDate>Sat, 21 Apr 2007 17:09:14 +0000</pubDate>
		<dc:creator>Johannes Brodwall</dc:creator>
				<category><![CDATA[Ruby-on-Rails]]></category>

		<guid isPermaLink="false">http://www.brodwall.com/johannes/blog/2007/04/21/rails-the-demonstration/</guid>
		<description><![CDATA[I often criticize products from the big vendors like IBM, Microsoft and Oracle for what I call the &#8220;New Coke Effect&#8221;. As retold by Malcom Gladwell in Blink, Pepsi introduced blind taste tests in the 80s. They beat Coca Cola by a big margin. In order to regain the advantage, Coke developed &#8220;New Coke&#8221;, a [...]]]></description>
			<content:encoded><![CDATA[<p>I often criticize products from the big vendors like IBM, Microsoft and Oracle for what I call the &#8220;New Coke Effect&#8221;. As retold by <a href="http://www.gladwell.com/">Malcom Gladwell</a> in <a href="http://www.gladwell.com/blink/">Blink</a>, Pepsi introduced blind taste tests in the 80s. They beat Coca Cola by a big margin. In order to regain the advantage, Coke developed &#8220;New Coke&#8221;, a product that was optimized for the blind taste tests. It tanked. Totally. It tanked so bad that coke had to have the words &#8220;classic coke&#8221; prominently on the label until 2002.</p>
<p>The problem is that a blind taste test is not the same as drinking a whole bottle. People prefer sweet tastes when they just take a sip, but not when they want to finish the glass.</p>
<p>A lot of visually oriented software development tools are similar: They have been optimized for a 30 minute demo in front of a crowded auditorium. Sadly, many of these products are an active obstacle when you want to &#8220;finish the glass&#8221;, that is, deliver working software into production.</p>
<p><a href="http://www.rubyonrails.com">Ruby on Rails</a> is different: It looks great in a demo, but it take the whole software development life cycle into account. These two facts put together is why I recommend it so much these days.<br />
(Shameless plug: If you&#8217;re located in Oslo, and would like an introduction to Ruby on Rails: Feel free to <a href="mailto:johannes@brodwall.com">get in contact with me</a>).</p>
<p>For a full tutorial on Rails, I recommend <a href="http://instantrails.rubyforge.org/tutorial/index.html">Rolling with Ruby on [Instant]Rails</a>, by Curt Hibbs and Bill Walton.</p>
<h3>The Demonstration</h3>
<p>This week, I showed a client how to use Ruby on Rails to get started developing web applications. I felt the workshop was a fruitful one. None of the people in the room (except me, of course) had any experience with Ruby on Rails or Ruby, and some of the audience had not worked with programming at all for several years.</p>
<p>In spite of this, everyone was able to understand how the application worked, and how everything fits together. This is what I find to be so fun about demonstrating Rails: There are no hidden tricks. I can install everything on a provided computer and I can explain how all the pieces fit together. I can explain how to address <a href="http://wiki.rubyonrails.org/rails/pages/Capistrano">deployment</a>, <a href="http://garrettsnider.backpackit.com/pub/367902">database upgrades</a>, layout issues, <a href="http://www.onlamp.com/pub/a/onlamp/2005/06/09/rails_ajax.html">AJAX</a>, <a href="http://www.ryandaigle.com/articles/2006/06/30/whats-new-in-edge-rails-activeresource-is-here">REST-webservices</a>, security, and <a href="http://railsexpress.de/blog/">scalability</a>. This is not a magic trick to be waved in front of an audience and they quickly hide behind your back.</p>
<p>In a matter of a few hours, we were able to demonstrate, discuss and explain:</p>
<ul>
<li><a href="http://www.rubyonrails.com/down">Install</a> the necessary software (<a href="http://rubyforge.org/frs/?group_id=167">Ruby</a>, <a href="http://dev.mysql.com/downloads/">MySQL</a>, and Rails itself via <code>gem install rails</code>. Alternatively, we could&#8217;ve used <a href="http://instantrails.rubyforge.org/">InstantRails</a>)</li>
<li>Create an explore a working, simple &#8220;hello world&#8221; web application</li>
<li>Use Ruby on Rails&#8217;s Migration and Scaffold to create a database table (<code>ruby script/generate model service_provider name:string description:text registration_date:date</code>) and the web pages to create, display, update, and delete entries in the table (<code>ruby script/generate scaffold service_provider</code>). Rails comes with scripts to create the tables (<code>rake db:migrate</code>), and load pregenerated (but editable) test data (<code>rake db:fixtures:load</code>).</li>
<li>Create and explore a bidirectional one-to-many relationship between ServiceProviders and Customers with <a href="http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html#M000642">has_many</a> and <a href="http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html#M000644">belongs_to</a></li>
<li>Implement a mock-login scheme using <a href="http://wiki.rubyonrails.com/rails/pages/HowtoWorkWithSessions">sessions</a>. Our login-action lists all the service_providers (using a <a href="http://api.rubyonrails.org/classes/ActionView/Helpers/FormHelper.html">select</a> list). Yeah, I know it&#8217;s lame, but implementing passwords takes time, and doesn&#8217;t really prove anything.</li>
<li>Restrict which Customers a ServiceProvider can see and modify (by using a <a href="http://api.rubyonrails.org/classes/ActionController/Filters/ClassMethods.html">before_filter</a> and using <code>session[:service_provider].customers.find</code> instead of <code>Customers.find</code>, <code>session[:service_provider].customers.delete</code> instead of <code>Customers.delete</code> and <code>session[:service_provider].customers.build</code> instead of <code>Customers.new</code>)</li>
<li>Implement some <a href="http://api.rubyonrails.org/classes/ActiveRecord/Validations/ClassMethods.html#M000945">validation rules</a></li>
<li>Explore (but sadly, not demonstrate) deployment options using <a href="http://manuals.rubyonrails.com/read/book/17">Capistrano</a></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://johannesbrodwall.com/2007/04/21/rails-the-demonstration/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
	</channel>
</rss>
