Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Mongoid part 2

  • Loading branch information...
commit 6f1c2b0bfe12c73d3246999c153cf27a7fb2d738 1 parent 0f5ef52
@eladmeidar authored
View
110 _posts/2010-3-7-creating-a-rails-authentication-system-on-mongoid-part-2-7-3-2010.textile
@@ -0,0 +1,110 @@
+---
+title: Creating a Rails authentication system on Mongoid Part 2 - Remember me and Account activation
+layout: post
+---
+
+On the first part of "Creating a Rails authentication system on Mongoid":http://blog.eizesus.com/2010/03/creating-a-rails-authentication-system-on-mongoid/ we tackled the basic structure of our authentication system. In this part we'll tackle our need in creating a "Remember me" functionality to allow users to login from a cookie and a basic account activation process.
+
+As a general thumb rule to this experience we try not to re-invent the wheel when we can, which basically means that we look at the existing authentication libraries source code and try to see if it has some kind of a problem on Mongo, if it doesn't we use it and i if does we fix it as you read in the first part.
+
+Out of all the authentication libraries we examined (and dropped for this cause) the one i liked the most and in my opinion the simplest yet complete is "Restful Authentication", so we chose it as our base line and we use code snippets from it when ever we can.
+
+h4. Remember me?
+
+The remember me functionality allows the user to login using a generated token that is found on a cookie we create, this allows the user to login without putting his user name and password *everytime* they want to login as long as the cookie was not expired.
+
+The first thing we need to do to allow a login from cookie, is to get our User model familiar with some new fields and methods to make that process possible.
+
+First, we need to add a few fields to our user document and a add a few methods to instance and class, this is our new @User.rb@:
+
+h5. User.rb changes
+
+We changed @User.rb@ a bit:
+
+<script src="http://gist.github.com/324635.js?file=User.rb"></script>
+
+We *added 2 fields*, @remember_token_expires_at@ and @remember_token@, both to keep a token and and an expiry limit.
+We also added the following instance methods:
+
+* *remember_token?* - determines if a token should and can be remembered.
+* *remember_me* - generates and saves the token and expiry limit.
+* *refresh_token* - creates a new token.
+* *forget_me* - cleans the token and expiry limit fields.
+
+we also added the following class methods:
+
+* *User.secure_digest* - a wrapper to our encryption method.
+* *User.make_token* - generates a new token.
+
+Now that we changed some of the options for our session management, we will need to update @sessions_controller@ and @application_controller@ as well.
+
+h5. ApplicationController changes
+
+In the end of Part 1, i gave an example to some methods that should be on @application_controller@ in order to make the session management and the entire authentication process easier. Since those were just examples and were meant barely to support basic usage, we will need to go through it a bit more seriously and create a more precise and smart @application_controller@.
+
+In this case, we can simply grab all the methods from Restful Authentication's @authentication.rb@ module, and weld it to our @application_controller@:
+
+<script src="http://gist.github.com/324641.js?file=application_controller.rb"></script>
+
+we added a few methods and changed a few existing ones, this is pretty straight forward and basically a 1:1 copy from Restful Authentication, the only important thing to really pay attention to are the @current_user@ and the @current_user=@ which are different than what we had in my previous example and now takes more into consideration (cookies and HTTPauth for example.)
+
+Since now we have a getter for @current_user@ we need to change our @sessions_controller@ too.
+
+h5. SessionsController changes
+
+This is our current @sessions_controller@:
+
+<script src="http://gist.github.com/324647.js?file=sessions_controller.rb"></script>
+
+note the "remember me" functionality consideration and the usage of our cookie-based-login methods from @application_controller@.
+
+Now you can simply add a checkbox named "remember_me" to your @SessionsController#new@ form, but i am sure you can do that without a gist :)
+
+h4. Activation
+
+"Account Activation" is generally a process that is meant to make sure the user who filled the registration form really has access to the email account by sending that address a message with a token-generated link that upon clicked, proves ownership of this email address and activates the account.
+
+h5. User.rb
+
+We had to find a solution to annotate the user instance with it's current activation status, with that given we figured we have 2 options to tackle it:
+
+* simple add a boolean field to store the current activation status
+* use some kind of a state machine that will allow us some more flexibility later
+
+Bearing in mind that we won't need more than a single status, we decided to go with the first option and simply add an @active@ boolean field, an @activation_code@ token field and an @activated_at@ timestamp. we also added those fields to our @attr_protected@ list since we don't really want them changed by mass-assignment.
+
+<script src="http://gist.github.com/324659.js?file=user.rb"></script>
+
+We also added a simple @before_create@ methods that will generate an activation token for our user and a method to @activate!@ the user.
+
+Given the key step in an activation process is the step where your application sends the user an email message with the activation link so we'll need to find a good way to send out an activation email when a user is created.
+
+As far as outgoing emails best practices goes, it's better not to preform the @ActionMailer#deliver_...@ method in the controller itself, but to:
+
+* Use an observer that will send that email when the current callback is fired. In our case that would be an @after_create@ observer on the User model.
+* Offload the task to some kind of a background processor such as DelayedJob or Resque.
+
+A quick check in the Mongoid source-code revealed that we don't have support for Observers so that option is ruled out (again, until a patch arrives). As for a background processor, while DelayedJob has an ActiveRecord dependency Resque is pretty much free and relies on Redis so we decided to use Resque in our application.
+
+I'll cover the email management on one of the next posts, but for now we'll just use an @after_create@ callback on the User model that will perform a regular @ActionMailer@ delivery.
+
+h5. UsersController changes (and a bonus mailer)
+
+Since we take care of the email notification on the model level (for now, until we offload it to a background processor later) we don't need to change our @UsersController#create@ methods, but we do need to add an action that will take care of the activation for us:
+
+<script src="http://gist.github.com/324700.js?file=users_controller.rb"></script>
+
+Remember to update your routes and either:
+
+* add a @:collection => {:activate => :get}@ to your @map.users@ routes.
+* add a named route like @map.activate '/users/activate/:activation_code, :controller => 'users', :action => 'activate'@
+
+we chose to add a *named route*, just because it makes more sense and that the @activate@ action is not a collection action, but not one that requires an @id@ too.
+
+Here are a "sample user mailer":http://gist.github.com/324719 and an "activation mail view":http://gist.github.com/324722 if you really need them :)
+
+
+h4. Conclusion
+
+In this part we didn't ran into *that* many issues because we use Mongoid, the only real problem was the lack of observers but since we are going to offload the email sending process to a background processor, it doesn't really matter.
+In the next part, we'll tackle password resets and background processing.
View
203 _site/2010/03/creating-a-rails-authentication-system-on-mongoid-part-2-7-3-2010/index.html
@@ -0,0 +1,203 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
+ <title>Emphasized Insanity - Creating a Rails authentication system on Mongoid Part 2 - Remember me and Account activation</title>
+ <script type="text/javascript" src="/javascripts/application.js"></script>
+ <link rel="stylesheet" type="text/css" href="/stylesheets/application.css">
+<link rel="alternate" type="application/rss+xml" title="Emphasized Insanity - Elad Meidar" href="http://feeds.feedburner.com/EladOnRails" />
+</head>
+<body>
+ <div id="wrap">
+ <div id="header">
+ <img src="/images/500.png" alt="Emphasized Insanity" />
+ <div id="summary">
+ <h1><strong>EmphasizedInsanity</strong> at <strong>/life
+ </strong></h1>
+ <h2>undefined method `Sanity` for #&lt;EladMeidar::Developer:0x12e0670&gt;</h2>
+ <ul>
+ <li class="first"><strong>file:</strong> <code>
+ brain.rb</code></li>
+ <li><strong>location:</strong> <code>instance_missing
+ </code></li>
+ <li class="last"><strong>line:
+ </strong> 1</li>
+ </ul>
+ </div>
+ <div class="clear"></div>
+ </div>
+
+ <div id="backtrace" class='expanded'>
+ <h3>BACKTRACE</h3>
+ <p><a href="#" id="expando"
+ onclick="toggleBacktrace(); return false">(condense)</a></p>
+ <p id="nav"><strong>JUMP TO:</strong>
+ <a href="#get-info">GET</a>
+ <a href="#post-info">POSTS</a>
+ <a href="#cookie-info">COOKIES</a>
+ <a href="#env-info">ENV</a>
+ </p>
+ <div class="clear"></div>
+
+ <ul id="backtrace-ul">
+
+ <li class="frame-info framework">
+ <code>
+ No, this is not a real Sinatra error :). <br/>
+ This is the personal homepage of Elad Meidar, a web developer and an entrepreneur specializing in Ruby on Rails. I hang around Fort Lauderdale, FL and Tel-Aviv in Israel, and i am currently running <a href="http://www.nautilus6.com">Nautilus6</a> so Feel free to contact me regarding projects :).<br/>
+ I am a proud member of <a href="http://www.railsbridge.org">RailsBridge</a>, Helping new <a href="http://www.railsmentors.org/users/185">Rails developers</a> get into our world and also contributed a few <a href="http://contributors.rubyonrails.org/contributors/elad-meidar/commits">Patches</a> to the Ruby on Rails core.
+ </code>
+ </li>
+ <li class="code framework">
+ </li>
+ </ul>
+ </div> <!-- /BACKTRACE -->
+
+ <div id="get">
+<a id="homepage_link" href="/">Back to Posts List</a>
+ <h3 id="get-info">GET</h3>
+ <h3 class="post_title"><a href="/2010/03/creating-a-rails-authentication-system-on-mongoid-part-2-7-3-2010">Creating a Rails authentication system on Mongoid Part 2 - Remember me and Account activation</a></h3>
+ <div class="single_post">
+ <p>On the first part of <a href="http://blog.eizesus.com/2010/03/creating-a-rails-authentication-system-on-mongoid/">Creating a Rails authentication system on Mongoid</a> we tackled the basic structure of our authentication system. In this part we&#8217;ll tackle our need in creating a &#8220;Remember me&#8221; functionality to allow users to login from a cookie and a basic account activation process.</p>
+<p>As a general thumb rule to this experience we try not to re-invent the wheel when we can, which basically means that we look at the existing authentication libraries source code and try to see if it has some kind of a problem on Mongo, if it doesn&#8217;t we use it and i if does we fix it as you read in the first part.</p>
+<p>Out of all the authentication libraries we examined (and dropped for this cause) the one i liked the most and in my opinion the simplest yet complete is &#8220;Restful Authentication&#8221;, so we chose it as our base line and we use code snippets from it when ever we can.</p>
+<h4>Remember me?</h4>
+<p>The remember me functionality allows the user to login using a generated token that is found on a cookie we create, this allows the user to login without putting his user name and password <strong>everytime</strong> they want to login as long as the cookie was not expired.</p>
+<p>The first thing we need to do to allow a login from cookie, is to get our User model familiar with some new fields and methods to make that process possible.</p>
+<p>First, we need to add a few fields to our user document and a add a few methods to instance and class, this is our new <code>User.rb</code>:</p>
+<h5>User.rb changes</h5>
+<script src="http://gist.github.com/324635.js?file=User.rb"></script><p>We <strong>added 2 fields</strong>, <code>remember_token_expires_at</code> and <code>remember_token</code>, both to keep a token and and an expiry limit.<br />
+We also added the following instance methods:</p>
+<ul>
+ <li><strong>remember_token?</strong> &#8211; determines if a token should and can be remembered.</li>
+ <li><strong>remember_me</strong> &#8211; generates and saves the token and expiry limit.</li>
+ <li><strong>refresh_token</strong> &#8211; creates a new token.</li>
+ <li><strong>forget_me</strong> &#8211; cleans the token and expiry limit fields.</li>
+</ul>
+<p>we also added the following class methods:</p>
+<ul>
+ <li><strong>User.secure_digest</strong> &#8211; a wrapper to our encryption method.</li>
+ <li><strong>User.make_token</strong> &#8211; generates a new token.</li>
+</ul>
+<p>Now that we changed some of the options for our session management, we will need to update <code>sessions_controller</code> and <code>application_controller</code> as well.</p>
+<h5>ApplicationController changes</h5>
+<p>In the end of Part 1, i gave an example to some methods that should be on <code>application_controller</code> in order to make the session management and the entire authentication process easier. Since those were just examples and were meant barely to support basic usage, we will need to go through it a bit more seriously and create a more precise and smart <code>application_controller</code>.</p>
+<p>In this case, we can simply grab all the methods from Restful Authentication&#8217;s <code>authentication.rb</code> module, and weld it to our <code>application_controller</code>:</p>
+<script src="http://gist.github.com/324641.js?file=application_controller.rb"></script><p>we added a few methods and changed a few existing ones, this is pretty straight forward and basically a 1:1 copy from Restful Authentication, the only important thing to really pay attention to are the <code>current_user</code> and the <code>current_user=</code> which are different than what we had in my previous example and now take more into consideration (cookies and HTTPauth for example.)</p>
+<p>Since now we have a getter for <code>current_user</code> we need to change our <code>sessions_controller</code> too.</p>
+<h5>SessionsController changes</h5>
+<p>This is our current <code>sessions_controller</code>:</p>
+<script src="http://gist.github.com/324647.js?file=sessions_controller.rb"></script><p>note the &#8220;remember me&#8221; functionality consideration and the usage of our cookie-based-login methods from <code>application_controller</code>.</p>
+<p>Now you can simply add a checkbox named &#8220;remember_me&#8221; to your <code>SessionsController#new</code> form, but i am sure you can do that without a gist :)</p>
+<h4>Activation</h4>
+<p>&#8220;Account Activation&#8221; is generally a process that is meant to make sure the user who filled the registration form really has access to the email account by sending that address a message with a token-generated link that upon clicked, proves ownership of this email address and activates the account.</p>
+<h5>User.rb</h5>
+<p>We had to find a solution to annotate the user instance with it&#8217;s current activation status, with that given we figured we have 2 options to tackle it:</p>
+<ul>
+ <li>simple add a boolean field to store the current activation status</li>
+ <li>use some kind of a state machine that will allow us some more flexibility later</li>
+</ul>
+<p>Bearing in mind that we won&#8217;t need more than a single status, we decided to go with the first option and simply add an <code>active</code> boolean field, an <code>activation_code</code> token field and an <code>activated_at</code> timestamp. we also added those fields to our <code>attr_protected</code> list since we don&#8217;t really want them changed by mass-assignment.</p>
+<script src="http://gist.github.com/324659.js?file=user.rb"></script><p>We also added a simple <code>before_create</code> methods that will generate an activation token for our user and a method to <code>activate!</code> the user.</p>
+<p>Given the key step in an activation process is the step where your application sends the user an email message with the activation link so we&#8217;ll need to find a good way to send out an activation email when a user is created.</p>
+<p>As far as outgoing emails best practices goes, it&#8217;s better not to preform the <code>ActionMailer#deliver_...</code> method in the controller itself, but to:</p>
+<ul>
+ <li>Use an observer that will send that email when the current callback is fired. In our case that would be an <code>after_create</code> observer on the User model.</li>
+ <li>Offload the task to some kind of a background processor such as DelayedJob or Resque.</li>
+</ul>
+<p>A quick check in the Mongoid source-code revealed that we don&#8217;t have support for Observers so that option is ruled out (again, until a patch arrives). As for a background processor, while DelayedJob has an ActiveRecord dependency Resque is pretty much free and relies on Redis so we decided to use Resque in our application.</p>
+<p>I&#8217;ll cover the email management on one of the next posts, but for now we&#8217;ll just use an <code>after_create</code> callback on the User model that will perform a regular <code>ActionMailer</code> delivery.</p>
+<h5>UsersController changes (and a bonus mailer)</h5>
+<p>Since we take care of the email notification on the model level (for now, until we offload it to a background processor later) we don&#8217;t need to change our <code>UsersController#create</code> methods, but we do need to add an action that will take care of the activation for us:</p>
+<script src="http://gist.github.com/324700.js?file=users_controller.rb"></script><p>Remember to update your routes and either:</p>
+<ul>
+ <li>add a <code>:collection =&gt; {:activate =&gt; :get}</code> to your <code>map.users</code> routes.</li>
+ <li>add a named route like <code>map.activate '/users/activate/:activation_code, :controller =&gt; 'users', :action =&gt; 'activate'</code></li>
+</ul>
+<p>we chose to add a <strong>named route</strong>, just because it makes more sense and that the <code>activate</code> action is not a collection action, but not one that requires an <code>id</code> too.</p>
+<p>Here are a <a href="http://gist.github.com/324719">sample user mailer</a> and an <a href="http://gist.github.com/324722">activation mail view</a> if you really need them :)</p>
+<h4>Conclusion</h4>
+<p>In this part we didn&#8217;t ran into <strong>that</strong> many issues because we use Mongoid, the only real problem was the lack of observers but since we are going to offload the email sending process to a background processor, it doesn&#8217;t really matter.<br />
+In the next part, we&#8217;ll tackle password resets and background processing.</p>
+ </div>
+ <div class="clear"></div>
+</div> <!-- /GET -->
+
+<div id="post">
+ <h3 id="post-info">POST</h3>
+ <div id="disqus_thread"></div><script type="text/javascript" src="http://disqus.com/forums/emphasizedinsanity/embed.js"></script><noscript><a href="http://emphasizedinsanity.disqus.com/?url=ref">View the discussion thread.</a></noscript><a href="http://disqus.com" class="dsq-brlink">blog comments powered by <span class="logo-disqus">Disqus</span></a>
+ <div class="clear"></div>
+</div> <!-- /POST -->
+
+ <div id="cookies">
+ <h3 id="cookie-info">COOKIES</h3>
+
+ <p class="no-data">I Don't have cookies.</p>
+
+ <div class="clear"></div>
+ </div> <!-- /COOKIES -->
+
+ <div id="rack">
+ <h3 id="env-info">ELAD ENV</h3>
+ <table class="req">
+ <tr>
+ <th>Variable</th>
+ <th>Value</th>
+ </tr>
+
+ <tr>
+ <td>LINKEDIN</td>
+ <td class="code"><div><a href="http://www.linkedin.com/in/eladmeidar">http://www.linkedin.com/in/eladmeidar</a></div></td>
+ </tr>
+
+ <tr>
+ <td>TWITTER</td>
+ <td class="code"><div><a href="http://www.twitter.com/eladmeidar">http://www.twitter.com/eladmeidar</a></div></td>
+ </tr>
+
+ <tr>
+ <td>FACEBOOK</td>
+ <td class="code"><div><a href="http://www.facebook.com/eladmeidar">http://www.facebook.com/eladmeidar</a></div></td>
+ </tr>
+
+ <tr>
+ <td>GITHUB</td>
+ <td class="code"><div><a href="http://github.com/eladmeidar">http://github.com/eladmeidar</a></div></td>
+ </tr>
+
+ <tr>
+ <td>WWR</td>
+ <td class="code"><div><code>{ :working_with_rails => '<a href="http://www.workingwithrails.com/person/5844-elad-meidar">http://www.workingwithrails.com/person/5844-elad-meidar</a>' }</code></div></td>
+ </tr>
+
+ <tr>
+ <td>IRC</td>
+ <td class="code"><div><code>{ 'irc.freenode.net' => [ '#rubyonrails', '#railsbridge', '#ruby', '#jquery' ]}</code></div></td>
+ </tr>
+ <tr>
+ <td>SKYPE</td>
+ <td class="code"><div>eladmeidar</div></td>
+ </tr>
+ </table>
+ <div class="clear"></div>
+ </div> <!-- /RACK ENV -->
+
+ <div class="stats">
+ <p>
+ <a href="http://feeds2.feedburner.com/EladOnRails"><img src="http://feeds2.feedburner.com/~fc/EladOnRails?bg=FFFFFF&amp;fg=444444&amp;anim=0" height="26" width="88" style="border:0" alt="" /></a>
+ <script type="text/javascript" language="javascript" src="http://twittercounter.com/embed/?username=eladmeidar&style=white"></script>
+ </p>
+ <p>
+ <script type="text/javascript" src="http://s51.sitemeter.com/js/counter.js?site=s51eizesusrulez"></script>
+ <noscript>
+ <a href="http://s51.sitemeter.com/stats.asp?site=s51eizesusrulez" target="_top">
+ <img src="http://s51.sitemeter.com/meter.asp?site=s51eizesusrulez" alt="Site Meter" border="0"/></a>
+ </noscript>
+ </p>
+ <div class="clear"></div>
+ </div>
+ <p id="explanation">You're seeing this error because I think it is funny.</p>
+
+ </div> <!-- /WRAP -->
+ </body>
+</html>
View
5 _site/archive.html
@@ -65,6 +65,11 @@ <h3 id="get-info">GET</h3>
<h3 id="post-info">POST</h3>
<div class="post">
+ <h4><a href="/2010/03/creating-a-rails-authentication-system-on-mongoid-part-2-7-3-2010">Creating a Rails authentication system on Mongoid Part 2 - Remember me and Account activation</a></h4>
+ <em>07/03/2010</em>
+ </div>
+
+ <div class="post">
<h4><a href="/2010/03/creating-a-rails-authentication-system-on-mongoid">Creating a Rails authentication system on Mongoid - Part 1</a></h4>
<em>06/03/2010</em>
</div>
View
92 _site/feed/atom.xml
@@ -4,7 +4,7 @@
<title>Emphasized Insanity</title>
<link href="http://blog.eizesus.com/feed/atom.xml" rel="self"/>
<link href="http://blog.eizesus.com/"/>
- <updated>2010-03-07T01:30:23-05:00</updated>
+ <updated>2010-03-07T18:35:01-05:00</updated>
<id>http://blog.eizesus.com/</id>
<author>
<name>Elad Meidar</name>
@@ -13,6 +13,74 @@
<entry>
+ <title>Creating a Rails authentication system on Mongoid Part 2 - Remember me and Account activation</title>
+ <link href="http://blog.eizesus.com/2010/03/creating-a-rails-authentication-system-on-mongoid-part-2-7-3-2010"/>
+ <updated>2010-03-07T00:00:00-05:00</updated>
+ <id>http://gitready.com/2010/03/creating-a-rails-authentication-system-on-mongoid-part-2-7-3-2010</id>
+ <content type="html">&lt;p&gt;On the first part of &lt;a href=&quot;http://blog.eizesus.com/2010/03/creating-a-rails-authentication-system-on-mongoid/&quot;&gt;Creating a Rails authentication system on Mongoid&lt;/a&gt; we tackled the basic structure of our authentication system. In this part we&amp;#8217;ll tackle our need in creating a &amp;#8220;Remember me&amp;#8221; functionality to allow users to login from a cookie and a basic account activation process.&lt;/p&gt;
+&lt;p&gt;As a general thumb rule to this experience we try not to re-invent the wheel when we can, which basically means that we look at the existing authentication libraries source code and try to see if it has some kind of a problem on Mongo, if it doesn&amp;#8217;t we use it and i if does we fix it as you read in the first part.&lt;/p&gt;
+&lt;p&gt;Out of all the authentication libraries we examined (and dropped for this cause) the one i liked the most and in my opinion the simplest yet complete is &amp;#8220;Restful Authentication&amp;#8221;, so we chose it as our base line and we use code snippets from it when ever we can.&lt;/p&gt;
+&lt;h4&gt;Remember me?&lt;/h4&gt;
+&lt;p&gt;The remember me functionality allows the user to login using a generated token that is found on a cookie we create, this allows the user to login without putting his user name and password &lt;strong&gt;everytime&lt;/strong&gt; they want to login as long as the cookie was not expired.&lt;/p&gt;
+&lt;p&gt;The first thing we need to do to allow a login from cookie, is to get our User model familiar with some new fields and methods to make that process possible.&lt;/p&gt;
+&lt;p&gt;First, we need to add a few fields to our user document and a add a few methods to instance and class, this is our new &lt;code&gt;User.rb&lt;/code&gt;:&lt;/p&gt;
+&lt;h5&gt;User.rb changes&lt;/h5&gt;
+&lt;script src=&quot;http://gist.github.com/324635.js?file=User.rb&quot;&gt;&lt;/script&gt;&lt;p&gt;We &lt;strong&gt;added 2 fields&lt;/strong&gt;, &lt;code&gt;remember_token_expires_at&lt;/code&gt; and &lt;code&gt;remember_token&lt;/code&gt;, both to keep a token and and an expiry limit.&lt;br /&gt;
+We also added the following instance methods:&lt;/p&gt;
+&lt;ul&gt;
+ &lt;li&gt;&lt;strong&gt;remember_token?&lt;/strong&gt; &amp;#8211; determines if a token should and can be remembered.&lt;/li&gt;
+ &lt;li&gt;&lt;strong&gt;remember_me&lt;/strong&gt; &amp;#8211; generates and saves the token and expiry limit.&lt;/li&gt;
+ &lt;li&gt;&lt;strong&gt;refresh_token&lt;/strong&gt; &amp;#8211; creates a new token.&lt;/li&gt;
+ &lt;li&gt;&lt;strong&gt;forget_me&lt;/strong&gt; &amp;#8211; cleans the token and expiry limit fields.&lt;/li&gt;
+&lt;/ul&gt;
+&lt;p&gt;we also added the following class methods:&lt;/p&gt;
+&lt;ul&gt;
+ &lt;li&gt;&lt;strong&gt;User.secure_digest&lt;/strong&gt; &amp;#8211; a wrapper to our encryption method.&lt;/li&gt;
+ &lt;li&gt;&lt;strong&gt;User.make_token&lt;/strong&gt; &amp;#8211; generates a new token.&lt;/li&gt;
+&lt;/ul&gt;
+&lt;p&gt;Now that we changed some of the options for our session management, we will need to update &lt;code&gt;sessions_controller&lt;/code&gt; and &lt;code&gt;application_controller&lt;/code&gt; as well.&lt;/p&gt;
+&lt;h5&gt;ApplicationController changes&lt;/h5&gt;
+&lt;p&gt;In the end of Part 1, i gave an example to some methods that should be on &lt;code&gt;application_controller&lt;/code&gt; in order to make the session management and the entire authentication process easier. Since those were just examples and were meant barely to support basic usage, we will need to go through it a bit more seriously and create a more precise and smart &lt;code&gt;application_controller&lt;/code&gt;.&lt;/p&gt;
+&lt;p&gt;In this case, we can simply grab all the methods from Restful Authentication&amp;#8217;s &lt;code&gt;authentication.rb&lt;/code&gt; module, and weld it to our &lt;code&gt;application_controller&lt;/code&gt;:&lt;/p&gt;
+&lt;script src=&quot;http://gist.github.com/324641.js?file=application_controller.rb&quot;&gt;&lt;/script&gt;&lt;p&gt;we added a few methods and changed a few existing ones, this is pretty straight forward and basically a 1:1 copy from Restful Authentication, the only important thing to really pay attention to are the &lt;code&gt;current_user&lt;/code&gt; and the &lt;code&gt;current_user=&lt;/code&gt; which are different than what we had in my previous example and now take more into consideration (cookies and HTTPauth for example.)&lt;/p&gt;
+&lt;p&gt;Since now we have a getter for &lt;code&gt;current_user&lt;/code&gt; we need to change our &lt;code&gt;sessions_controller&lt;/code&gt; too.&lt;/p&gt;
+&lt;h5&gt;SessionsController changes&lt;/h5&gt;
+&lt;p&gt;This is our current &lt;code&gt;sessions_controller&lt;/code&gt;:&lt;/p&gt;
+&lt;script src=&quot;http://gist.github.com/324647.js?file=sessions_controller.rb&quot;&gt;&lt;/script&gt;&lt;p&gt;note the &amp;#8220;remember me&amp;#8221; functionality consideration and the usage of our cookie-based-login methods from &lt;code&gt;application_controller&lt;/code&gt;.&lt;/p&gt;
+&lt;p&gt;Now you can simply add a checkbox named &amp;#8220;remember_me&amp;#8221; to your &lt;code&gt;SessionsController#new&lt;/code&gt; form, but i am sure you can do that without a gist :)&lt;/p&gt;
+&lt;h4&gt;Activation&lt;/h4&gt;
+&lt;p&gt;&amp;#8220;Account Activation&amp;#8221; is generally a process that is meant to make sure the user who filled the registration form really has access to the email account by sending that address a message with a token-generated link that upon clicked, proves ownership of this email address and activates the account.&lt;/p&gt;
+&lt;h5&gt;User.rb&lt;/h5&gt;
+&lt;p&gt;We had to find a solution to annotate the user instance with it&amp;#8217;s current activation status, with that given we figured we have 2 options to tackle it:&lt;/p&gt;
+&lt;ul&gt;
+ &lt;li&gt;simple add a boolean field to store the current activation status&lt;/li&gt;
+ &lt;li&gt;use some kind of a state machine that will allow us some more flexibility later&lt;/li&gt;
+&lt;/ul&gt;
+&lt;p&gt;Bearing in mind that we won&amp;#8217;t need more than a single status, we decided to go with the first option and simply add an &lt;code&gt;active&lt;/code&gt; boolean field, an &lt;code&gt;activation_code&lt;/code&gt; token field and an &lt;code&gt;activated_at&lt;/code&gt; timestamp. we also added those fields to our &lt;code&gt;attr_protected&lt;/code&gt; list since we don&amp;#8217;t really want them changed by mass-assignment.&lt;/p&gt;
+&lt;script src=&quot;http://gist.github.com/324659.js?file=user.rb&quot;&gt;&lt;/script&gt;&lt;p&gt;We also added a simple &lt;code&gt;before_create&lt;/code&gt; methods that will generate an activation token for our user and a method to &lt;code&gt;activate!&lt;/code&gt; the user.&lt;/p&gt;
+&lt;p&gt;Given the key step in an activation process is the step where your application sends the user an email message with the activation link so we&amp;#8217;ll need to find a good way to send out an activation email when a user is created.&lt;/p&gt;
+&lt;p&gt;As far as outgoing emails best practices goes, it&amp;#8217;s better not to preform the &lt;code&gt;ActionMailer#deliver_...&lt;/code&gt; method in the controller itself, but to:&lt;/p&gt;
+&lt;ul&gt;
+ &lt;li&gt;Use an observer that will send that email when the current callback is fired. In our case that would be an &lt;code&gt;after_create&lt;/code&gt; observer on the User model.&lt;/li&gt;
+ &lt;li&gt;Offload the task to some kind of a background processor such as DelayedJob or Resque.&lt;/li&gt;
+&lt;/ul&gt;
+&lt;p&gt;A quick check in the Mongoid source-code revealed that we don&amp;#8217;t have support for Observers so that option is ruled out (again, until a patch arrives). As for a background processor, while DelayedJob has an ActiveRecord dependency Resque is pretty much free and relies on Redis so we decided to use Resque in our application.&lt;/p&gt;
+&lt;p&gt;I&amp;#8217;ll cover the email management on one of the next posts, but for now we&amp;#8217;ll just use an &lt;code&gt;after_create&lt;/code&gt; callback on the User model that will perform a regular &lt;code&gt;ActionMailer&lt;/code&gt; delivery.&lt;/p&gt;
+&lt;h5&gt;UsersController changes (and a bonus mailer)&lt;/h5&gt;
+&lt;p&gt;Since we take care of the email notification on the model level (for now, until we offload it to a background processor later) we don&amp;#8217;t need to change our &lt;code&gt;UsersController#create&lt;/code&gt; methods, but we do need to add an action that will take care of the activation for us:&lt;/p&gt;
+&lt;script src=&quot;http://gist.github.com/324700.js?file=users_controller.rb&quot;&gt;&lt;/script&gt;&lt;p&gt;Remember to update your routes and either:&lt;/p&gt;
+&lt;ul&gt;
+ &lt;li&gt;add a &lt;code&gt;:collection =&amp;gt; {:activate =&amp;gt; :get}&lt;/code&gt; to your &lt;code&gt;map.users&lt;/code&gt; routes.&lt;/li&gt;
+ &lt;li&gt;add a named route like &lt;code&gt;map.activate '/users/activate/:activation_code, :controller =&amp;gt; 'users', :action =&amp;gt; 'activate'&lt;/code&gt;&lt;/li&gt;
+&lt;/ul&gt;
+&lt;p&gt;we chose to add a &lt;strong&gt;named route&lt;/strong&gt;, just because it makes more sense and that the &lt;code&gt;activate&lt;/code&gt; action is not a collection action, but not one that requires an &lt;code&gt;id&lt;/code&gt; too.&lt;/p&gt;
+&lt;p&gt;Here are a &lt;a href=&quot;http://gist.github.com/324719&quot;&gt;sample user mailer&lt;/a&gt; and an &lt;a href=&quot;http://gist.github.com/324722&quot;&gt;activation mail view&lt;/a&gt; if you really need them :)&lt;/p&gt;
+&lt;h4&gt;Conclusion&lt;/h4&gt;
+&lt;p&gt;In this part we didn&amp;#8217;t ran into &lt;strong&gt;that&lt;/strong&gt; many issues because we use Mongoid, the only real problem was the lack of observers but since we are going to offload the email sending process to a background processor, it doesn&amp;#8217;t really matter.&lt;br /&gt;
+In the next part, we&amp;#8217;ll tackle password resets and background processing.&lt;/p&gt;</content>
+ </entry>
+
+ <entry>
<title>Creating a Rails authentication system on Mongoid - Part 1</title>
<link href="http://blog.eizesus.com/2010/03/creating-a-rails-authentication-system-on-mongoid"/>
<updated>2010-03-06T00:00:00-05:00</updated>
@@ -366,27 +434,5 @@ Some of you may say &amp;#8220;so why don&amp;#8217;t you use a local ssh deploy
&lt;p&gt;And i am not forgetting &lt;a href=&quot;http://www.heroku.com&quot;&gt;Heroku&lt;/a&gt; which proves to be an extremely reliable service and for some projects that&amp;#8217;s all you really need, service and cost wise.&lt;/p&gt;</content>
</entry>
- <entry>
- <title>Facebooker tips 1 - SessionExpired, Cucumber and Default environment</title>
- <link href="http://blog.eizesus.com/2010/02/facebooker-tips-1-session-expiry-cucumber-and-env-6-2-2010"/>
- <updated>2010-02-06T00:00:00-05:00</updated>
- <id>http://gitready.com/2010/02/facebooker-tips-1-session-expiry-cucumber-and-env-6-2-2010</id>
- <content type="html">&lt;p&gt;For my next project i have to use &lt;a href=&quot;http://gemcutter.org/gems/facebooker&quot;&gt;Facebooker&lt;/a&gt;, which is currently the most stable Ruby gem that wraps the Facebook &lt;span class=&quot;caps&quot;&gt;API&lt;/span&gt;.&lt;br /&gt;
-Sadly it&amp;#8217;s very badly documented and for the past 2 projects i&amp;#8217;ve been using it, i remember exactly why i don&amp;#8217;t really like this library.&lt;/p&gt;
-&lt;p&gt;So why do i use it and don&amp;#8217;t write our own implementation? we&amp;#8217;ll we do. but it will take some time since the Facebook API&amp;#8217;s own documentation is a world of pain and we are not going to make the same mistake again and make a library with poor documentation.&lt;/p&gt;
-&lt;p&gt;So for the meanwhile, i&amp;#8217;ll just post some useful tips we find along the way and might help others getting things to work:&lt;/p&gt;
-&lt;h4&gt;Tip #1: SessionExpired&lt;/h4&gt;
-&lt;p&gt;Yeah, i posted how to handle &lt;a href=&quot;http://blog.eizesus.com/2009/11/handle-facebook-session-expiry-with-facebooker/&quot;&gt;Facebook&amp;#8217;s stupid Session Expiry&lt;/a&gt; in a safe manner before, thought it worth mentioning again.&lt;/p&gt;
-&lt;h4&gt;Tip #2: Test your Facebook application with Facebook&lt;/h4&gt;
-&lt;p&gt;Oh this was hell, there was absolutely no documentation about how to mock a facebook user and &lt;span class=&quot;caps&quot;&gt;API&lt;/span&gt; interaction if you use Cucumber. I did find &lt;a href=&quot;http://opensoul.org/2009/3/6/testing-facebook-with-cucumber&quot;&gt;this&lt;/a&gt; tutorial which, just doesn&amp;#8217;t work.&lt;/p&gt;
-&lt;p&gt;So for example if we use this scenario:&lt;/p&gt;
-&lt;script src=&quot;http://gist.github.com/296758.js?file=manage_users.feature&quot;&gt;&lt;/script&gt;&lt;p&gt;And this is how the step goes:&lt;/p&gt;
-&lt;script src=&quot;http://gist.github.com/296758.js?file=user_steps.rb&quot;&gt;&lt;/script&gt;&lt;p&gt;Note the usage of &lt;code&gt;User#facebook_user&lt;/code&gt;, which basically returns a &lt;code&gt;Facebooker::User&lt;/code&gt; instance:&lt;/p&gt;
-&lt;script src=&quot;http://gist.github.com/296758.js?file=user.rb&quot;&gt;&lt;/script&gt;&lt;h4&gt;Cucumber&amp;#8217;s default environment&lt;/h4&gt;
-&lt;p&gt;Cucumber runs on it&amp;#8217;s own environment, default named &lt;code&gt;Cucumber&lt;/code&gt;, so when you get something like that trying to run your features:&lt;/p&gt;
-&lt;script src=&quot;http://gist.github.com/296759.js?file=gistfile1.txt&quot;&gt;&lt;/script&gt;&lt;p&gt;All you need to do is just to add another environment named &lt;code&gt;cucumber&lt;/code&gt; in &lt;code&gt;config/facebooker.yml&lt;/code&gt; :&lt;/p&gt;
-&lt;script src=&quot;http://gist.github.com/296763.js?file=facebooker.yml&quot;&gt;&lt;/script&gt;</content>
- </entry>
-
</feed>
View
10 _site/index.html
@@ -71,6 +71,11 @@ <h3 id="post-info">POSTS</h3>
<div class="posts_list">
<div class="post_headline">
+ <h4><a href="/2010/03/creating-a-rails-authentication-system-on-mongoid-part-2-7-3-2010">Creating a Rails authentication system on Mongoid Part 2 - Remember me and Account activation</a></h4>
+ <em>07/03/2010</em>
+ </div>
+
+ <div class="post_headline">
<h4><a href="/2010/03/creating-a-rails-authentication-system-on-mongoid">Creating a Rails authentication system on Mongoid - Part 1</a></h4>
<em>06/03/2010</em>
</div>
@@ -215,11 +220,6 @@ <h3 id="post-info">POSTS</h3>
<em>30/10/2009</em>
</div>
- <div class="post_headline">
- <h4><a href="/2009/10/using-blackbird-javascript-console-in-rails">Using BlackBird javascript console in Rails</a></h4>
- <em>28/10/2009</em>
- </div>
-
</div>
<div class="clear"></div>
</div> <!-- /POST -->
View
5 _site/page10/index.html
@@ -71,6 +71,11 @@ <h3 id="post-info">POSTS</h3>
<div class="posts_list">
<div class="post_headline">
+ <h4><a href="/2008/07/randexp-gem-2">RandExp Gem</a></h4>
+ <em>16/07/2008</em>
+ </div>
+
+ <div class="post_headline">
<h4><a href="/2008/07/apache-x-sendfile-in-rails-2">Apache X-SendFile in Rails</a></h4>
<em>16/07/2008</em>
</div>
View
10 _site/page2/index.html
@@ -71,6 +71,11 @@ <h3 id="post-info">POSTS</h3>
<div class="posts_list">
<div class="post_headline">
+ <h4><a href="/2009/10/using-blackbird-javascript-console-in-rails">Using BlackBird javascript console in Rails</a></h4>
+ <em>28/10/2009</em>
+ </div>
+
+ <div class="post_headline">
<h4><a href="/2009/10/bag-o-links-27-10-2009">Bag O' Links - 27/10/2009</a></h4>
<em>27/10/2009</em>
</div>
@@ -215,11 +220,6 @@ <h3 id="post-info">POSTS</h3>
<em>10/08/2009</em>
</div>
- <div class="post_headline">
- <h4><a href="/2009/08/bag-o-links-10-8-2009">Bag O' Links - 10/8/2009</a></h4>
- <em>10/08/2009</em>
- </div>
-
</div>
<div class="clear"></div>
</div> <!-- /POST -->
View
10 _site/page3/index.html
@@ -71,6 +71,11 @@ <h3 id="post-info">POSTS</h3>
<div class="posts_list">
<div class="post_headline">
+ <h4><a href="/2009/08/bag-o-links-10-8-2009">Bag O' Links - 10/8/2009</a></h4>
+ <em>10/08/2009</em>
+ </div>
+
+ <div class="post_headline">
<h4><a href="/2009/08/bag-o-links-7-8-2009">Bag O' Links - 7/8/2009</a></h4>
<em>07/08/2009</em>
</div>
@@ -215,11 +220,6 @@ <h3 id="post-info">POSTS</h3>
<em>13/05/2009</em>
</div>
- <div class="post_headline">
- <h4><a href="/2009/05/bag-o-links-10-5-2009">Bag O' Links - 10/5/2009</a></h4>
- <em>11/05/2009</em>
- </div>
-
</div>
<div class="clear"></div>
</div> <!-- /POST -->
View
10 _site/page4/index.html
@@ -71,6 +71,11 @@ <h3 id="post-info">POSTS</h3>
<div class="posts_list">
<div class="post_headline">
+ <h4><a href="/2009/05/bag-o-links-10-5-2009">Bag O' Links - 10/5/2009</a></h4>
+ <em>11/05/2009</em>
+ </div>
+
+ <div class="post_headline">
<h4><a href="/2009/05/railsbridge-com-volunteers-required">RailsBridge.com: volunteers required</a></h4>
<em>10/05/2009</em>
</div>
@@ -215,11 +220,6 @@ <h3 id="post-info">POSTS</h3>
<em>15/04/2009</em>
</div>
- <div class="post_headline">
- <h4><a href="/2009/04/bag-o-links-15-4-2009">Bag O' Links - 15/4/2009</a></h4>
- <em>15/04/2009</em>
- </div>
-
</div>
<div class="clear"></div>
</div> <!-- /POST -->
View
10 _site/page5/index.html
@@ -71,6 +71,11 @@ <h3 id="post-info">POSTS</h3>
<div class="posts_list">
<div class="post_headline">
+ <h4><a href="/2009/04/bag-o-links-15-4-2009">Bag O' Links - 15/4/2009</a></h4>
+ <em>15/04/2009</em>
+ </div>
+
+ <div class="post_headline">
<h4><a href="/2009/04/bag-o-links-14-4-2009">Bag O' Links - 14/4/2009</a></h4>
<em>14/04/2009</em>
</div>
@@ -215,11 +220,6 @@ <h3 id="post-info">POSTS</h3>
<em>23/03/2009</em>
</div>
- <div class="post_headline">
- <h4><a href="/2009/03/ie8-overview">IE8 Overview</a></h4>
- <em>22/03/2009</em>
- </div>
-
</div>
<div class="clear"></div>
</div> <!-- /POST -->
View
10 _site/page6/index.html
@@ -71,6 +71,11 @@ <h3 id="post-info">POSTS</h3>
<div class="posts_list">
<div class="post_headline">
+ <h4><a href="/2009/03/ie8-overview">IE8 Overview</a></h4>
+ <em>22/03/2009</em>
+ </div>
+
+ <div class="post_headline">
<h4><a href="/2009/03/jquery-s-ready-runs-before-load-event">JQuery's ready() runs before load() event?</a></h4>
<em>21/03/2009</em>
</div>
@@ -215,11 +220,6 @@ <h3 id="post-info">POSTS</h3>
<em>30/01/2009</em>
</div>
- <div class="post_headline">
- <h4><a href="/2009/01/amazon-aws-calculate-your-monthly-costs-on-amazon-s3-ec2-and-sqs">Amazon AWS: Calculate your monthly costs on Amazon S3, EC2 and SQS</a></h4>
- <em>30/01/2009</em>
- </div>
-
</div>
<div class="clear"></div>
</div> <!-- /POST -->
View
10 _site/page7/index.html
@@ -71,6 +71,11 @@ <h3 id="post-info">POSTS</h3>
<div class="posts_list">
<div class="post_headline">
+ <h4><a href="/2009/01/amazon-aws-calculate-your-monthly-costs-on-amazon-s3-ec2-and-sqs">Amazon AWS: Calculate your monthly costs on Amazon S3, EC2 and SQS</a></h4>
+ <em>30/01/2009</em>
+ </div>
+
+ <div class="post_headline">
<h4><a href="/2009/01/web-base-sql-schema-design-2">Web Based SQL schema design</a></h4>
<em>29/01/2009</em>
</div>
@@ -215,11 +220,6 @@ <h3 id="post-info">POSTS</h3>
<em>11/01/2009</em>
</div>
- <div class="post_headline">
- <h4><a href="/2009/01/yougetsignal-com-great-web2-0-tool-2">yougetsignal.com: Great web2.0 tool</a></h4>
- <em>09/01/2009</em>
- </div>
-
</div>
<div class="clear"></div>
</div> <!-- /POST -->
View
10 _site/page8/index.html
@@ -71,6 +71,11 @@ <h3 id="post-info">POSTS</h3>
<div class="posts_list">
<div class="post_headline">
+ <h4><a href="/2009/01/yougetsignal-com-great-web2-0-tool-2">yougetsignal.com: Great web2.0 tool</a></h4>
+ <em>09/01/2009</em>
+ </div>
+
+ <div class="post_headline">
<h4><a href="/2009/01/free-shell-accounts-2">Free Shell Accounts</a></h4>
<em>09/01/2009</em>
</div>
@@ -215,11 +220,6 @@ <h3 id="post-info">POSTS</h3>
<em>24/10/2008</em>
</div>
- <div class="post_headline">
- <h4><a href="/2008/10/tip-finding-all-unread-messages-in-your-gmail-inbox-2">Tip: Finding all Unread messages in your gmail inbox</a></h4>
- <em>24/10/2008</em>
- </div>
-
</div>
<div class="clear"></div>
</div> <!-- /POST -->
View
10 _site/page9/index.html
@@ -71,6 +71,11 @@ <h3 id="post-info">POSTS</h3>
<div class="posts_list">
<div class="post_headline">
+ <h4><a href="/2008/10/tip-finding-all-unread-messages-in-your-gmail-inbox-2">Tip: Finding all Unread messages in your gmail inbox</a></h4>
+ <em>24/10/2008</em>
+ </div>
+
+ <div class="post_headline">
<h4><a href="/2008/10/string-boolean-methodmissing-fun-2">String boolean: MethodMissing fun!</a></h4>
<em>24/10/2008</em>
</div>
@@ -215,11 +220,6 @@ <h3 id="post-info">POSTS</h3>
<em>16/07/2008</em>
</div>
- <div class="post_headline">
- <h4><a href="/2008/07/randexp-gem-2">RandExp Gem</a></h4>
- <em>16/07/2008</em>
- </div>
-
</div>
<div class="clear"></div>
</div> <!-- /POST -->
Please sign in to comment.
Something went wrong with that request. Please try again.