<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet href="http://feeds.binarylogic.com/~d/styles/atom10full.xsl" type="text/xsl" media="screen"?><?xml-stylesheet href="http://feeds.binarylogic.com/~d/styles/itemcontent.css" type="text/css" media="screen"?><feed xmlns="http://www.w3.org/2005/Atom" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" xml:lang="en-US">
  <title>Binary Logic</title>
  <id>tag:www.binarylogic.com,2009:mephisto/</id>
  <generator uri="http://mephistoblog.com" version="0.8.0">Mephisto Drax</generator>
  
  <link href="http://www.binarylogic.com/" rel="alternate" type="text/html" />
  <updated>2008-11-30T08:19:20Z</updated>
  <link rel="self" href="http://feeds.binarylogic.com/binarylogic" type="application/atom+xml" /><entry xml:base="http://www.binarylogic.com/">
    <author>
      <name>benjohnson</name>
    </author>
    <id>tag:www.binarylogic.com,2008-11-30:280</id>
    <published>2008-11-30T07:59:00Z</published>
    <updated>2008-11-30T03:17:15Z</updated>
    <category term="Searchlogic" />
    <category term="advanced searching" />
    <category term="complex searching" />
    <category term="searchlogic" />
    <link href="http://feeds.binarylogic.com/~r/binarylogic/~3/470048763/searchlogic-1-5-7-complex-searching-no-longer-a-problem" rel="alternate" type="text/html" />
    <title>Searchlogic 1.5.7 - Complex searching no longer a problem</title>
<summary type="html">&lt;p&gt;Searchlogic 1.5.7 is by far my favorite release because it takes Searchlogic to a whole new level. It solves a problem I thought it would never solve. Before I explain the new features, let me give you a quick run down on my perspective of Searchlogic:&lt;/p&gt;

&lt;h2&gt;Fillin' a brotha in&lt;/h2&gt;

&lt;p&gt;A lot of people think Searchlogic is a "console" searching utility. Meaning you can pop into your console and execute some simple searches quickly and easily, and it is, but by accident. My goal with Searchlogic has always been freeing your application of searching clutter. If you've ever done an app with searching you know there is a lot of "cruft" that goes along with it: nasty controller actions, excessive named_scopes, etc. Searchlogic rids you of this by representing an entire search's criteria with a hash: conditions, ordering, pagination, the whole package. Why is this nice? Because GET and POST parameters are a hash. What's nice about that? Because an HTML form's sole purpose is to send GET and POST parameters to a URI. This means you can build a form that represents your entire search. Adding a condition to your search is as easy as adding a field to your form. This ultimately makes your controller dead simple, frees it of any search clutter, and rids your models of excessive named_scopes. Here is what your controller action should look like with Searchlogic:&lt;/p&gt;

&lt;pre class="cobalt"&gt;
&lt;span class="Variable"&gt;&lt;span class="Punctuation"&gt;@&lt;/span&gt;search&lt;/span&gt; &lt;span class="Keyword"&gt;=&lt;/span&gt; &lt;span class="Support"&gt;User&lt;/span&gt;&lt;span class="FunctionCall"&gt;&lt;span class="Punctuation"&gt;.&lt;/span&gt;&lt;span class="Entity"&gt;new_search&lt;/span&gt;&lt;/span&gt;&lt;span class="Punctuation"&gt;(&lt;/span&gt;params&lt;span class="Punctuation"&gt;[&lt;/span&gt;&lt;span class="Constant"&gt;&lt;span class="Punctuation"&gt;:&lt;/span&gt;search&lt;/span&gt;&lt;span class="Punctuation"&gt;]&lt;/span&gt;&lt;span class="Punctuation"&gt;)&lt;/span&gt;
&lt;span class="Variable"&gt;&lt;span class="Punctuation"&gt;@&lt;/span&gt;users&lt;/span&gt; &lt;span class="Keyword"&gt;=&lt;/span&gt; &lt;span class="Variable"&gt;&lt;span class="Punctuation"&gt;@&lt;/span&gt;search&lt;/span&gt;&lt;span class="FunctionCall"&gt;&lt;span class="Punctuation"&gt;.&lt;/span&gt;&lt;span class="Entity"&gt;all&lt;/span&gt;&lt;/span&gt;
&lt;/pre&gt;</summary><content type="html">
            &lt;p&gt;Searchlogic 1.5.7 is by far my favorite release because it takes Searchlogic to a whole new level. It solves a problem I thought it would never solve. Before I explain the new features, let me give you a quick run down on my perspective of Searchlogic:&lt;/p&gt;

&lt;h2&gt;Fillin' a brotha in&lt;/h2&gt;

&lt;p&gt;A lot of people think Searchlogic is a "console" searching utility. Meaning you can pop into your console and execute some simple searches quickly and easily, and it is, but by accident. My goal with Searchlogic has always been freeing your application of searching clutter. If you've ever done an app with searching you know there is a lot of "cruft" that goes along with it: nasty controller actions, excessive named_scopes, etc. Searchlogic rids you of this by representing an entire search's criteria with a hash: conditions, ordering, pagination, the whole package. Why is this nice? Because GET and POST parameters are a hash. What's nice about that? Because an HTML form's sole purpose is to send GET and POST parameters to a URI. This means you can build a form that represents your entire search. Adding a condition to your search is as easy as adding a field to your form. This ultimately makes your controller dead simple, frees it of any search clutter, and rids your models of excessive named_scopes. Here is what your controller action should look like with Searchlogic:&lt;/p&gt;

&lt;pre class="cobalt"&gt;
&lt;span class="Variable"&gt;&lt;span class="Punctuation"&gt;@&lt;/span&gt;search&lt;/span&gt; &lt;span class="Keyword"&gt;=&lt;/span&gt; &lt;span class="Support"&gt;User&lt;/span&gt;&lt;span class="FunctionCall"&gt;&lt;span class="Punctuation"&gt;.&lt;/span&gt;&lt;span class="Entity"&gt;new_search&lt;/span&gt;&lt;/span&gt;&lt;span class="Punctuation"&gt;(&lt;/span&gt;params&lt;span class="Punctuation"&gt;[&lt;/span&gt;&lt;span class="Constant"&gt;&lt;span class="Punctuation"&gt;:&lt;/span&gt;search&lt;/span&gt;&lt;span class="Punctuation"&gt;]&lt;/span&gt;&lt;span class="Punctuation"&gt;)&lt;/span&gt;
&lt;span class="Variable"&gt;&lt;span class="Punctuation"&gt;@&lt;/span&gt;users&lt;/span&gt; &lt;span class="Keyword"&gt;=&lt;/span&gt; &lt;span class="Variable"&gt;&lt;span class="Punctuation"&gt;@&lt;/span&gt;search&lt;/span&gt;&lt;span class="FunctionCall"&gt;&lt;span class="Punctuation"&gt;.&lt;/span&gt;&lt;span class="Entity"&gt;all&lt;/span&gt;&lt;/span&gt;
&lt;/pre&gt;
&lt;h2&gt;Complex searching in tha house&lt;/h2&gt;

&lt;p&gt;This is great for simple searching, but how do you represent complex searches this way? Let's take this query:&lt;/p&gt;

&lt;pre class="cobalt"&gt;
select * from users where id &amp;gt; 5 AND
  (email LIKE 'ben%' or email LIKE '%binarylogic.com') AND
  first_name LIKE '%ben%'
&lt;/pre&gt;

&lt;p&gt;Before, Searchlogic couldn't handle this. It did not support grouping (parenthesis) and it did not allow you to mix and match "AND" and "OR", you had to pick one or the other. Why? Because I never intended for Searchlogic to replace complex searching. If you need to perform a complex search there is nothing wrong with using Searchlogic in conjunction with some named_scopes. SQL is not bad, but what is bad is that all of that searching cruft starts seeping back into your project. All of a sudden your controller is not clean, your form has to stray away from using the form builder, and your model gets cluttered with named scopes that you are only using for one section in your application. Searchlogic fails to meet its goal of keeping your application free of "search clutter" and a tear runs down your cheek.&lt;/p&gt;

&lt;h2&gt;Slap a prefix on it!&lt;/h2&gt;

&lt;p&gt;Solving the problem of mixing "AND" and "OR" was easier than I thought. The only major change I had to make was making the conditions order relevant. The order you set your conditions is the same order they will appear in your SQL statement. Before, the conditions were stored in a hash, where order was not preserved. Now you can slap an "and_" or "or_" prefix in front of your conditions:&lt;/p&gt;

&lt;pre class="cobalt"&gt;
search &lt;span class="Keyword"&gt;=&lt;/span&gt; &lt;span class="Support"&gt;User&lt;/span&gt;&lt;span class="FunctionCall"&gt;&lt;span class="Punctuation"&gt;.&lt;/span&gt;&lt;span class="Entity"&gt;new_search&lt;/span&gt;&lt;/span&gt;
search&lt;span class="FunctionCall"&gt;&lt;span class="Punctuation"&gt;.&lt;/span&gt;&lt;span class="Entity"&gt;conditions&lt;/span&gt;&lt;/span&gt;&lt;span class="FunctionCall"&gt;&lt;span class="Punctuation"&gt;.&lt;/span&gt;&lt;span class="Entity"&gt;name_like&lt;/span&gt;&lt;/span&gt; &lt;span class="Keyword"&gt;=&lt;/span&gt; &lt;span class="String"&gt;&lt;span class="Punctuation"&gt;&amp;quot;&lt;/span&gt;Ben&lt;span class="Punctuation"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
search&lt;span class="FunctionCall"&gt;&lt;span class="Punctuation"&gt;.&lt;/span&gt;&lt;span class="Entity"&gt;conditions&lt;/span&gt;&lt;/span&gt;&lt;span class="FunctionCall"&gt;&lt;span class="Punctuation"&gt;.&lt;/span&gt;&lt;span class="Entity"&gt;or_email_like&lt;/span&gt;&lt;/span&gt; &lt;span class="Keyword"&gt;=&lt;/span&gt; &lt;span class="String"&gt;&lt;span class="Punctuation"&gt;&amp;quot;&lt;/span&gt;a@a.com&lt;span class="Punctuation"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
search&lt;span class="FunctionCall"&gt;&lt;span class="Punctuation"&gt;.&lt;/span&gt;&lt;span class="Entity"&gt;conditions&lt;/span&gt;&lt;/span&gt;&lt;span class="FunctionCall"&gt;&lt;span class="Punctuation"&gt;.&lt;/span&gt;&lt;span class="Entity"&gt;and_id_gt&lt;/span&gt;&lt;/span&gt; &lt;span class="Keyword"&gt;=&lt;/span&gt; &lt;span class="Constant"&gt;5&lt;/span&gt;
&lt;span class="Comment"&gt;&lt;span class="Punctuation"&gt;#&lt;/span&gt; =&amp;gt; name LIKE '%Ben%' OR email like '%a@a.com%' AND id &amp;gt; 5&lt;/span&gt;
&lt;/pre&gt;

&lt;p&gt;The last condition "and_id_gt" could also be written as "id_gt", because, by default, we are joining with "AND". Not specifying a prefix uses whatever you are joining your conditions with by default, specifying a prefix will &lt;em&gt;always&lt;/em&gt; use that join. If you want your conditions to be joined by "OR" by default just do:&lt;/p&gt;

&lt;pre class="cobalt"&gt;
search&lt;span class="FunctionCall"&gt;&lt;span class="Punctuation"&gt;.&lt;/span&gt;&lt;span class="Entity"&gt;any&lt;/span&gt;&lt;/span&gt; &lt;span class="Keyword"&gt;=&lt;/span&gt; &lt;span class="Constant"&gt;true&lt;/span&gt;
&lt;/pre&gt;

&lt;h2&gt;You best wrap it with some parenthesis&lt;/h2&gt;

&lt;p&gt;What about grouping conditions with parenthesis? No problem. Take the above query:&lt;/p&gt;

&lt;pre class="cobalt"&gt;
search &lt;span class="Keyword"&gt;=&lt;/span&gt; &lt;span class="Support"&gt;User&lt;/span&gt;&lt;span class="FunctionCall"&gt;&lt;span class="Punctuation"&gt;.&lt;/span&gt;&lt;span class="Entity"&gt;new_search&lt;/span&gt;&lt;/span&gt;
search&lt;span class="FunctionCall"&gt;&lt;span class="Punctuation"&gt;.&lt;/span&gt;&lt;span class="Entity"&gt;conditions&lt;/span&gt;&lt;/span&gt;&lt;span class="FunctionCall"&gt;&lt;span class="Punctuation"&gt;.&lt;/span&gt;&lt;span class="Entity"&gt;id_gt&lt;/span&gt;&lt;/span&gt; &lt;span class="Keyword"&gt;=&lt;/span&gt; &lt;span class="Constant"&gt;5&lt;/span&gt;
search&lt;span class="FunctionCall"&gt;&lt;span class="Punctuation"&gt;.&lt;/span&gt;&lt;span class="Entity"&gt;conditions&lt;/span&gt;&lt;/span&gt;&lt;span class="FunctionCall"&gt;&lt;span class="Punctuation"&gt;.&lt;/span&gt;&lt;span class="Entity"&gt;group&lt;/span&gt;&lt;/span&gt; &lt;span class="Keyword"&gt;do &lt;/span&gt;&lt;span class="Punctuation"&gt;|&lt;/span&gt;&lt;span class="Variable"&gt;group&lt;/span&gt;&lt;span class="Punctuation"&gt;|&lt;/span&gt;
  group&lt;span class="FunctionCall"&gt;&lt;span class="Punctuation"&gt;.&lt;/span&gt;&lt;span class="Entity"&gt;email_begins_with&lt;/span&gt;&lt;/span&gt; &lt;span class="Keyword"&gt;=&lt;/span&gt; &lt;span class="String"&gt;&lt;span class="Punctuation"&gt;&amp;quot;&lt;/span&gt;ben&lt;span class="Punctuation"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
  group&lt;span class="FunctionCall"&gt;&lt;span class="Punctuation"&gt;.&lt;/span&gt;&lt;span class="Entity"&gt;or_email_ends_with&lt;/span&gt;&lt;/span&gt; &lt;span class="Keyword"&gt;=&lt;/span&gt; &lt;span class="String"&gt;&lt;span class="Punctuation"&gt;&amp;quot;&lt;/span&gt;binarylogic.com&lt;span class="Punctuation"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class="Keyword"&gt;end&lt;/span&gt;
search&lt;span class="FunctionCall"&gt;&lt;span class="Punctuation"&gt;.&lt;/span&gt;&lt;span class="Entity"&gt;conditions&lt;/span&gt;&lt;/span&gt;&lt;span class="FunctionCall"&gt;&lt;span class="Punctuation"&gt;.&lt;/span&gt;&lt;span class="Entity"&gt;first_name_contains&lt;/span&gt;&lt;/span&gt; &lt;span class="Keyword"&gt;=&lt;/span&gt; &lt;span class="String"&gt;&lt;span class="Punctuation"&gt;&amp;quot;&lt;/span&gt;ben&lt;span class="Punctuation"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
search&lt;span class="FunctionCall"&gt;&lt;span class="Punctuation"&gt;.&lt;/span&gt;&lt;span class="Entity"&gt;all&lt;/span&gt;&lt;/span&gt;
&lt;/pre&gt;

&lt;p&gt;What about a hash?&lt;/p&gt;

&lt;pre class="cobalt"&gt;
search &lt;span class="Keyword"&gt;=&lt;/span&gt; &lt;span class="Support"&gt;User&lt;/span&gt;&lt;span class="FunctionCall"&gt;&lt;span class="Punctuation"&gt;.&lt;/span&gt;&lt;span class="Entity"&gt;new_search&lt;/span&gt;&lt;/span&gt;&lt;span class="Punctuation"&gt;(&lt;/span&gt;&lt;span class="Constant"&gt;&lt;span class="Punctuation"&gt;:&lt;/span&gt;conditions&lt;/span&gt; &lt;span class="Punctuation"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="Punctuation"&gt;[&lt;/span&gt;
  &lt;span class="Punctuation"&gt;{&lt;/span&gt;&lt;span class="Constant"&gt;&lt;span class="Punctuation"&gt;:&lt;/span&gt;id_gt&lt;/span&gt; &lt;span class="Punctuation"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="Constant"&gt;5&lt;/span&gt;&lt;span class="Punctuation"&gt;}&lt;/span&gt;&lt;span class="Punctuation"&gt;,&lt;/span&gt;
  &lt;span class="Punctuation"&gt;{&lt;/span&gt;&lt;span class="Constant"&gt;&lt;span class="Punctuation"&gt;:&lt;/span&gt;group&lt;/span&gt; &lt;span class="Punctuation"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="Punctuation"&gt;[&lt;/span&gt;
    &lt;span class="Punctuation"&gt;{&lt;/span&gt;&lt;span class="Constant"&gt;&lt;span class="Punctuation"&gt;:&lt;/span&gt;email_begins_with&lt;/span&gt; &lt;span class="Punctuation"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="String"&gt;&lt;span class="Punctuation"&gt;&amp;quot;&lt;/span&gt;ben&lt;span class="Punctuation"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class="Punctuation"&gt;}&lt;/span&gt;&lt;span class="Punctuation"&gt;,&lt;/span&gt;
    &lt;span class="Punctuation"&gt;{&lt;/span&gt;&lt;span class="Constant"&gt;&lt;span class="Punctuation"&gt;:&lt;/span&gt;or_email_ends_with&lt;/span&gt; &lt;span class="Punctuation"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="String"&gt;&lt;span class="Punctuation"&gt;&amp;quot;&lt;/span&gt;binarylogic.com&lt;span class="Punctuation"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class="Punctuation"&gt;}&lt;/span&gt;
  &lt;span class="Punctuation"&gt;]&lt;/span&gt;&lt;span class="Punctuation"&gt;}&lt;/span&gt;&lt;span class="Punctuation"&gt;,&lt;/span&gt;
  &lt;span class="Punctuation"&gt;{&lt;/span&gt;&lt;span class="Constant"&gt;&lt;span class="Punctuation"&gt;:&lt;/span&gt;first_name_contains&lt;/span&gt; &lt;span class="Punctuation"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="String"&gt;&lt;span class="Punctuation"&gt;&amp;quot;&lt;/span&gt;ben&lt;span class="Punctuation"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class="Punctuation"&gt;}&lt;/span&gt;
&lt;span class="Punctuation"&gt;]&lt;/span&gt;&lt;span class="Punctuation"&gt;)&lt;/span&gt;
&lt;/pre&gt;

&lt;p&gt;What about a form?&lt;/p&gt;

&lt;pre class="cobalt"&gt;
&lt;span class="Keyword"&gt;-&lt;/span&gt; form_for &lt;span class="Variable"&gt;&lt;span class="Punctuation"&gt;@&lt;/span&gt;search&lt;/span&gt; &lt;span class="Keyword"&gt;do &lt;/span&gt;&lt;span class="Punctuation"&gt;|&lt;/span&gt;&lt;span class="Variable"&gt;search&lt;/span&gt;&lt;span class="Punctuation"&gt;|&lt;/span&gt;
  &lt;span class="Keyword"&gt;-&lt;/span&gt; search&lt;span class="FunctionCall"&gt;&lt;span class="Punctuation"&gt;.&lt;/span&gt;&lt;span class="Entity"&gt;fields_for&lt;/span&gt;&lt;/span&gt; &lt;span class="String"&gt;&lt;span class="Punctuation"&gt;&amp;quot;&lt;/span&gt;conditions&lt;span class="Punctuation"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class="Keyword"&gt;do &lt;/span&gt;&lt;span class="Punctuation"&gt;|&lt;/span&gt;&lt;span class="Variable"&gt;conditions_array&lt;/span&gt;&lt;span class="Punctuation"&gt;|&lt;/span&gt;
    &lt;span class="Keyword"&gt;-&lt;/span&gt; conditions_array&lt;span class="FunctionCall"&gt;&lt;span class="Punctuation"&gt;.&lt;/span&gt;&lt;span class="Entity"&gt;fields_for&lt;/span&gt;&lt;/span&gt; &lt;span class="String"&gt;&lt;span class="Punctuation"&gt;&amp;quot;&lt;/span&gt;[]&lt;span class="Punctuation"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class="Punctuation"&gt;,&lt;/span&gt; search&lt;span class="FunctionCall"&gt;&lt;span class="Punctuation"&gt;.&lt;/span&gt;&lt;span class="Entity"&gt;object&lt;/span&gt;&lt;/span&gt;&lt;span class="FunctionCall"&gt;&lt;span class="Punctuation"&gt;.&lt;/span&gt;&lt;span class="Entity"&gt;conditions&lt;/span&gt;&lt;/span&gt; &lt;span class="Keyword"&gt;do &lt;/span&gt;&lt;span class="Punctuation"&gt;|&lt;/span&gt;&lt;span class="Variable"&gt;conditions&lt;/span&gt;&lt;span class="Punctuation"&gt;|&lt;/span&gt;
      &lt;span class="Keyword"&gt;=&lt;/span&gt; conditions&lt;span class="FunctionCall"&gt;&lt;span class="Punctuation"&gt;.&lt;/span&gt;&lt;span class="Entity"&gt;text_field&lt;/span&gt;&lt;/span&gt; &lt;span class="Constant"&gt;&lt;span class="Punctuation"&gt;:&lt;/span&gt;id_gt&lt;/span&gt;
      &lt;span class="Keyword"&gt;-&lt;/span&gt; conditions&lt;span class="FunctionCall"&gt;&lt;span class="Punctuation"&gt;.&lt;/span&gt;&lt;span class="Entity"&gt;fields_for&lt;/span&gt;&lt;/span&gt; &lt;span class="String"&gt;&lt;span class="Punctuation"&gt;&amp;quot;&lt;/span&gt;group&lt;span class="Punctuation"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class="Keyword"&gt;do &lt;/span&gt;&lt;span class="Punctuation"&gt;|&lt;/span&gt;&lt;span class="Variable"&gt;group_array&lt;/span&gt;&lt;span class="Punctuation"&gt;|&lt;/span&gt;
        &lt;span class="Keyword"&gt;-&lt;/span&gt; group_array&lt;span class="FunctionCall"&gt;&lt;span class="Punctuation"&gt;.&lt;/span&gt;&lt;span class="Entity"&gt;fields_for&lt;/span&gt;&lt;/span&gt; &lt;span class="String"&gt;&lt;span class="Punctuation"&gt;&amp;quot;&lt;/span&gt;[]&lt;span class="Punctuation"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class="Keyword"&gt;do &lt;/span&gt;&lt;span class="Punctuation"&gt;|&lt;/span&gt;&lt;span class="Variable"&gt;group&lt;/span&gt;&lt;span class="Punctuation"&gt;|&lt;/span&gt;
          &lt;span class="Keyword"&gt;=&lt;/span&gt; group&lt;span class="FunctionCall"&gt;&lt;span class="Punctuation"&gt;.&lt;/span&gt;&lt;span class="Entity"&gt;text_field&lt;/span&gt;&lt;/span&gt; &lt;span class="Constant"&gt;&lt;span class="Punctuation"&gt;:&lt;/span&gt;email_begins_with&lt;/span&gt;
          &lt;span class="Keyword"&gt;=&lt;/span&gt; group&lt;span class="FunctionCall"&gt;&lt;span class="Punctuation"&gt;.&lt;/span&gt;&lt;span class="Entity"&gt;text_field&lt;/span&gt;&lt;/span&gt; &lt;span class="Constant"&gt;&lt;span class="Punctuation"&gt;:&lt;/span&gt;or_email_ends_with&lt;/span&gt;
      &lt;span class="Keyword"&gt;=&lt;/span&gt; conditions&lt;span class="FunctionCall"&gt;&lt;span class="Punctuation"&gt;.&lt;/span&gt;&lt;span class="Entity"&gt;text_field&lt;/span&gt;&lt;/span&gt; &lt;span class="Constant"&gt;&lt;span class="Punctuation"&gt;:&lt;/span&gt;first_name_contains&lt;/span&gt;
&lt;/pre&gt;

&lt;p&gt;You will notice the hash and the form are implementing arrays, thats because hashes do not preserve the order. In our case above, order is important to us. What does preserve the order? An array. So if order is relevant to you, then you need to structure your conditions into an array. There is no other choice with this, because forms can either submit a hash or an array of parameters.&lt;/p&gt;

&lt;p&gt;I know what you are thinking: "the above looks a little confusing and messy". I agree with you, to a point. The word "messy" is a relative term. In our case, we have no other choice, this is the 100% correct way to do this. That being said, this is clean, because there is no other cleaner option. Sorry to be a debbie downer here, but this is how forms work, there is nothing I can do about that. Regardless, the above is still cleaner than having a nasty controller action or adding a bunch of named_scopes into you model. Your search logic is nice and DRY, in one spot: the view.&lt;/p&gt;

&lt;h2&gt;99 problems, but complex searching aint one&lt;/h2&gt;

&lt;p&gt;I think this is pretty nifty, now you have the tools to construct any type of search in your form. I've been getting a lot of emails asking me about this, and I had to be a debbie downer and tell them to use named scopes. Now you can ditch the named scopes and keep your search logic nice and DRY in your form, where it probably belongs.&lt;/p&gt;

&lt;p&gt;The last thing I want to say is that there is a time and a place for a named scope, by no means am I discouraging them, because they are by far one of the nicest features in ActiveRecord. But something about creating a complex named scope or a bunch of small named scopes for a single action in one of my controllers felt dirty. It felt like clutter. I knew I would never use those named scopes anywhere else, and they were solely for that search form. After a while all of these named scopes start overlapping and start sharing search logic. If you're extremely picky like me, your don't feel like your code is DRY. So how far do you go to break down a named scope? Breaking them down too much defeats their purpose, but not breaking them down enough seems to create redundant search logic. Searchlogic solved my problem with this, now all of my view specific search logic is where it should be, in my view.&lt;/p&gt;
          &lt;img src="http://feeds.binarylogic.com/~r/binarylogic/~4/470048763" height="1" width="1"/&gt;</content>  <feedburner:origLink>http://www.binarylogic.com/2008/11/30/searchlogic-1-5-7-complex-searching-no-longer-a-problem</feedburner:origLink></entry>
  <entry xml:base="http://www.binarylogic.com/">
    <author>
      <name>benjohnson</name>
    </author>
    <id>tag:www.binarylogic.com,2008-11-23:253</id>
    <published>2008-11-23T22:46:00Z</published>
    <updated>2008-11-23T17:53:58Z</updated>
    <category term="Authlogic" />
    <category term="authlogic" />
    <category term="migrate" />
    <category term="restful_authentication" />
    <category term="transition" />
    <category term="upgrade" />
    <link href="http://feeds.binarylogic.com/~r/binarylogic/~3/463271426/tutorial-easily-migrate-from-restful_authentication-to-authlogic" rel="alternate" type="text/html" />
    <title>Tutorial: Easily migrate from restful_authentication to Authlogic</title>
<summary type="html">&lt;p&gt;I've been getting a lot of emails asking the best way to migrate from restful_authentication. Where it gets complicated is in the password encryption methods. Authlogic and restful_authentication use different methods. You don't want to change this method because it will break backwards compatibility with your current passwords, meaning no one will be able to log into their account. Fear not, because I did all of the hard work for you...&lt;/p&gt;</summary><content type="html">
            &lt;p&gt;I've been getting a lot of emails asking the best way to migrate from restful_authentication. Where it gets complicated is in the password encryption methods. Authlogic and restful_authentication use different methods. You don't want to change this method because it will break backwards compatibility with your current passwords, meaning no one will be able to log into their account. Fear not, because I did all of the hard work for you...&lt;/p&gt;
&lt;h2&gt;Use the same password algorithm as restful_authentication&lt;/h2&gt;

&lt;pre class="cobalt"&gt;
&lt;span class="Comment"&gt;&lt;span class="Punctuation"&gt;#&lt;/span&gt; app/models/user.rb&lt;/span&gt;
&lt;span class="Keyword"&gt;class&lt;/span&gt; &lt;span class="Entity"&gt;User&lt;span class="EntityInheritedClass"&gt; &lt;span class="Punctuation"&gt;&amp;lt;&lt;/span&gt; ActiveRecord::Base&lt;/span&gt;&lt;/span&gt;
  acts_as_authentic &lt;span class="Constant"&gt;&lt;span class="Punctuation"&gt;:&lt;/span&gt;act_like_restful_authentication&lt;/span&gt; &lt;span class="Punctuation"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="Constant"&gt;true&lt;/span&gt;
&lt;span class="Keyword"&gt;end&lt;/span&gt;
&lt;/pre&gt;

&lt;h2&gt;Transition to one of Authlogic password algorithms&lt;/h2&gt;

&lt;p&gt;The first thing you need to do is make sure your database field "crypted_password" and "salt" allow for the storage of at least 128 characters (assuming you are migrating to Sha512). restful_authentication uses Sha1 which is 40 characters. If you are limiting the size, you need to create a migration that looks similar to:&lt;/p&gt;

&lt;pre class="cobalt"&gt;
change_column &lt;span class="Constant"&gt;&lt;span class="Punctuation"&gt;:&lt;/span&gt;users&lt;/span&gt;&lt;span class="Punctuation"&gt;,&lt;/span&gt; &lt;span class="Constant"&gt;&lt;span class="Punctuation"&gt;:&lt;/span&gt;crypted_password&lt;/span&gt;&lt;span class="Punctuation"&gt;,&lt;/span&gt; &lt;span class="Constant"&gt;&lt;span class="Punctuation"&gt;:&lt;/span&gt;string&lt;/span&gt;&lt;span class="Punctuation"&gt;,&lt;/span&gt; &lt;span class="Constant"&gt;&lt;span class="Punctuation"&gt;:&lt;/span&gt;limit&lt;/span&gt; &lt;span class="Punctuation"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="Constant"&gt;128&lt;/span&gt;&lt;span class="Punctuation"&gt;,&lt;/span&gt;
  &lt;span class="Constant"&gt;&lt;span class="Punctuation"&gt;:&lt;/span&gt;null&lt;/span&gt; &lt;span class="Punctuation"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="Constant"&gt;false&lt;/span&gt;&lt;span class="Punctuation"&gt;,&lt;/span&gt; &lt;span class="Constant"&gt;&lt;span class="Punctuation"&gt;:&lt;/span&gt;default&lt;/span&gt; &lt;span class="Punctuation"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="String"&gt;&lt;span class="Punctuation"&gt;&amp;quot;&lt;/span&gt;&lt;span class="Punctuation"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;

change_column &lt;span class="Constant"&gt;&lt;span class="Punctuation"&gt;:&lt;/span&gt;users&lt;/span&gt;&lt;span class="Punctuation"&gt;,&lt;/span&gt; &lt;span class="Constant"&gt;&lt;span class="Punctuation"&gt;:&lt;/span&gt;salt&lt;/span&gt;&lt;span class="Punctuation"&gt;,&lt;/span&gt; &lt;span class="Constant"&gt;&lt;span class="Punctuation"&gt;:&lt;/span&gt;string&lt;/span&gt;&lt;span class="Punctuation"&gt;,&lt;/span&gt; &lt;span class="Constant"&gt;&lt;span class="Punctuation"&gt;:&lt;/span&gt;limit&lt;/span&gt; &lt;span class="Punctuation"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="Constant"&gt;128&lt;/span&gt;&lt;span class="Punctuation"&gt;,&lt;/span&gt;
  &lt;span class="Constant"&gt;&lt;span class="Punctuation"&gt;:&lt;/span&gt;null&lt;/span&gt; &lt;span class="Punctuation"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="Constant"&gt;false&lt;/span&gt;&lt;span class="Punctuation"&gt;,&lt;/span&gt; &lt;span class="Constant"&gt;&lt;span class="Punctuation"&gt;:&lt;/span&gt;default&lt;/span&gt; &lt;span class="Punctuation"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="String"&gt;&lt;span class="Punctuation"&gt;&amp;quot;&lt;/span&gt;&lt;span class="Punctuation"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;/pre&gt;

&lt;p&gt;Now just tell acts_as_authentic what you are doing:&lt;/p&gt;

&lt;pre class="cobalt"&gt;
&lt;span class="Comment"&gt;&lt;span class="Punctuation"&gt;#&lt;/span&gt; app/models/user.rb&lt;/span&gt;
&lt;span class="Keyword"&gt;class&lt;/span&gt; &lt;span class="Entity"&gt;User&lt;span class="EntityInheritedClass"&gt; &lt;span class="Punctuation"&gt;&amp;lt;&lt;/span&gt; ActiveRecord::Base&lt;/span&gt;&lt;/span&gt;
  acts_as_authentic &lt;span class="Constant"&gt;&lt;span class="Punctuation"&gt;:&lt;/span&gt;transition_from_restful_authentication&lt;/span&gt; &lt;span class="Punctuation"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="Constant"&gt;true&lt;/span&gt;
&lt;span class="Keyword"&gt;end&lt;/span&gt;
&lt;/pre&gt;

&lt;p&gt;You could pass an optional argument to transition to any password algorithm you want. By default Authlogic uses the Sha512 algorithm, but let's say you wanted to transition to the BCrypt algorithm. No problem:&lt;/p&gt;

&lt;pre class="cobalt"&gt;
&lt;span class="Comment"&gt;&lt;span class="Punctuation"&gt;#&lt;/span&gt; app/models/user.rb&lt;/span&gt;
&lt;span class="Keyword"&gt;class&lt;/span&gt; &lt;span class="Entity"&gt;User&lt;span class="EntityInheritedClass"&gt; &lt;span class="Punctuation"&gt;&amp;lt;&lt;/span&gt; ActiveRecord::Base&lt;/span&gt;&lt;/span&gt;
  acts_as_authentic &lt;span class="Constant"&gt;&lt;span class="Punctuation"&gt;:&lt;/span&gt;transition_from_restful_authentication&lt;/span&gt; &lt;span class="Punctuation"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="Constant"&gt;true&lt;/span&gt;&lt;span class="Punctuation"&gt;,&lt;/span&gt;
    &lt;span class="Constant"&gt;&lt;span class="Punctuation"&gt;:&lt;/span&gt;crypto_provider&lt;/span&gt; &lt;span class="Punctuation"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="Support"&gt;Authlogic&lt;/span&gt;&lt;span class="FunctionCall"&gt;&lt;span class="Punctuation"&gt;::&lt;/span&gt;&lt;span class="Entity"&gt;CryptoProviders&lt;/span&gt;&lt;/span&gt;&lt;span class="FunctionCall"&gt;&lt;span class="Punctuation"&gt;::&lt;/span&gt;&lt;span class="Entity"&gt;BCrypt&lt;/span&gt;&lt;/span&gt;
&lt;span class="Keyword"&gt;end&lt;/span&gt;
&lt;/pre&gt;

&lt;p&gt;For more information on BCrypt &lt;a href="http://www.binarylogic.com/2008/11/22/storing-nuclear-launch-codes-in-your-app-enter-bcrypt-for-authlogic"&gt;checkout my blog post about it&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;What's the difference?&lt;/h2&gt;

&lt;p&gt;:act_like_restful_authentication will not change a thing, your users passwords will remain in the same format. From your database's perspective, it will be as if you are using restful_authentication.&lt;/p&gt;

&lt;p&gt;:transition_from_restful_authentication starts changing your users passwords using the Authlogic passwords system that you specify with the :crypto_provider option. How does it do this? It's simple, every time a user successfully logs in and their password is encrypted with the restful_authentication algorithm it will update their password with the Authlogic algorithm. When a new account is created it will use the Authlogic algorithm. This allows your user base to slowly transition and allowing them to still be able to log in.&lt;/p&gt;

&lt;p&gt;That's it. I'm not going to go into the Authlogic set up because &lt;a href="http://www.binarylogic.com/2008/11/3/tutorial-authlogic-basic-setup"&gt;I already have a tutorial on this&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Let me know what you think or if you have any questions.&lt;/p&gt;
          &lt;img src="http://feeds.binarylogic.com/~r/binarylogic/~4/463271426" height="1" width="1"/&gt;</content>  <feedburner:origLink>http://www.binarylogic.com/2008/11/23/tutorial-easily-migrate-from-restful_authentication-to-authlogic</feedburner:origLink></entry>
  <entry xml:base="http://www.binarylogic.com/">
    <author>
      <name>benjohnson</name>
    </author>
    <id>tag:www.binarylogic.com,2008-11-23:252</id>
    <published>2008-11-23T22:02:00Z</published>
    <updated>2008-11-23T17:43:24Z</updated>
    <category term="Authlogic" />
    <category term="authlogic" />
    <category term="transition passwords" />
    <category term="upgrade passwords" />
    <link href="http://feeds.binarylogic.com/~r/binarylogic/~3/463247213/tutorial-upgrade-passwords-easily-with-authlogic" rel="alternate" type="text/html" />
    <title>Tutorial: Upgrade passwords easily with Authlogic</title>
<summary type="html">&lt;p&gt;I released Authlogic 1.3.3 which has some handy options for migrating passwords to a new and improved algorithm. Without Authlogic this is somewhat of a pain in the ass, because there has to be a transition period in which your users can upgrade their passwords. You can't just upgrade the algorithm because then no one will be able to log in. Authlogic solves this problem and makes it dead simple:&lt;/p&gt;</summary><content type="html">
            &lt;p&gt;I released Authlogic 1.3.3 which has some handy options for migrating passwords to a new and improved algorithm. Without Authlogic this is somewhat of a pain in the ass, because there has to be a transition period in which your users can upgrade their passwords. You can't just upgrade the algorithm because then no one will be able to log in. Authlogic solves this problem and makes it dead simple:&lt;/p&gt;
&lt;h2&gt;Migrating to another password algorithm within Authlogic&lt;/h2&gt;

&lt;p&gt;&lt;a href="http://www.binarylogic.com/2008/11/22/storing-nuclear-launch-codes-in-your-app-enter-bcrypt-for-authlogic"&gt;I recently released BCrypt as an optional crypto provider for Authlogic&lt;/a&gt;, let's say you are using the default crypto provider Sha512 and want to start using BCrypt. No problem:&lt;/p&gt;

&lt;pre class="cobalt"&gt;
&lt;span class="Comment"&gt;&lt;span class="Punctuation"&gt;#&lt;/span&gt; app/models/user.rb&lt;/span&gt;
&lt;span class="Keyword"&gt;class&lt;/span&gt; &lt;span class="Entity"&gt;User&lt;span class="EntityInheritedClass"&gt; &lt;span class="Punctuation"&gt;&amp;lt;&lt;/span&gt; ActiveRecord::Base&lt;/span&gt;&lt;/span&gt;
  acts_as_authentic &lt;span class="Constant"&gt;&lt;span class="Punctuation"&gt;:&lt;/span&gt;transition_from_crypto_provider&lt;/span&gt; &lt;span class="Punctuation"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="Support"&gt;Authlogic&lt;/span&gt;&lt;span class="FunctionCall"&gt;&lt;span class="Punctuation"&gt;::&lt;/span&gt;&lt;span class="Entity"&gt;CryptoProviders&lt;/span&gt;&lt;/span&gt;&lt;span class="FunctionCall"&gt;&lt;span class="Punctuation"&gt;::&lt;/span&gt;&lt;span class="Entity"&gt;Sha512&lt;/span&gt;&lt;/span&gt;&lt;span class="Punctuation"&gt;,&lt;/span&gt;
    &lt;span class="Constant"&gt;&lt;span class="Punctuation"&gt;:&lt;/span&gt;cypto_provider&lt;/span&gt; &lt;span class="Punctuation"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="Support"&gt;Authlogic&lt;/span&gt;&lt;span class="FunctionCall"&gt;&lt;span class="Punctuation"&gt;::&lt;/span&gt;&lt;span class="Entity"&gt;CryptoProviders&lt;/span&gt;&lt;/span&gt;&lt;span class="FunctionCall"&gt;&lt;span class="Punctuation"&gt;::&lt;/span&gt;&lt;span class="Entity"&gt;BCrypt&lt;/span&gt;&lt;/span&gt;
&lt;span class="Keyword"&gt;end&lt;/span&gt;
&lt;/pre&gt;

&lt;p&gt;All of your users will be migrated to the new BCrypt method when they log in next or when a user creates a new account.&lt;/p&gt;

&lt;p&gt;Let's pretend a new algorithm came out called "CCrypt", and its better than BCrypt, and you want to use it. You're users are in the middle of transitioning from Sha512 to BCrypt. Oh no!&lt;/p&gt;

&lt;p&gt;Not to worry, because Authlogic can transition your users from more than one algorithm. Just pass an array to :transition_from_crypto_provider&lt;/p&gt;

&lt;pre class="cobalt"&gt;
&lt;span class="Comment"&gt;&lt;span class="Punctuation"&gt;#&lt;/span&gt; app/models/user.rb&lt;/span&gt;
&lt;span class="Keyword"&gt;class&lt;/span&gt; &lt;span class="Entity"&gt;User&lt;span class="EntityInheritedClass"&gt; &lt;span class="Punctuation"&gt;&amp;lt;&lt;/span&gt; ActiveRecord::Base&lt;/span&gt;&lt;/span&gt;
  acts_as_authentic &lt;span class="Constant"&gt;&lt;span class="Punctuation"&gt;:&lt;/span&gt;transition_from_crypto_provider&lt;/span&gt; &lt;span class="Punctuation"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="Punctuation"&gt;[&lt;/span&gt;&lt;span class="Support"&gt;Authlogic&lt;/span&gt;&lt;span class="FunctionCall"&gt;&lt;span class="Punctuation"&gt;::&lt;/span&gt;&lt;span class="Entity"&gt;CryptoProviders&lt;/span&gt;&lt;/span&gt;&lt;span class="FunctionCall"&gt;&lt;span class="Punctuation"&gt;::&lt;/span&gt;&lt;span class="Entity"&gt;Sha512&lt;/span&gt;&lt;/span&gt;&lt;span class="Punctuation"&gt;,&lt;/span&gt;
    &lt;span class="Support"&gt;Authlogic&lt;/span&gt;&lt;span class="FunctionCall"&gt;&lt;span class="Punctuation"&gt;::&lt;/span&gt;&lt;span class="Entity"&gt;CryptoProviders&lt;/span&gt;&lt;/span&gt;&lt;span class="FunctionCall"&gt;&lt;span class="Punctuation"&gt;::&lt;/span&gt;&lt;span class="Entity"&gt;BCrypt&lt;/span&gt;&lt;/span&gt;&lt;span class="Punctuation"&gt;]&lt;/span&gt;&lt;span class="Punctuation"&gt;,&lt;/span&gt; &lt;span class="Constant"&gt;&lt;span class="Punctuation"&gt;:&lt;/span&gt;cypto_provider&lt;/span&gt; &lt;span class="Punctuation"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="Variable"&gt;CCrypt&lt;/span&gt;
&lt;span class="Keyword"&gt;end&lt;/span&gt;
&lt;/pre&gt;

&lt;p&gt;That's it. You can specify as many as you want. When your users login or create a new account their passwords will be encrypted with the CCrypt algorithm.&lt;/p&gt;

&lt;h2&gt;Migrating from any other password algorithm&lt;/h2&gt;

&lt;p&gt;All that you need to do is create a crypto provider that represents how your passwords are encrypted. Believe it or not, it's dead simple. Sometimes the easiest way to explain something is by using code example, so please checkout the Authlogic::CryptoProviders module and sub classes in the documentation. All that you need to do is create a class with a class level encrypt and matches? method:&lt;/p&gt;

&lt;pre class="cobalt"&gt;
&lt;span class="Comment"&gt;&lt;span class="Punctuation"&gt;#&lt;/span&gt; lib/my_awesome_crypto_provider.rb&lt;/span&gt;
&lt;span class="Keyword"&gt;class&lt;/span&gt; &lt;span class="Entity"&gt;MyAwesomeCryptoProvider&lt;/span&gt;
  &lt;span class="Keyword"&gt;def&lt;/span&gt; &lt;span class="Entity"&gt;self.encrypt&lt;/span&gt;&lt;span class="Punctuation"&gt;(&lt;/span&gt;&lt;span class="Variable"&gt;&lt;span class="Keyword"&gt;*&lt;/span&gt;tokens&lt;/span&gt;&lt;span class="Punctuation"&gt;)&lt;/span&gt;
&lt;span class="Comment"&gt;    &lt;span class="Punctuation"&gt;#&lt;/span&gt; encrypt your password here&lt;/span&gt;
  &lt;span class="Keyword"&gt;end&lt;/span&gt;

  &lt;span class="Keyword"&gt;def&lt;/span&gt; &lt;span class="Entity"&gt;self.matches?&lt;/span&gt;&lt;span class="Punctuation"&gt;(&lt;/span&gt;&lt;span class="Variable"&gt;crypted_password&lt;span class="Punctuation"&gt;,&lt;/span&gt; &lt;span class="Keyword"&gt;*&lt;/span&gt;tokens&lt;/span&gt;&lt;span class="Punctuation"&gt;)&lt;/span&gt;
&lt;span class="Comment"&gt;    &lt;span class="Punctuation"&gt;#&lt;/span&gt; return true if the tokens match the crypted_password&lt;/span&gt;
  &lt;span class="Keyword"&gt;end&lt;/span&gt;
&lt;span class="Keyword"&gt;end&lt;/span&gt;
&lt;/pre&gt;

&lt;p&gt;Then just tell Authlogic about it:&lt;/p&gt;

&lt;pre class="cobalt"&gt;
&lt;span class="Comment"&gt;&lt;span class="Punctuation"&gt;#&lt;/span&gt; app/models/user.rb&lt;/span&gt;
&lt;span class="Keyword"&gt;class&lt;/span&gt; &lt;span class="Entity"&gt;User&lt;span class="EntityInheritedClass"&gt; &lt;span class="Punctuation"&gt;&amp;lt;&lt;/span&gt; ActiveRecord::Base&lt;/span&gt;&lt;/span&gt;
  acts_as_authentic &lt;span class="Constant"&gt;&lt;span class="Punctuation"&gt;:&lt;/span&gt;transition_from_crypto_provider&lt;/span&gt; &lt;span class="Punctuation"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="Variable"&gt;MyAwesomeCryptoProvider&lt;/span&gt;&lt;span class="Punctuation"&gt;,&lt;/span&gt;
    &lt;span class="Constant"&gt;&lt;span class="Punctuation"&gt;:&lt;/span&gt;cypto_provider&lt;/span&gt; &lt;span class="Punctuation"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="Support"&gt;Authlogic&lt;/span&gt;&lt;span class="FunctionCall"&gt;&lt;span class="Punctuation"&gt;::&lt;/span&gt;&lt;span class="Entity"&gt;CryptoProviders&lt;/span&gt;&lt;/span&gt;&lt;span class="FunctionCall"&gt;&lt;span class="Punctuation"&gt;::&lt;/span&gt;&lt;span class="Entity"&gt;BCrypt&lt;/span&gt;&lt;/span&gt;
&lt;span class="Keyword"&gt;end&lt;/span&gt;
&lt;/pre&gt;

&lt;p&gt;Transition to a new algorithm doesn't get any easier than that.&lt;/p&gt;
          &lt;img src="http://feeds.binarylogic.com/~r/binarylogic/~4/463247213" height="1" width="1"/&gt;</content>  <feedburner:origLink>http://www.binarylogic.com/2008/11/23/tutorial-upgrade-passwords-easily-with-authlogic</feedburner:origLink></entry>
  <entry xml:base="http://www.binarylogic.com/">
    <author>
      <name>benjohnson</name>
    </author>
    <id>tag:www.binarylogic.com,2008-11-22:238</id>
    <published>2008-11-22T18:43:00Z</published>
    <updated>2008-11-23T12:04:41Z</updated>
    <category term="Authlogic" />
    <category term="authlogic" />
    <category term="bcrypt" />
    <category term="security" />
    <link href="http://feeds.binarylogic.com/~r/binarylogic/~3/462156236/storing-nuclear-launch-codes-in-your-app-enter-bcrypt-for-authlogic" rel="alternate" type="text/html" />
    <title>Storing nuclear launch codes in your app? Enter BCrypt for Authlogic.</title>
<summary type="html">&lt;p&gt;Today is Saturday, which is "fun day", and there is nothing more fun that talking about encryption algorithms. So let's get started...&lt;/p&gt;

&lt;p&gt;Part of &lt;a href="http://github.com/binarylogic/authlogic"&gt;Authlogic's&lt;/a&gt; responsibility to is to keep you on the cutting edge when it comes to security. Afterall, that is part of the reason you use Authlogic, so you don''t have to deal with it. Your app can use the latest and great security techniques just by updating the Authlogic gem.&lt;/p&gt;</summary><content type="html">
            &lt;p&gt;Today is Saturday, which is "fun day", and there is nothing more fun that talking about encryption algorithms. So let's get started...&lt;/p&gt;

&lt;p&gt;Part of &lt;a href="http://github.com/binarylogic/authlogic"&gt;Authlogic's&lt;/a&gt; responsibility to is to keep you on the cutting edge when it comes to security. Afterall, that is part of the reason you use Authlogic, so you don''t have to deal with it. Your app can use the latest and great security techniques just by updating the Authlogic gem.&lt;/p&gt;
&lt;p&gt;That being said, today I released Authlogic 1.3.2. With this came a new optional crypto provider: BCrypt. According the to &lt;a href="http://bcrypt.sourceforge.net/"&gt;BCrypt website&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
    &lt;p&gt;"There are two kinds of cryptography in this world: cryptography that will stop your kid sister from reading your files, and cryptography that will stop major governments from reading your files."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;My personal opinion is that the default Sha512 encryption that Authlogic uses is &lt;em&gt;plenty&lt;/em&gt; secure, emphasis on plenty. Authlogic uses salted Sha512 with multiple stretches. Hell, the majority of apps use Sha1, because that's what restful_authentication uses, and Sha1 is much less secure. I don't want to link to these resources directly, but there are a number of resources available to perform reverse lookups on Sha1. I don't want to paint the wrong picture here by saying Sha1 is insecure. It's all in how you use it. As long as you are salting it and doing a number of stretches, which restful_authenticaton is doing, you are fine. But if you are storing extremely sensitive information in your app, such as nuclear launch codes, then you might consider something a little more secure.&lt;/p&gt;

&lt;h2&gt;What makes BCrypt more secure?&lt;/h2&gt;

&lt;p&gt;For one, BCrypt provides it's own salting, then Authlogic provides salting as well. Double salting!&lt;/p&gt;

&lt;p&gt;Secondly, when it comes to hashing algorithms, security mostly deals with the amount of time it takes to generate the hash. Take a dictionary attack on a Sha1 algorithm. A decent computer could fly through a list of every dictionary word in a relatively fast amount of time compared to BCrypt. Let me show you wish some benchmarks:&lt;/p&gt;

&lt;pre class="cobalt"&gt;
&lt;span class="Support"&gt;Benchmark&lt;/span&gt;&lt;span class="FunctionCall"&gt;&lt;span class="Punctuation"&gt;.&lt;/span&gt;&lt;span class="Entity"&gt;bm&lt;/span&gt;&lt;/span&gt;&lt;span class="Punctuation"&gt;(&lt;/span&gt;&lt;span class="Constant"&gt;18&lt;/span&gt;&lt;span class="Punctuation"&gt;)&lt;/span&gt; &lt;span class="Keyword"&gt;do &lt;/span&gt;&lt;span class="Punctuation"&gt;|&lt;/span&gt;&lt;span class="Variable"&gt;x&lt;/span&gt;&lt;span class="Punctuation"&gt;|&lt;/span&gt;
  x&lt;span class="FunctionCall"&gt;&lt;span class="Punctuation"&gt;.&lt;/span&gt;&lt;span class="Entity"&gt;report&lt;/span&gt;&lt;/span&gt;&lt;span class="Punctuation"&gt;(&lt;/span&gt;&lt;span class="String"&gt;&lt;span class="Punctuation"&gt;&amp;quot;&lt;/span&gt;BCrypt (cost = 10:&lt;span class="Punctuation"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class="Punctuation"&gt;)&lt;/span&gt; &lt;span class="Punctuation"&gt;{&lt;/span&gt; &lt;span class="Constant"&gt;100&lt;/span&gt;&lt;span class="FunctionCall"&gt;&lt;span class="Punctuation"&gt;.&lt;/span&gt;&lt;span class="Entity"&gt;times&lt;/span&gt;&lt;/span&gt; &lt;span class="Punctuation"&gt;{&lt;/span&gt; &lt;span class="Variable"&gt;BCrypt&lt;/span&gt;&lt;span class="FunctionCall"&gt;&lt;span class="Punctuation"&gt;::&lt;/span&gt;&lt;span class="Entity"&gt;Password&lt;/span&gt;&lt;/span&gt;&lt;span class="FunctionCall"&gt;&lt;span class="Punctuation"&gt;.&lt;/span&gt;&lt;span class="Entity"&gt;create&lt;/span&gt;&lt;/span&gt;&lt;span class="Punctuation"&gt;(&lt;/span&gt;&lt;span class="String"&gt;&lt;span class="Punctuation"&gt;&amp;quot;&lt;/span&gt;mypass&lt;span class="Punctuation"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class="Punctuation"&gt;,&lt;/span&gt; &lt;span class="Constant"&gt;&lt;span class="Punctuation"&gt;:&lt;/span&gt;cost&lt;/span&gt; &lt;span class="Punctuation"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="Constant"&gt;10&lt;/span&gt;&lt;span class="Punctuation"&gt;)&lt;/span&gt; &lt;span class="Punctuation"&gt;}&lt;/span&gt; &lt;span class="Punctuation"&gt;}&lt;/span&gt;
  x&lt;span class="FunctionCall"&gt;&lt;span class="Punctuation"&gt;.&lt;/span&gt;&lt;span class="Entity"&gt;report&lt;/span&gt;&lt;/span&gt;&lt;span class="Punctuation"&gt;(&lt;/span&gt;&lt;span class="String"&gt;&lt;span class="Punctuation"&gt;&amp;quot;&lt;/span&gt;BCrypt (cost = 2:&lt;span class="Punctuation"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class="Punctuation"&gt;)&lt;/span&gt; &lt;span class="Punctuation"&gt;{&lt;/span&gt; &lt;span class="Constant"&gt;100&lt;/span&gt;&lt;span class="FunctionCall"&gt;&lt;span class="Punctuation"&gt;.&lt;/span&gt;&lt;span class="Entity"&gt;times&lt;/span&gt;&lt;/span&gt; &lt;span class="Punctuation"&gt;{&lt;/span&gt; &lt;span class="Variable"&gt;BCrypt&lt;/span&gt;&lt;span class="FunctionCall"&gt;&lt;span class="Punctuation"&gt;::&lt;/span&gt;&lt;span class="Entity"&gt;Password&lt;/span&gt;&lt;/span&gt;&lt;span class="FunctionCall"&gt;&lt;span class="Punctuation"&gt;.&lt;/span&gt;&lt;span class="Entity"&gt;create&lt;/span&gt;&lt;/span&gt;&lt;span class="Punctuation"&gt;(&lt;/span&gt;&lt;span class="String"&gt;&lt;span class="Punctuation"&gt;&amp;quot;&lt;/span&gt;mypass&lt;span class="Punctuation"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class="Punctuation"&gt;,&lt;/span&gt; &lt;span class="Constant"&gt;&lt;span class="Punctuation"&gt;:&lt;/span&gt;cost&lt;/span&gt; &lt;span class="Punctuation"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="Constant"&gt;2&lt;/span&gt;&lt;span class="Punctuation"&gt;)&lt;/span&gt; &lt;span class="Punctuation"&gt;}&lt;/span&gt; &lt;span class="Punctuation"&gt;}&lt;/span&gt;
  x&lt;span class="FunctionCall"&gt;&lt;span class="Punctuation"&gt;.&lt;/span&gt;&lt;span class="Entity"&gt;report&lt;/span&gt;&lt;/span&gt;&lt;span class="Punctuation"&gt;(&lt;/span&gt;&lt;span class="String"&gt;&lt;span class="Punctuation"&gt;&amp;quot;&lt;/span&gt;Sha512:&lt;span class="Punctuation"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class="Punctuation"&gt;)&lt;/span&gt; &lt;span class="Punctuation"&gt;{&lt;/span&gt; &lt;span class="Constant"&gt;100&lt;/span&gt;&lt;span class="FunctionCall"&gt;&lt;span class="Punctuation"&gt;.&lt;/span&gt;&lt;span class="Entity"&gt;times&lt;/span&gt;&lt;/span&gt; &lt;span class="Punctuation"&gt;{&lt;/span&gt; &lt;span class="Support"&gt;Digest&lt;/span&gt;&lt;span class="FunctionCall"&gt;&lt;span class="Punctuation"&gt;::&lt;/span&gt;&lt;span class="Entity"&gt;SHA512&lt;/span&gt;&lt;/span&gt;&lt;span class="FunctionCall"&gt;&lt;span class="Punctuation"&gt;.&lt;/span&gt;&lt;span class="Entity"&gt;hexdigest&lt;/span&gt;&lt;/span&gt;&lt;span class="Punctuation"&gt;(&lt;/span&gt;&lt;span class="String"&gt;&lt;span class="Punctuation"&gt;&amp;quot;&lt;/span&gt;mypass&lt;span class="Punctuation"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class="Punctuation"&gt;)&lt;/span&gt; &lt;span class="Punctuation"&gt;}&lt;/span&gt; &lt;span class="Punctuation"&gt;}&lt;/span&gt;
  x&lt;span class="FunctionCall"&gt;&lt;span class="Punctuation"&gt;.&lt;/span&gt;&lt;span class="Entity"&gt;report&lt;/span&gt;&lt;/span&gt;&lt;span class="Punctuation"&gt;(&lt;/span&gt;&lt;span class="String"&gt;&lt;span class="Punctuation"&gt;&amp;quot;&lt;/span&gt;Sha1:&lt;span class="Punctuation"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class="Punctuation"&gt;)&lt;/span&gt; &lt;span class="Punctuation"&gt;{&lt;/span&gt; &lt;span class="Constant"&gt;100&lt;/span&gt;&lt;span class="FunctionCall"&gt;&lt;span class="Punctuation"&gt;.&lt;/span&gt;&lt;span class="Entity"&gt;times&lt;/span&gt;&lt;/span&gt; &lt;span class="Punctuation"&gt;{&lt;/span&gt; &lt;span class="Support"&gt;Digest&lt;/span&gt;&lt;span class="FunctionCall"&gt;&lt;span class="Punctuation"&gt;::&lt;/span&gt;&lt;span class="Entity"&gt;SHA1&lt;/span&gt;&lt;/span&gt;&lt;span class="FunctionCall"&gt;&lt;span class="Punctuation"&gt;.&lt;/span&gt;&lt;span class="Entity"&gt;hexdigest&lt;/span&gt;&lt;/span&gt;&lt;span class="Punctuation"&gt;(&lt;/span&gt;&lt;span class="String"&gt;&lt;span class="Punctuation"&gt;&amp;quot;&lt;/span&gt;mypass&lt;span class="Punctuation"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class="Punctuation"&gt;)&lt;/span&gt; &lt;span class="Punctuation"&gt;}&lt;/span&gt; &lt;span class="Punctuation"&gt;}&lt;/span&gt;
&lt;span class="Keyword"&gt;end&lt;/span&gt;

&lt;span class="Comment"&gt;&lt;span class="Punctuation"&gt;#&lt;/span&gt;                         user     system      total        real&lt;/span&gt;
&lt;span class="Comment"&gt;&lt;span class="Punctuation"&gt;#&lt;/span&gt; BCrypt (cost = 10): 10.780000   0.060000  10.840000 ( 11.100289)&lt;/span&gt;
&lt;span class="Comment"&gt;&lt;span class="Punctuation"&gt;#&lt;/span&gt; BCrypt (cost = 2):  0.180000   0.000000   0.180000 (  0.181914)&lt;/span&gt;
&lt;span class="Comment"&gt;&lt;span class="Punctuation"&gt;#&lt;/span&gt; Sha512:             0.000000   0.000000   0.000000 (  0.000829)&lt;/span&gt;
&lt;span class="Comment"&gt;&lt;span class="Punctuation"&gt;#&lt;/span&gt; Sha1:               0.000000   0.000000   0.000000 (  0.000395)&lt;/span&gt;
&lt;/pre&gt;

&lt;p&gt;That my friend is a huge difference. There is a trade off between security and performance. If you are willing to take the performance hit then go for it. Play with the :cost option to get that perfect balance between performance and security. By default the BCrypt library uses a cost of 10.&lt;/p&gt;

&lt;h2&gt;Easily upgrade encryption and transition your users&lt;/h2&gt;

&lt;p&gt;As I mentioned above, the cost can be adjusted. So let's say 5 years from now a cost of 10 isn't as effective as it used to be, because computers are now faster, things have advanced, etc. No problem, just bump the cost up to whatever is &lt;em&gt;now&lt;/em&gt; suitable. Your old passwords will continue to work, while the new passwords will be much stronger.&lt;/p&gt;

&lt;p&gt;Here's why using a library like Authlogic is so nice. As your users start to log in, Authlogic will handle upgrading their passwords to the new and improved cost.&lt;/p&gt;

&lt;p&gt;Now your app can move with the times and constantly stay on the cutting edge of security, and you don't have to worry about breaking all of your users passwords.&lt;/p&gt;

&lt;p&gt;This is a cool feature, but nothing to go crazy about. The average app will probably never need to upgrade their encryption algorithm. If your app is around long enough, maybe you will upgrade it once. Even then, it's probably not necessary because of the salting and stretches. Regardless, Authlogic will assist you in your upgrade if you choose to do so.&lt;/p&gt;

&lt;p&gt;Lastly, you can get this feature with any encryption algorithm, including Sha. Checkout the "Upgrading encryption methods" in the Authlogic README. It's very simple.&lt;/p&gt;

&lt;h2&gt;How do I use this?&lt;/h2&gt;

&lt;p&gt;It's simple:&lt;/p&gt;

&lt;pre class="cobalt"&gt;
$ sudo gem install bcrypt-ruby
&lt;/pre&gt;

&lt;p&gt;Starting a new app?:&lt;/p&gt;

&lt;pre class="cobalt"&gt;
&lt;span class="Comment"&gt;&lt;span class="Punctuation"&gt;#&lt;/span&gt; app/models/user.rb&lt;/span&gt;
&lt;span class="Keyword"&gt;class&lt;/span&gt; &lt;span class="Entity"&gt;User&lt;span class="EntityInheritedClass"&gt; &lt;span class="Punctuation"&gt;&amp;lt;&lt;/span&gt; ActiveRecord::Base&lt;/span&gt;&lt;/span&gt;
  acts_as_authentic &lt;span class="Constant"&gt;&lt;span class="Punctuation"&gt;:&lt;/span&gt;crypto_provider&lt;/span&gt; &lt;span class="Punctuation"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="Support"&gt;Authlogic&lt;/span&gt;&lt;span class="FunctionCall"&gt;&lt;span class="Punctuation"&gt;::&lt;/span&gt;&lt;span class="Entity"&gt;CryptoProviders&lt;/span&gt;&lt;/span&gt;&lt;span class="FunctionCall"&gt;&lt;span class="Punctuation"&gt;::&lt;/span&gt;&lt;span class="Entity"&gt;BCrypt&lt;/span&gt;&lt;/span&gt;
&lt;span class="Keyword"&gt;end&lt;/span&gt;
&lt;/pre&gt;

&lt;p&gt;Looking to switch to BCrypt?:&lt;/p&gt;

&lt;pre class="cobalt"&gt;
&lt;span class="Comment"&gt;&lt;span class="Punctuation"&gt;#&lt;/span&gt; app/models/user.rb&lt;/span&gt;
&lt;span class="Keyword"&gt;class&lt;/span&gt; &lt;span class="Entity"&gt;User&lt;span class="EntityInheritedClass"&gt; &lt;span class="Punctuation"&gt;&amp;lt;&lt;/span&gt; ActiveRecord::Base&lt;/span&gt;&lt;/span&gt;
  acts_as_authentic &lt;span class="Constant"&gt;&lt;span class="Punctuation"&gt;:&lt;/span&gt;crypto_provider&lt;/span&gt; &lt;span class="Punctuation"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="Support"&gt;Authlogic&lt;/span&gt;&lt;span class="FunctionCall"&gt;&lt;span class="Punctuation"&gt;::&lt;/span&gt;&lt;span class="Entity"&gt;CryptoProviders&lt;/span&gt;&lt;/span&gt;&lt;span class="FunctionCall"&gt;&lt;span class="Punctuation"&gt;::&lt;/span&gt;&lt;span class="Entity"&gt;BCrypt&lt;/span&gt;&lt;/span&gt;&lt;span class="Punctuation"&gt;,&lt;/span&gt;
    &lt;span class="Constant"&gt;&lt;span class="Punctuation"&gt;:&lt;/span&gt;transition_from_crypto_provider&lt;/span&gt; &lt;span class="Punctuation"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="Support"&gt;Authlogic&lt;/span&gt;&lt;span class="FunctionCall"&gt;&lt;span class="Punctuation"&gt;::&lt;/span&gt;&lt;span class="Entity"&gt;CryptoProviders&lt;/span&gt;&lt;/span&gt;&lt;span class="FunctionCall"&gt;&lt;span class="Punctuation"&gt;::&lt;/span&gt;&lt;span class="Entity"&gt;Sha512&lt;/span&gt;&lt;/span&gt;
&lt;span class="Keyword"&gt;end&lt;/span&gt;
&lt;/pre&gt;

&lt;p&gt;The :transition_from_crypto_provider is whatever crypto provider you are currently using. Check out my blog posts about transitioning to another crypto provider:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="http://www.binarylogic.com/2008/11/23/tutorial-upgrade-passwords-easily-with-authlogic"&gt;Upgrade passwords easily with Authlogic&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.binarylogic.com/2008/11/23/tutorial-easily-migrate-from-restful_authentication-to-authlogic"&gt;Easily migrating from restful_authentication to Authlogic&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;What about [insert encryption method here]?&lt;/h2&gt;

&lt;p&gt;Check out the Authlogic::CryptoProviders module and the subclasses within. You can add you own method just by creating a simple class and letting acts_as_authentic know about. Authlogic bundles some common methods as a convenience to you, there is nothing wrong with adding your own if you feel its necessary.&lt;/p&gt;

&lt;h2&gt;Why isn't this the default encryption method for Authlogic?&lt;/h2&gt;

&lt;p&gt;I have heard of people having issues with the BCrypt library on windows. I have not used windows in years, so don't take my word for it, but approach it with some caution. I decided to go with Sha512 since that is part of the ruby core and works wherever ruby can be installed.&lt;/p&gt;

&lt;p&gt;Then again, using a library like bcrypt on windows is somewhat ironic. If you are very concerned with security I doubt you will be putting your app on windows. To me using BCrypt on Windows is like putting a state of the art lock on a cardboard box.&lt;/p&gt;

&lt;h2&gt;Final thoughts&lt;/h2&gt;

&lt;p&gt;The level of security your app provides is really up to you. Unless you are writing apps for the pentagon, the default Sha512 is fine. Regardless, Authlogic shouldn't get in your way or make decisions for you, so if you feel BCrypt is necessary then go for it.&lt;/p&gt;
          &lt;img src="http://feeds.binarylogic.com/~r/binarylogic/~4/462156236" height="1" width="1"/&gt;</content>  <feedburner:origLink>http://www.binarylogic.com/2008/11/22/storing-nuclear-launch-codes-in-your-app-enter-bcrypt-for-authlogic</feedburner:origLink></entry>
  <entry xml:base="http://www.binarylogic.com/">
    <author>
      <name>benjohnson</name>
    </author>
    <id>tag:www.binarylogic.com,2008-11-21:223</id>
    <published>2008-11-21T02:12:00Z</published>
    <updated>2008-11-21T08:33:40Z</updated>
    <category term="Authlogic" />
    <category term="authentication" />
    <category term="authlogic" />
    <category term="openid" />
    <category term="rails" />
    <category term="tutorial" />
    <link href="http://feeds.binarylogic.com/~r/binarylogic/~3/460259762/tutorial-using-openid-with-authlogic" rel="alternate" type="text/html" />
    <title>Tutorial: Using OpenID with Authlogic</title>
<summary type="html">&lt;p&gt;I know some of you have been waiting for OpenID support in &lt;a href="http://github.com/binarylogic/authlogic"&gt;Authlogic&lt;/a&gt;. I came up with a pretty slick solution this (&lt;a href="http://authlogicexample.binarylogic.com"&gt;check out a live example here&lt;/a&gt;), I think you will like it. That being said, let me show you:&lt;/p&gt;

&lt;h2&gt;My dream&lt;/h2&gt;

&lt;p&gt;My dream is that the following code, in your sessions controller, would be capable of handling any type of authentication method you throw at it:&lt;/p&gt;

&lt;pre class="cobalt"&gt;
&lt;span class="Comment"&gt;&lt;span class="Punctuation"&gt;#&lt;/span&gt; app/controllers/user_sessions_controller.rb&lt;/span&gt;
&lt;span class="Keyword"&gt;def&lt;/span&gt; &lt;span class="Entity"&gt;create&lt;/span&gt;
  &lt;span class="Variable"&gt;&lt;span class="Punctuation"&gt;@&lt;/span&gt;user_session&lt;/span&gt; &lt;span class="Keyword"&gt;=&lt;/span&gt; &lt;span class="Support"&gt;UserSession&lt;/span&gt;&lt;span class="FunctionCall"&gt;&lt;span class="Punctuation"&gt;.&lt;/span&gt;&lt;span class="Entity"&gt;new&lt;/span&gt;&lt;/span&gt;&lt;span class="Punctuation"&gt;(&lt;/span&gt;params&lt;span class="Punctuation"&gt;[&lt;/span&gt;&lt;span class="Constant"&gt;&lt;span class="Punctuation"&gt;:&lt;/span&gt;user_session&lt;/span&gt;&lt;span class="Punctuation"&gt;]&lt;/span&gt;&lt;span class="Punctuation"&gt;)&lt;/span&gt;
  &lt;span class="Variable"&gt;&lt;span class="Punctuation"&gt;@&lt;/span&gt;user_session&lt;/span&gt;&lt;span class="FunctionCall"&gt;&lt;span class="Punctuation"&gt;.&lt;/span&gt;&lt;span class="Entity"&gt;save&lt;/span&gt;&lt;/span&gt; &lt;span class="Keyword"&gt;do &lt;/span&gt;&lt;span class="Punctuation"&gt;|&lt;/span&gt;&lt;span class="Variable"&gt;result&lt;/span&gt;&lt;span class="Punctuation"&gt;|&lt;/span&gt;
    &lt;span class="Keyword"&gt;if&lt;/span&gt; result
      flash&lt;span class="Punctuation"&gt;[&lt;/span&gt;&lt;span class="Constant"&gt;&lt;span class="Punctuation"&gt;:&lt;/span&gt;notice&lt;/span&gt;&lt;span class="Punctuation"&gt;]&lt;/span&gt; &lt;span class="Keyword"&gt;=&lt;/span&gt; &lt;span class="String"&gt;&lt;span class="Punctuation"&gt;&amp;quot;&lt;/span&gt;Login successful!&lt;span class="Punctuation"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
      redirect_back_or_default account_url
    &lt;span class="Keyword"&gt;else&lt;/span&gt;
      &lt;span class="SupportFunction"&gt;render&lt;/span&gt; &lt;span class="Constant"&gt;&lt;span class="Punctuation"&gt;:&lt;/span&gt;action&lt;/span&gt; &lt;span class="Punctuation"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="Constant"&gt;&lt;span class="Punctuation"&gt;:&lt;/span&gt;new&lt;/span&gt;
    &lt;span class="Keyword"&gt;end&lt;/span&gt;
  &lt;span class="Keyword"&gt;end&lt;/span&gt;
&lt;span class="Keyword"&gt;end&lt;/span&gt;
&lt;/pre&gt;

&lt;p&gt;That could handle regular authentication, OpenID authentication, Facebook connection authentication, LDAP authentication, or whatever you want, the sky is the limit. There is no OpenID cruft in your controller, and it won't get cluttered as you add more methods. Your controller stays clean and focused.&lt;/p&gt;

&lt;p&gt;Guess what? You're in luck, because the above code can do that. Here's how...&lt;/p&gt;</summary><content type="html">
            &lt;p&gt;I know some of you have been waiting for OpenID support in &lt;a href="http://github.com/binarylogic/authlogic"&gt;Authlogic&lt;/a&gt;. I came up with a pretty slick solution this (&lt;a href="http://authlogicexample.binarylogic.com"&gt;check out a live example here&lt;/a&gt;), I think you will like it. That being said, let me show you:&lt;/p&gt;

&lt;h2&gt;My dream&lt;/h2&gt;

&lt;p&gt;My dream is that the following code, in your sessions controller, would be capable of handling any type of authentication method you throw at it:&lt;/p&gt;

&lt;pre class="cobalt"&gt;
&lt;span class="Comment"&gt;&lt;span class="Punctuation"&gt;#&lt;/span&gt; app/controllers/user_sessions_controller.rb&lt;/span&gt;
&lt;span class="Keyword"&gt;def&lt;/span&gt; &lt;span class="Entity"&gt;create&lt;/span&gt;
  &lt;span class="Variable"&gt;&lt;span class="Punctuation"&gt;@&lt;/span&gt;user_session&lt;/span&gt; &lt;span class="Keyword"&gt;=&lt;/span&gt; &lt;span class="Support"&gt;UserSession&lt;/span&gt;&lt;span class="FunctionCall"&gt;&lt;span class="Punctuation"&gt;.&lt;/span&gt;&lt;span class="Entity"&gt;new&lt;/span&gt;&lt;/span&gt;&lt;span class="Punctuation"&gt;(&lt;/span&gt;params&lt;span class="Punctuation"&gt;[&lt;/span&gt;&lt;span class="Constant"&gt;&lt;span class="Punctuation"&gt;:&lt;/span&gt;user_session&lt;/span&gt;&lt;span class="Punctuation"&gt;]&lt;/span&gt;&lt;span class="Punctuation"&gt;)&lt;/span&gt;
  &lt;span class="Variable"&gt;&lt;span class="Punctuation"&gt;@&lt;/span&gt;user_session&lt;/span&gt;&lt;span class="FunctionCall"&gt;&lt;span class="Punctuation"&gt;.&lt;/span&gt;&lt;span class="Entity"&gt;save&lt;/span&gt;&lt;/span&gt; &lt;span class="Keyword"&gt;do &lt;/span&gt;&lt;span class="Punctuation"&gt;|&lt;/span&gt;&lt;span class="Variable"&gt;result&lt;/span&gt;&lt;span class="Punctuation"&gt;|&lt;/span&gt;
    &lt;span class="Keyword"&gt;if&lt;/span&gt; result
      flash&lt;span class="Punctuation"&gt;[&lt;/span&gt;&lt;span class="Constant"&gt;&lt;span class="Punctuation"&gt;:&lt;/span&gt;notice&lt;/span&gt;&lt;span class="Punctuation"&gt;]&lt;/span&gt; &lt;span class="Keyword"&gt;=&lt;/span&gt; &lt;span class="String"&gt;&lt;span class="Punctuation"&gt;&amp;quot;&lt;/span&gt;Login successful!&lt;span class="Punctuation"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
      redirect_back_or_default account_url
    &lt;span class="Keyword"&gt;else&lt;/span&gt;
      &lt;span class="SupportFunction"&gt;render&lt;/span&gt; &lt;span class="Constant"&gt;&lt;span class="Punctuation"&gt;:&lt;/span&gt;action&lt;/span&gt; &lt;span class="Punctuation"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="Constant"&gt;&lt;span class="Punctuation"&gt;:&lt;/span&gt;new&lt;/span&gt;
    &lt;span class="Keyword"&gt;end&lt;/span&gt;
  &lt;span class="Keyword"&gt;end&lt;/span&gt;
&lt;span class="Keyword"&gt;end&lt;/span&gt;
&lt;/pre&gt;

&lt;p&gt;That could handle regular authentication, OpenID authentication, Facebook connection authentication, LDAP authentication, or whatever you want, the sky is the limit. There is no OpenID cruft in your controller, and it won't get cluttered as you add more methods. Your controller stays clean and focused.&lt;/p&gt;

&lt;p&gt;Guess what? You're in luck, because the above code can do that. Here's how...&lt;/p&gt;
&lt;h2&gt;My approach&lt;/h2&gt;

&lt;p&gt;As I'm sure you know, OpenID is not the only single sign on method. &lt;a href="http://msdn.microsoft.com/en-us/library/ms984587.aspx"&gt;Microsoft has their own&lt;/a&gt;, &lt;a href="http://wiki.developers.facebook.com/index.php/Trying_Out_Facebook_Connect"&gt;Facebook has their own&lt;/a&gt;, corporations have their own private method, a lot of universities use LDAP, etc. So it would be silly of me to build specific OpenID support directly into Authlogic. I want to keep Authlogic focused on the core authentication methods. I want to keep it clean, small, and focused. By writing an OpenID solution specific for Authlogic I am just recreating the wheel, bloating Authlogic, and adding more responsibility to the library. All of the current OpenID solutions for ruby are very good, there is very little room for improvement. Why not use them?&lt;/p&gt;

&lt;p&gt;So I took a different approach. Instead of writing OpenID specific code, I am giving you all of the tools you need to implement any type of single sign on method easily and quickly. Now when you get that client that has to have the Facebook single sign on method, it will fit into your application nicely, and you don't have to wait for Authlogic to add support for it.&lt;/p&gt;

&lt;p&gt;Let me walk you through implementing OpenID, and you can judge for yourself how easy this is:&lt;/p&gt;

&lt;h2&gt;What I'm assuming you know&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;What Authlogic is and how to set it up&lt;/li&gt;
&lt;li&gt;What the Authlogic example app is. If you don't know what this is, it's an app I have been building with the tutorials I have been writing. What tutorials?
&lt;ol&gt;
&lt;li&gt;&lt;a href="http://www.binarylogic.com/2008/11/3/tutorial-authlogic-basic-setup"&gt;Authlogic basic setup&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.binarylogic.com/2008/11/16/tutorial-reset-passwords-with-authlogic"&gt;Resetting password with Authlogic&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;&lt;/li&gt;
&lt;li&gt;What OpenID is and how it works&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;Some helpful links for reference&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="http://authlogic_example.binarylogic.com/"&gt;Live example of the this tutorial&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://github.com/binarylogic/authlogic_example/tree/with-openid"&gt;Source code of this tutorial&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.binarylogic.com/2008/11/3/tutorial-authlogic-basic-setup"&gt;Tutorial: Authlogic basic setup&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.binarylogic.com/2008/11/3/tutorial-authlogic-basic-setup"&gt;Tutorial: Reset password with Authlogic the RESTful way&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://github.com/binarylogic/authlogic"&gt;Authlogic repository&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://authlogic.rubyforge.org/"&gt;Authlogic documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://github.com/rails/open_id_authentication"&gt;open_id_authentication rails plugin&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;1. Install the ruby-openid gem and open_id_authentication plugin&lt;/h2&gt;

&lt;p&gt;Install the openid gem:&lt;/p&gt;

&lt;pre class="cobalt"&gt;
$ gem install ruby-openid
&lt;/pre&gt;

&lt;p&gt;Now install the &lt;a href="http://github.com/rails/open_id_authentication"&gt;open_id_authentication rails plugin&lt;/a&gt;:&lt;/p&gt;

&lt;pre class="cobalt"&gt;
$ script/plugin install git://github.com/rails/open_id_authentication.git
&lt;/pre&gt;

&lt;h2&gt;2. Add the proper database fields&lt;/h2&gt;

&lt;pre class="cobalt"&gt;
$ script/generate migration add_users_openid_field
&lt;/pre&gt;

&lt;p&gt;Your migration should look like:&lt;/p&gt;

&lt;pre class="cobalt"&gt;
&lt;span class="Keyword"&gt;class&lt;/span&gt; &lt;span class="Entity"&gt;AddUsersOpenidField&lt;span class="EntityInheritedClass"&gt; &lt;span class="Punctuation"&gt;&amp;lt;&lt;/span&gt; ActiveRecord::Migration&lt;/span&gt;&lt;/span&gt;
  &lt;span class="Keyword"&gt;def&lt;/span&gt; &lt;span class="Entity"&gt;self.up&lt;/span&gt;
    add_column &lt;span class="Constant"&gt;&lt;span class="Punctuation"&gt;:&lt;/span&gt;users&lt;/span&gt;&lt;span class="Punctuation"&gt;,&lt;/span&gt; &lt;span class="Constant"&gt;&lt;span class="Punctuation"&gt;:&lt;/span&gt;openid_identifier&lt;/span&gt;&lt;span class="Punctuation"&gt;,&lt;/span&gt; &lt;span class="Constant"&gt;&lt;span class="Punctuation"&gt;:&lt;/span&gt;string&lt;/span&gt;
    add_index &lt;span class="Constant"&gt;&lt;span class="Punctuation"&gt;:&lt;/span&gt;users&lt;/span&gt;&lt;span class="Punctuation"&gt;,&lt;/span&gt; &lt;span class="Constant"&gt;&lt;span class="Punctuation"&gt;:&lt;/span&gt;openid_identifier&lt;/span&gt;

    change_column &lt;span class="Constant"&gt;&lt;span class="Punctuation"&gt;:&lt;/span&gt;users&lt;/span&gt;&lt;span class="Punctuation"&gt;,&lt;/span&gt; &lt;span class="Constant"&gt;&lt;span class="Punctuation"&gt;:&lt;/span&gt;login&lt;/span&gt;&lt;span class="Punctuation"&gt;,&lt;/span&gt; &lt;span class="Constant"&gt;&lt;span class="Punctuation"&gt;:&lt;/span&gt;string&lt;/span&gt;&lt;span class="Punctuation"&gt;,&lt;/span&gt; &lt;span class="Constant"&gt;&lt;span class="Punctuation"&gt;:&lt;/span&gt;default&lt;/span&gt; &lt;span class="Punctuation"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="Constant"&gt;nil&lt;/span&gt;&lt;span class="Punctuation"&gt;,&lt;/span&gt; &lt;span class="Constant"&gt;&lt;span class="Punctuation"&gt;:&lt;/span&gt;null&lt;/span&gt; &lt;span class="Punctuation"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="Constant"&gt;true&lt;/span&gt;
    change_column &lt;span class="Constant"&gt;&lt;span class="Punctuation"&gt;:&lt;/span&gt;users&lt;/span&gt;&lt;span class="Punctuation"&gt;,&lt;/span&gt; &lt;span class="Constant"&gt;&lt;span class="Punctuation"&gt;:&lt;/span&gt;crypted_password&lt;/span&gt;&lt;span class="Punctuation"&gt;,&lt;/span&gt; &lt;span class="Constant"&gt;&lt;span class="Punctuation"&gt;:&lt;/span&gt;string&lt;/span&gt;&lt;span class="Punctuation"&gt;,&lt;/span&gt; &lt;span class="Constant"&gt;&lt;span class="Punctuation"&gt;:&lt;/span&gt;default&lt;/span&gt; &lt;span class="Punctuation"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="Constant"&gt;nil&lt;/span&gt;&lt;span class="Punctuation"&gt;,&lt;/span&gt; &lt;span class="Constant"&gt;&lt;span class="Punctuation"&gt;:&lt;/span&gt;null&lt;/span&gt; &lt;span class="Punctuation"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="Constant"&gt;true&lt;/span&gt;
    change_column &lt;span class="Constant"&gt;&lt;span class="Punctuation"&gt;:&lt;/span&gt;users&lt;/span&gt;&lt;span class="Punctuation"&gt;,&lt;/span&gt; &lt;span class="Constant"&gt;&lt;span class="Punctuation"&gt;:&lt;/span&gt;password_salt&lt;/span&gt;&lt;span class="Punctuation"&gt;,&lt;/span&gt; &lt;span class="Constant"&gt;&lt;span class="Punctuation"&gt;:&lt;/span&gt;string&lt;/span&gt;&lt;span class="Punctuation"&gt;,&lt;/span&gt; &lt;span class="Constant"&gt;&lt;span class="Punctuation"&gt;:&lt;/span&gt;default&lt;/span&gt; &lt;span class="Punctuation"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="Constant"&gt;nil&lt;/span&gt;&lt;span class="Punctuation"&gt;,&lt;/span&gt; &lt;span class="Constant"&gt;&lt;span class="Punctuation"&gt;:&lt;/span&gt;null&lt;/span&gt; &lt;span class="Punctuation"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="Constant"&gt;true&lt;/span&gt;
  &lt;span class="Keyword"&gt;end&lt;/span&gt;

  &lt;span class="Keyword"&gt;def&lt;/span&gt; &lt;span class="Entity"&gt;self.down&lt;/span&gt;
    remove_column &lt;span class="Constant"&gt;&lt;span class="Punctuation"&gt;:&lt;/span&gt;users&lt;/span&gt;&lt;span class="Punctuation"&gt;,&lt;/span&gt; &lt;span class="Constant"&gt;&lt;span class="Punctuation"&gt;:&lt;/span&gt;openid_identifier&lt;/span&gt;
    &lt;span class="Punctuation"&gt;[&lt;/span&gt;&lt;span class="Constant"&gt;&lt;span class="Punctuation"&gt;:&lt;/span&gt;login&lt;/span&gt;&lt;span class="Punctuation"&gt;,&lt;/span&gt; &lt;span class="Constant"&gt;&lt;span class="Punctuation"&gt;:&lt;/span&gt;crypted_password&lt;/span&gt;&lt;span class="Punctuation"&gt;,&lt;/span&gt; &lt;span class="Constant"&gt;&lt;span class="Punctuation"&gt;:&lt;/span&gt;password_salt&lt;/span&gt;&lt;span class="Punctuation"&gt;]&lt;/span&gt;&lt;span class="FunctionCall"&gt;&lt;span class="Punctuation"&gt;.&lt;/span&gt;&lt;span class="Entity"&gt;each&lt;/span&gt;&lt;/span&gt; &lt;span class="Keyword"&gt;do &lt;/span&gt;&lt;span class="Punctuation"&gt;|&lt;/span&gt;&lt;span class="Variable"&gt;field&lt;/span&gt;&lt;span class="Punctuation"&gt;|&lt;/span&gt;
      &lt;span class="Support"&gt;User&lt;/span&gt;&lt;span class="FunctionCall"&gt;&lt;span class="Punctuation"&gt;.&lt;/span&gt;&lt;span class="Entity"&gt;all&lt;/span&gt;&lt;/span&gt;&lt;span class="Punctuation"&gt;(&lt;/span&gt;&lt;span class="Constant"&gt;&lt;span class="Punctuation"&gt;:&lt;/span&gt;conditions&lt;/span&gt; &lt;span class="Punctuation"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="String"&gt;&lt;span class="Punctuation"&gt;&amp;quot;&lt;/span&gt;&lt;span class="StringEmbeddedSource"&gt;&lt;span class="Punctuation"&gt;#{&lt;/span&gt;field&lt;span class="Punctuation"&gt;}&lt;/span&gt;&lt;/span&gt; is NULL&lt;span class="Punctuation"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class="Punctuation"&gt;)&lt;/span&gt;&lt;span class="FunctionCall"&gt;&lt;span class="Punctuation"&gt;.&lt;/span&gt;&lt;span class="Entity"&gt;each&lt;/span&gt;&lt;/span&gt; &lt;span class="Punctuation"&gt;{&lt;/span&gt; &lt;span class="Punctuation"&gt;|&lt;/span&gt;&lt;span class="Variable"&gt;user&lt;/span&gt;&lt;span class="Punctuation"&gt;|&lt;/span&gt; user&lt;span class="FunctionCall"&gt;&lt;span class="Punctuation"&gt;.&lt;/span&gt;&lt;span class="Entity"&gt;update_attribute&lt;/span&gt;&lt;/span&gt;&lt;span class="Punctuation"&gt;(&lt;/span&gt;field&lt;span class="Punctuation"&gt;,&lt;/span&gt; &lt;span class="String"&gt;&lt;span class="Punctuation"&gt;&amp;quot;&lt;/span&gt;&lt;span class="Punctuation"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class="Punctuation"&gt;)&lt;/span&gt; &lt;span class="Keyword"&gt;if&lt;/span&gt; user&lt;span class="FunctionCall"&gt;&lt;span class="Punctuation"&gt;.&lt;/span&gt;&lt;span class="Entity"&gt;send&lt;/span&gt;&lt;/span&gt;&lt;span class="Punctuation"&gt;(&lt;/span&gt;field&lt;span class="Punctuation"&gt;)&lt;/span&gt;&lt;span class="FunctionCall"&gt;&lt;span class="Punctuation"&gt;.&lt;/span&gt;&lt;span class="Entity"&gt;nil?&lt;/span&gt;&lt;/span&gt; &lt;span class="Punctuation"&gt;}&lt;/span&gt;
      change_column &lt;span class="Constant"&gt;&lt;span class="Punctuation"&gt;:&lt;/span&gt;users&lt;/span&gt;&lt;span class="Punctuation"&gt;,&lt;/span&gt; field&lt;span class="Punctuation"&gt;,&lt;/span&gt; &lt;span class="Constant"&gt;&lt;span class="Punctuation"&gt;:&lt;/span&gt;string&lt;/span&gt;&lt;span class="Punctuation"&gt;,&lt;/span&gt; &lt;span class="Constant"&gt;&lt;span class="Punctuation"&gt;:&lt;/span&gt;default&lt;/span&gt; &lt;span class="Punctuation"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="String"&gt;&lt;span class="Punctuation"&gt;&amp;quot;&lt;/span&gt;&lt;span class="Punctuation"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class="Punctuation"&gt;,&lt;/span&gt; &lt;span class="Constant"&gt;&lt;span class="Punctuation"&gt;:&lt;/span&gt;null&lt;/span&gt; &lt;span class="Punctuation"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="Constant"&gt;false&lt;/span&gt;
    &lt;span class="Keyword"&gt;end&lt;/span&gt;
  &lt;span class="Keyword"&gt;end&lt;/span&gt;
&lt;span class="Keyword"&gt;end&lt;/span&gt;
&lt;/pre&gt;

&lt;p&gt;We are changing the login, crypted_password, and password_salt field to be optional now that your users have the OpenID option. The down method is setting all nil fields to "" otherwise you will get a database error.&lt;/p&gt;

&lt;p&gt;By default the open_id_authentication plugin uses database store to store all of the OpenID associations and nonces. It comes with a handy generator for those migrations:&lt;/p&gt;

&lt;pre class="cobalt"&gt;
$ script/generate open_id_authentication_tables create_openid_tables
&lt;/pre&gt;

&lt;p&gt;Now let's migrate everything:&lt;/p&gt;

&lt;pre class="cobalt"&gt;
$ rake db:migrate
&lt;/pre&gt;

&lt;h2&gt;3. Update User validation&lt;/h2&gt;

&lt;p&gt;Now let's make some changes to our User model to accommodate for this:&lt;/p&gt;

&lt;pre class="cobalt"&gt;
&lt;span class="Comment"&gt;&lt;span class="Punctuation"&gt;#&lt;/span&gt; app/models/user.rb&lt;/span&gt;
acts_as_authentic &lt;span class="Constant"&gt;&lt;span class="Punctuation"&gt;:&lt;/span&gt;login_field_validation_options&lt;/span&gt; &lt;span class="Punctuation"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="Punctuation"&gt;{&lt;/span&gt;&lt;span class="Constant"&gt;&lt;span class="Punctuation"&gt;:&lt;/span&gt;if&lt;/span&gt; &lt;span class="Punctuation"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="Constant"&gt;&lt;span class="Punctuation"&gt;:&lt;/span&gt;openid_identifier_blank?&lt;/span&gt;&lt;span class="Punctuation"&gt;}&lt;/span&gt;&lt;span class="Punctuation"&gt;,&lt;/span&gt;
  &lt;span class="Constant"&gt;&lt;span class="Punctuation"&gt;:&lt;/span&gt;password_field_validation_options&lt;/span&gt; &lt;span class="Punctuation"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="Punctuation"&gt;{&lt;/span&gt;&lt;span class="Constant"&gt;&lt;span class="Punctuation"&gt;:&lt;/span&gt;if&lt;/span&gt; &lt;span class="Punctuation"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="Constant"&gt;&lt;span class="Punctuation"&gt;:&lt;/span&gt;openid_identifier_blank?&lt;/span&gt;&lt;span class="Punctuation"&gt;}&lt;/span&gt;

&lt;span class="SupportFunction"&gt;validate&lt;/span&gt; &lt;span class="Constant"&gt;&lt;span class="Punctuation"&gt;:&lt;/span&gt;normalize_openid_identifier&lt;/span&gt;
&lt;span class="SupportFunction"&gt;validates_uniqueness_of&lt;/span&gt; &lt;span class="Constant"&gt;&lt;span class="Punctuation"&gt;:&lt;/span&gt;openid_identifier&lt;/span&gt;&lt;span class="Punctuation"&gt;,&lt;/span&gt; &lt;span class="Constant"&gt;&lt;span class="Punctuation"&gt;:&lt;/span&gt;allow_blank&lt;/span&gt; &lt;span class="Punctuation"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="Constant"&gt;true&lt;/span&gt;

&lt;span class="Comment"&gt;&lt;span class="Punctuation"&gt;#&lt;/span&gt; For acts_as_authentic configuration&lt;/span&gt;
&lt;span class="Keyword"&gt;def&lt;/span&gt; &lt;span class="Entity"&gt;openid_identifier_blank?&lt;/span&gt;
  openid_identifier&lt;span class="FunctionCall"&gt;&lt;span class="Punctuation"&gt;.&lt;/span&gt;&lt;span class="Entity"&gt;blank?&lt;/span&gt;&lt;/span&gt;
&lt;span class="Keyword"&gt;end&lt;/span&gt;

&lt;span class="Keyword"&gt;private&lt;/span&gt;
  &lt;span class="Keyword"&gt;def&lt;/span&gt; &lt;span class="Entity"&gt;normalize_openid_identifier&lt;/span&gt;
    &lt;span class="Keyword"&gt;begin&lt;/span&gt;
      &lt;span class="LangVariable"&gt;self&lt;/span&gt;&lt;span class="FunctionCall"&gt;&lt;span class="Punctuation"&gt;.&lt;/span&gt;&lt;span class="Entity"&gt;openid_identifier&lt;/span&gt;&lt;/span&gt; &lt;span class="Keyword"&gt;=&lt;/span&gt; &lt;span class="Support"&gt;OpenIdAuthentication&lt;/span&gt;&lt;span class="FunctionCall"&gt;&lt;span class="Punctuation"&gt;.&lt;/span&gt;&lt;span class="Entity"&gt;normalize_url&lt;/span&gt;&lt;/span&gt;&lt;span class="Punctuation"&gt;(&lt;/span&gt;openid_identifier&lt;span class="Punctuation"&gt;)&lt;/span&gt; &lt;span class="Keyword"&gt;if&lt;/span&gt; &lt;span class="Keyword"&gt;!&lt;/span&gt;openid_identifier&lt;span class="FunctionCall"&gt;&lt;span class="Punctuation"&gt;.&lt;/span&gt;&lt;span class="Entity"&gt;blank?&lt;/span&gt;&lt;/span&gt;
    &lt;span class="Keyword"&gt;rescue&lt;/span&gt; &lt;span class="Support"&gt;OpenIdAuthentication&lt;/span&gt;&lt;span class="FunctionCall"&gt;&lt;span class="Punctuation"&gt;::&lt;/span&gt;&lt;span class="Entity"&gt;InvalidOpenId&lt;/span&gt;&lt;/span&gt; &lt;span class="Punctuation"&gt;=&amp;gt;&lt;/span&gt; e
      errors&lt;span class="FunctionCall"&gt;&lt;span class="Punctuation"&gt;.&lt;/span&gt;&lt;span class="Entity"&gt;add&lt;/span&gt;&lt;/span&gt;&lt;span class="Punctuation"&gt;(&lt;/span&gt;&lt;span class="Constant"&gt;&lt;span class="Punctuation"&gt;:&lt;/span&gt;openid_identifier&lt;/span&gt;&lt;span class="Punctuation"&gt;,&lt;/span&gt; e&lt;span class="FunctionCall"&gt;&lt;span class="Punctuation"&gt;.&lt;/span&gt;&lt;span class="Entity"&gt;message&lt;/span&gt;&lt;/span&gt;&lt;span class="Punctuation"&gt;)&lt;/span&gt;
    &lt;span class="Keyword"&gt;end&lt;/span&gt;
  &lt;span class="Keyword"&gt;end&lt;/span&gt;
&lt;/pre&gt;

&lt;p&gt;The above code just tells Authlogic to allow blank values for the login and password, it makes sure a login is supplied if no openid is given, it makes sure the openid is unique, and it also normalizes the openid that the user passes. Simple enough.&lt;/p&gt;

&lt;h2&gt;4. Update your UserSessionsController&lt;/h2&gt;

&lt;p&gt;Here is my favorite part, and why Authlogic is so nice for integrating with methods like this. Change your create method to look like this:&lt;/p&gt;

&lt;pre class="cobalt"&gt;
&lt;span class="Comment"&gt;&lt;span class="Punctuation"&gt;#&lt;/span&gt; app/controllers/user_sessions_controller.rb&lt;/span&gt;
&lt;span class="Keyword"&gt;def&lt;/span&gt; &lt;span class="Entity"&gt;create&lt;/span&gt;
  &lt;span class="Variable"&gt;&lt;span class="Punctuation"&gt;@&lt;/span&gt;user_session&lt;/span&gt; &lt;span class="Keyword"&gt;=&lt;/span&gt; &lt;span class="Support"&gt;UserSession&lt;/span&gt;&lt;span class="FunctionCall"&gt;&lt;span class="Punctuation"&gt;.&lt;/span&gt;&lt;span class="Entity"&gt;new&lt;/span&gt;&lt;/span&gt;&lt;span class="Punctuation"&gt;(&lt;/span&gt;params&lt;span class="Punctuation"&gt;[&lt;/span&gt;&lt;span class="Constant"&gt;&lt;span class="Punctuation"&gt;:&lt;/span&gt;user_session&lt;/span&gt;&lt;span class="Punctuation"&gt;]&lt;/span&gt;&lt;span class="Punctuation"&gt;)&lt;/span&gt;
  &lt;span class="Variable"&gt;&lt;span class="Punctuation"&gt;@&lt;/span&gt;user_session&lt;/span&gt;&lt;span class="FunctionCall"&gt;&lt;span class="Punctuation"&gt;.&lt;/span&gt;&lt;span class="Entity"&gt;save&lt;/span&gt;&lt;/span&gt; &lt;span class="Keyword"&gt;do &lt;/span&gt;&lt;span class="Punctuation"&gt;|&lt;/span&gt;&lt;span class="Variable"&gt;result&lt;/span&gt;&lt;span class="Punctuation"&gt;|&lt;/span&gt;
    &lt;span class="Keyword"&gt;if&lt;/span&gt; result
      flash&lt;span class="Punctuation"&gt;[&lt;/span&gt;&lt;span class="Constant"&gt;&lt;span class="Punctuation"&gt;:&lt;/span&gt;notice&lt;/span&gt;&lt;span class="Punctuation"&gt;]&lt;/span&gt; &lt;span class="Keyword"&gt;=&lt;/span&gt; &lt;span class="String"&gt;&lt;span class="Punctuation"&gt;&amp;quot;&lt;/span&gt;Login successful!&lt;span class="Punctuation"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
      redirect_back_or_default account_url
    &lt;span class="Keyword"&gt;else&lt;/span&gt;
      &lt;span class="SupportFunction"&gt;render&lt;/span&gt; &lt;span class="Constant"&gt;&lt;span class="Punctuation"&gt;:&lt;/span&gt;action&lt;/span&gt; &lt;span class="Punctuation"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="Constant"&gt;&lt;span class="Punctuation"&gt;:&lt;/span&gt;new&lt;/span&gt;
    &lt;span class="Keyword"&gt;end&lt;/span&gt;
  &lt;span class="Keyword"&gt;end&lt;/span&gt;
&lt;span class="Keyword"&gt;end&lt;/span&gt;
&lt;/pre&gt;

&lt;p&gt;Notice the small 1 line change? We are now passing a block to save. I think that's pretty slick because that block will do everything for you. It will redirect the user to their proper OpenID provider, thus keeping your UserSessionsController clean and focused and not full of OpenID clutter.&lt;/p&gt;

&lt;p&gt;But wait, Authlogic is not magical, we need to tell our UserSession how to integrate in with the open_id_authentication plugin. No problem...&lt;/p&gt;

&lt;h2&gt;5. Update your UserSession&lt;/h2&gt;

&lt;p&gt;Let's just override the save method and implement our OpenID specific code:&lt;/p&gt;

&lt;pre class="cobalt"&gt;
&lt;span class="Comment"&gt;&lt;span class="Punctuation"&gt;#&lt;/span&gt; app/models/user_session.rb&lt;/span&gt;
&lt;span class="Keyword"&gt;class&lt;/span&gt; &lt;span class="Entity"&gt;UserSession&lt;span class="EntityInheritedClass"&gt; &lt;span class="Punctuation"&gt;&amp;lt;&lt;/span&gt; Authlogic::Session::Base&lt;/span&gt;&lt;/span&gt;
  &lt;span class="Keyword"&gt;attr_accessor&lt;/span&gt; &lt;span class="Constant"&gt;&lt;span class="Punctuation"&gt;:&lt;/span&gt;openid_identifier&lt;/span&gt;

  &lt;span class="Keyword"&gt;def&lt;/span&gt; &lt;span class="Entity"&gt;authenticating_with_openid?&lt;/span&gt;
    &lt;span class="Keyword"&gt;!&lt;/span&gt;openid_identifier&lt;span class="FunctionCall"&gt;&lt;span class="Punctuation"&gt;.&lt;/span&gt;&lt;span class="Entity"&gt;blank?&lt;/span&gt;&lt;/span&gt; &lt;span class="Keyword"&gt;||&lt;/span&gt; controller&lt;span class="FunctionCall"&gt;&lt;span class="Punctuation"&gt;.&lt;/span&gt;&lt;span class="Entity"&gt;params&lt;/span&gt;&lt;/span&gt;&lt;span class="Punctuation"&gt;[&lt;/span&gt;&lt;span class="Constant"&gt;&lt;span class="Punctuation"&gt;:&lt;/span&gt;open_id_complete&lt;/span&gt;&lt;span class="Punctuation"&gt;]&lt;/span&gt;
  &lt;span class="Keyword"&gt;end&lt;/span&gt;

  &lt;span class="Keyword"&gt;def&lt;/span&gt; &lt;span class="Entity"&gt;save&lt;/span&gt;&lt;span class="Punctuation"&gt;(&lt;/span&gt;&lt;span class="Variable"&gt;&lt;span class="Keyword"&gt;&amp;amp;&lt;/span&gt;block&lt;/span&gt;&lt;span class="Punctuation"&gt;)&lt;/span&gt;
    &lt;span class="Keyword"&gt;if&lt;/span&gt; authenticating_with_openid?
      &lt;span class="Keyword"&gt;raise&lt;/span&gt; &lt;span class="Support"&gt;ArgumentError&lt;/span&gt;&lt;span class="FunctionCall"&gt;&lt;span class="Punctuation"&gt;.&lt;/span&gt;&lt;span class="Entity"&gt;new&lt;/span&gt;&lt;/span&gt;&lt;span class="Punctuation"&gt;(&lt;/span&gt;&lt;span class="String"&gt;&lt;span class="Punctuation"&gt;&amp;quot;&lt;/span&gt;You must supply a block to authenticate with OpenID&lt;span class="Punctuation"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class="Punctuation"&gt;)&lt;/span&gt; &lt;span class="Keyword"&gt;unless&lt;/span&gt; &lt;span class="Keyword"&gt;block_given?&lt;/span&gt;

      controller&lt;span class="FunctionCall"&gt;&lt;span class="Punctuation"&gt;.&lt;/span&gt;&lt;span class="Entity"&gt;send&lt;/span&gt;&lt;/span&gt;&lt;span class="Punctuation"&gt;(&lt;/span&gt;&lt;span class="Constant"&gt;&lt;span class="Punctuation"&gt;:&lt;/span&gt;authenticate_with_open_id&lt;/span&gt;&lt;span class="Punctuation"&gt;,&lt;/span&gt; openid_identifier&lt;span class="Punctuation"&gt;)&lt;/span&gt; &lt;span class="Keyword"&gt;do &lt;/span&gt;&lt;span class="Punctuation"&gt;|&lt;/span&gt;&lt;span class="Variable"&gt;result&lt;/span&gt;&lt;span class="Punctuation"&gt;,&lt;/span&gt; &lt;span class="Variable"&gt;openid_identifier&lt;/span&gt;&lt;span class="Punctuation"&gt;|&lt;/span&gt;
        &lt;span class="Keyword"&gt;if&lt;/span&gt; &lt;span class="Keyword"&gt;!&lt;/span&gt;result&lt;span class="FunctionCall"&gt;&lt;span class="Punctuation"&gt;.&lt;/span&gt;&lt;span class="Entity"&gt;successful?&lt;/span&gt;&lt;/span&gt;
          errors&lt;span class="FunctionCall"&gt;&lt;span class="Punctuation"&gt;.&lt;/span&gt;&lt;span class="Entity"&gt;add_to_base&lt;/span&gt;&lt;/span&gt;&lt;span class="Punctuation"&gt;(&lt;/span&gt;result&lt;span class="FunctionCall"&gt;&lt;span class="Punctuation"&gt;.&lt;/span&gt;&lt;span class="Entity"&gt;message&lt;/span&gt;&lt;/span&gt;&lt;span class="Punctuation"&gt;)&lt;/span&gt;
          &lt;span class="Keyword"&gt;yield&lt;/span&gt; &lt;span class="Constant"&gt;false&lt;/span&gt;
          &lt;span class="Keyword"&gt;return&lt;/span&gt;
        &lt;span class="Keyword"&gt;end&lt;/span&gt;

        record &lt;span class="Keyword"&gt;=&lt;/span&gt; klass&lt;span class="FunctionCall"&gt;&lt;span class="Punctuation"&gt;.&lt;/span&gt;&lt;span class="Entity"&gt;find_by_openid_identifier&lt;/span&gt;&lt;/span&gt;&lt;span class="Punctuation"&gt;(&lt;/span&gt;openid_identifier&lt;span class="Punctuation"&gt;)&lt;/span&gt;

        &lt;span class="Keyword"&gt;if&lt;/span&gt; &lt;span class="Keyword"&gt;!&lt;/span&gt;record
          errors&lt;span class="FunctionCall"&gt;&lt;span class="Punctuation"&gt;.&lt;/span&gt;&lt;span class="Entity"&gt;add&lt;/span&gt;&lt;/span&gt;&lt;span class="Punctuation"&gt;(&lt;/span&gt;&lt;span class="Constant"&gt;&lt;span class="Punctuation"&gt;:&lt;/span&gt;openid_identifier&lt;/span&gt;&lt;span class="Punctuation"&gt;,&lt;/span&gt; &lt;span class="String"&gt;&lt;span class="Punctuation"&gt;&amp;quot;&lt;/span&gt;did not match any users in our database, have you set up your account to use OpenID?&lt;span class="Punctuation"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class="Punctuation"&gt;)&lt;/span&gt;
          &lt;span class="Keyword"&gt;yield&lt;/span&gt; &lt;span class="Constant"&gt;false&lt;/span&gt;
          &lt;span class="Keyword"&gt;return&lt;/span&gt;
        &lt;span class="Keyword"&gt;end&lt;/span&gt;

        &lt;span class="LangVariable"&gt;self&lt;/span&gt;&lt;span class="FunctionCall"&gt;&lt;span class="Punctuation"&gt;.&lt;/span&gt;&lt;span class="Entity"&gt;unauthorized_record&lt;/span&gt;&lt;/span&gt; &lt;span class="Keyword"&gt;=&lt;/span&gt; record
        &lt;span class="Keyword"&gt;super&lt;/span&gt;
      &lt;span class="Keyword"&gt;end&lt;/span&gt;
    &lt;span class="Keyword"&gt;else&lt;/span&gt;
      &lt;span class="Keyword"&gt;super&lt;/span&gt;
    &lt;span class="Keyword"&gt;end&lt;/span&gt;
  &lt;span class="Keyword"&gt;end&lt;/span&gt;
&lt;span class="Keyword"&gt;end&lt;/span&gt;
&lt;/pre&gt;

&lt;p&gt;Let me explain what is going on here:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The authenticating_with_openid? method is just letting us know if they are trying to login with OpenID or not, we use this in the save method.&lt;/li&gt;
&lt;li&gt;The save method is just checking if the user is authenticating with OpenID, if so it uses the open_id_authentication plugin to do its magic. I won't get into the specifics of this plugin because it has its own README and documentation, but it's pretty simple and self explanatory.&lt;/li&gt;
&lt;li&gt;You will notice once we find the record we set it to unauthorized_record. This is an authentication method that Authlogic supplies as an alternative to login / password authentication. Basically when you do this you are vouching for the user. You are saying "I can guarantee this user is who he says he is, lets create a session for him". Authlogic uses this itself when persisting the sessions via a cookie. It just finds the record with the matching cookie token and then vouches for the user by authenticating this way.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;Final thoughts&lt;/h3&gt;

&lt;p&gt;As you can see, you can take the above method and do pretty much anything you want. There are no restrictions and there is no authentication method that can't be implemented this way. Authlogic doesn't choose how you implement the method either. You can use any plugin you want, or write your own code, the sky is the limit.&lt;/p&gt;

&lt;p&gt;Let me know what you think, if you like it, hate it, etc. I am always looking to improve my tutorials / libraries.&lt;/p&gt;
          &lt;img src="http://feeds.binarylogic.com/~r/binarylogic/~4/460259762" height="1" width="1"/&gt;</content>  <feedburner:origLink>http://www.binarylogic.com/2008/11/21/tutorial-using-openid-with-authlogic</feedburner:origLink></entry>
  <entry xml:base="http://www.binarylogic.com/">
    <author>
      <name>benjohnson</name>
    </author>
    <id>tag:www.binarylogic.com,2008-11-16:133</id>
    <published>2008-11-16T15:19:00Z</published>
    <updated>2008-11-19T16:08:15Z</updated>
    <category term="Authlogic" />
    <category term="authlogic" />
    <category term="passwords" />
    <category term="reset" />
    <category term="resstful" />
    <category term="rest" />
    <category term="tutorial" />
    <link href="http://feeds.binarylogic.com/~r/binarylogic/~3/455237010/tutorial-reset-passwords-with-authlogic" rel="alternate" type="text/html" />
    <title>Tutorial: Reset passwords with Authlogic the RESTful way</title>
<summary type="html">&lt;p&gt;I've been getting emails asking me how to reset passwords with &lt;a href="http://github.com/binarylogic/authlogic"&gt;Authlogic&lt;/a&gt;, or how to confirm accounts. In this tutorial I'll cover resetting passwords, since it is more complex, but after reading this tutorial there is no reason why you couldn't set up account confirmation as well. In fact, my next tutorial will cover just that.&lt;/p&gt;

&lt;h2&gt;What am I about to read?&lt;/h2&gt;

&lt;p&gt;You are going to read a tutorial on how to reset passwords the RESTful way. I am going to pick up where I left off on the &lt;a href="http://www.binarylogic.com/2008/11/3/tutorial-authlogic-basic-setup"&gt;Authlogic basic setup tutorial&lt;/a&gt;, so if you have not read that I highly recommend doing so.&lt;/p&gt;

&lt;p&gt;Want to see it in action before you start? Check it out for yourself:&lt;/p&gt;

&lt;h3&gt;&lt;a href="http://authlogic_example.binarylogic.com"&gt;A live example of this tutorial&lt;/a&gt;&lt;/h3&gt;

&lt;p&gt;Before we begin, let me walk you through the basic process of resetting a password as I see it:&lt;/p&gt;</summary><content type="html">
            &lt;p&gt;I've been getting emails asking me how to reset passwords with &lt;a href="http://github.com/binarylogic/authlogic"&gt;Authlogic&lt;/a&gt;, or how to confirm accounts. In this tutorial I'll cover resetting passwords, since it is more complex, but after reading this tutorial there is no reason why you couldn't set up account confirmation as well. In fact, my next tutorial will cover just that.&lt;/p&gt;

&lt;h2&gt;What am I about to read?&lt;/h2&gt;

&lt;p&gt;You are going to read a tutorial on how to reset passwords the RESTful way. I am going to pick up where I left off on the &lt;a href="http://www.binarylogic.com/2008/11/3/tutorial-authlogic-basic-setup"&gt;Authlogic basic setup tutorial&lt;/a&gt;, so if you have not read that I highly recommend doing so.&lt;/p&gt;

&lt;p&gt;Want to see it in action before you start? Check it out for yourself:&lt;/p&gt;

&lt;h3&gt;&lt;a href="http://authlogic_example.binarylogic.com"&gt;A live example of this tutorial&lt;/a&gt;&lt;/h3&gt;

&lt;p&gt;Before we begin, let me walk you through the basic process of resetting a password as I see it:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;A user requests a password reset&lt;/li&gt;
&lt;li&gt;An email is sent to them with a link to reset their password&lt;/li&gt;
&lt;li&gt;The user verifies their identity be using the link we emailed them&lt;/li&gt;
&lt;li&gt;They are presented with a basic form to change their password&lt;/li&gt;
&lt;li&gt;After they change their password we log them in, redirect them to their account, and expire the URL we just sent them&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That seems pretty simple, right? So let's get started...&lt;/p&gt;

&lt;h2&gt;Helpful links&lt;/h2&gt;

&lt;p&gt;Before we start I want give you some helpful / related links:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="http://www.binarylogic.com/2008/11/3/tutorial-authlogic-basic-setup"&gt;Tutorial: Authlogic basic setup&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://authlogic_example.binarylogic.com/"&gt;Live example of the this tutorial&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://github.com/binarylogic/authlogic_example/tree/with-password-resets"&gt;Source code of this tutorial&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://github.com/binarylogic/authlogic"&gt;Authlogic repository&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://authlogic.rubyforge.org/"&gt;Authlogic documentation&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;1. Add in the reset_password_token and email fields&lt;/h2&gt;

&lt;p&gt;I am going to pick up from the &lt;a href="http://www.binarylogic.com/2008/11/3/tutorial-authlogic-basic-setup"&gt;Authlogic basic setup tutorial&lt;/a&gt;, so I am assuming you are familiar with Authlogic and the basic setup.&lt;/p&gt;

&lt;p&gt;With this tutorial I am introducing a new field in your database called &lt;strong&gt;perishable_token&lt;/strong&gt;. Authlogic will take care of maintaining this for you. Here is how:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The token gets set to a unique value before validation, which constantly changes the token. The value is a "friendly" value, something like: 4LiXF7FiGUppIPubBPey, not as long or as hardcore as a Sha512 hash, so it doesn't cause problems when emailed or copying and pasting into a browser.&lt;/li&gt;
&lt;li&gt;After a session is successfully saved (aka logged in) the the token will be reset. This makes the email we sent them before no longer usable.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Generate your migration:&lt;/p&gt;

&lt;pre class="cobalt"&gt;
$ script/generate migration add_users_password_reset_fields
&lt;/pre&gt;

&lt;p&gt;Now update the migration:&lt;/p&gt;

&lt;pre class="cobalt"&gt;
&lt;span class="Keyword"&gt;class&lt;/span&gt; &lt;span class="Entity"&gt;AddUsersPasswordResetFields&lt;span class="EntityInheritedClass"&gt; &lt;span class="Punctuation"&gt;&amp;lt;&lt;/span&gt; ActiveRecord::Migration&lt;/span&gt;&lt;/span&gt;
  &lt;span class="Keyword"&gt;def&lt;/span&gt; &lt;span class="Entity"&gt;self.up&lt;/span&gt;
    add_column &lt;span class="Constant"&gt;&lt;span class="Punctuation"&gt;:&lt;/span&gt;users&lt;/span&gt;&lt;span class="Punctuation"&gt;,&lt;/span&gt; &lt;span class="Constant"&gt;&lt;span class="Punctuation"&gt;:&lt;/span&gt;perishable_token&lt;/span&gt;&lt;span class="Punctuation"&gt;,&lt;/span&gt; &lt;span class="Constant"&gt;&lt;span class="Punctuation"&gt;:&lt;/span&gt;string&lt;/span&gt;&lt;span class="Punctuation"&gt;,&lt;/span&gt; &lt;span class="Constant"&gt;&lt;span class="Punctuation"&gt;:&lt;/span&gt;default&lt;/span&gt; &lt;span class="Punctuation"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="String"&gt;&lt;span class="Punctuation"&gt;&amp;quot;&lt;/span&gt;&lt;span class="Punctuation"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class="Punctuation"&gt;,&lt;/span&gt; &lt;span class="Constant"&gt;&lt;span class="Punctuation"&gt;:&lt;/span&gt;null&lt;/span&gt; &lt;span class="Punctuation"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="Constant"&gt;false&lt;/span&gt;
    add_column &lt;span class="Constant"&gt;&lt;span class="Punctuation"&gt;:&lt;/span&gt;users&lt;/span&gt;&lt;span class="Punctuation"&gt;,&lt;/span&gt; &lt;span class="Constant"&gt;&lt;span class="Punctuation"&gt;:&lt;/span&gt;email&lt;/span&gt;&lt;span class="Punctuation"&gt;,&lt;/span&gt; &lt;span class="Constant"&gt;&lt;span class="Punctuation"&gt;:&lt;/span&gt;string&lt;/span&gt;&lt;span class="Punctuation"&gt;,&lt;/span&gt; &lt;span class="Constant"&gt;&lt;span class="Punctuation"&gt;:&lt;/span&gt;default&lt;/span&gt; &lt;span class="Punctuation"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="String"&gt;&lt;span class="Punctuation"&gt;&amp;quot;&lt;/span&gt;&lt;span class="Punctuation"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class="Punctuation"&gt;,&lt;/span&gt; &lt;span class="Constant"&gt;&lt;span class="Punctuation"&gt;:&lt;/span&gt;null&lt;/span&gt; &lt;span class="Punctuation"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="Constant"&gt;false&lt;/span&gt;

    add_index &lt;span class="Constant"&gt;&lt;span class="Punctuation"&gt;:&lt;/span&gt;users&lt;/span&gt;&lt;span class="Punctuation"&gt;,&lt;/span&gt; &lt;span class="Constant"&gt;&lt;span class="Punctuation"&gt;:&lt;/span&gt;perishable_token&lt;/span&gt;
    add_index &lt;span class="Constant"&gt;&lt;span class="Punctuation"&gt;:&lt;/span&gt;users&lt;/span&gt;&lt;span class="Punctuation"&gt;,&lt;/span&gt; &lt;span class="Constant"&gt;&lt;span class="Punctuation"&gt;:&lt;/span&gt;email&lt;/span&gt;
  &lt;span class="Keyword"&gt;end&lt;/span&gt;

  &lt;span class="Keyword"&gt;def&lt;/span&gt; &lt;span class="Entity"&gt;self.down&lt;/span&gt;
    remove_column &lt;span class="Constant"&gt;&lt;span class="Punctuation"&gt;:&lt;/span&gt;users&lt;/span&gt;&lt;span class="Punctuation"&gt;,&lt;/span&gt; &lt;span class="Constant"&gt;&lt;span class="Punctuation"&gt;:&lt;/span&gt;perishable_token&lt;/span&gt;
    remove_column &lt;span class="Constant"&gt;&lt;span class="Punctuation"&gt;:&lt;/span&gt;users&lt;/span&gt;&lt;span class="Punctuation"&gt;,&lt;/span&gt; &lt;span class="Constant"&gt;&lt;span class="Punctuation"&gt;:&lt;/span&gt;email&lt;/span&gt;
  &lt;span class="Keyword"&gt;end&lt;/span&gt;
&lt;span class="Keyword"&gt;end&lt;/span&gt;
&lt;/pre&gt;

&lt;p&gt;Migrate your database:&lt;/p&gt;

&lt;pre class="cobalt"&gt;
$ rake db:migrate
&lt;/pre&gt;

&lt;p&gt;When adding the email field Authlogic will notice this and validate it for you, making sure the email is unique and a valid email address. If you wish to disable this just pass the :validate_email_field =&gt; false option to acts_as_authentic. You can also have it ignore the email field all together by passing the :email_field =&gt; nil option.&lt;/p&gt;

&lt;h2&gt;2. Let users request a password reset&lt;/h2&gt;

&lt;p&gt;We need to know if users lost their password, why not create another resource for this?&lt;/p&gt;

&lt;pre class="cobalt"&gt;
$ script/generate controller password_resets
&lt;/pre&gt;

&lt;p&gt;Let's fill out this controller with some actions (I will explain them below):&lt;/p&gt;

&lt;pre class="cobalt"&gt;
&lt;span class="Comment"&gt;&lt;span class="Punctuation"&gt;#&lt;/span&gt; app/controllers/password_resets_controller.rb&lt;/span&gt;
&lt;span class="Keyword"&gt;class&lt;/span&gt; &lt;span class="Entity"&gt;PasswordResetsController&lt;span class="EntityInheritedClass"&gt; &lt;span class="Punctuation"&gt;&amp;lt;&lt;/span&gt; ApplicationController&lt;/span&gt;&lt;/span&gt;
  &lt;span class="Keyword"&gt;def&lt;/span&gt; &lt;span class="Entity"&gt;new&lt;/span&gt;
    &lt;span class="SupportFunction"&gt;render&lt;/span&gt;
  &lt;span class="Keyword"&gt;end&lt;/span&gt;

  &lt;span class="Keyword"&gt;def&lt;/span&gt; &lt;span class="Entity"&gt;create&lt;/span&gt;
    &lt;span class="Variable"&gt;&lt;span class="Punctuation"&gt;@&lt;/span&gt;user&lt;/span&gt; &lt;span class="Keyword"&gt;=&lt;/span&gt; &lt;span class="Support"&gt;User&lt;/span&gt;&lt;span class="FunctionCall"&gt;&lt;span class="Punctuation"&gt;.&lt;/span&gt;&lt;span class="Entity"&gt;find_by_email&lt;/span&gt;&lt;/span&gt;&lt;span class="Punctuation"&gt;(&lt;/span&gt;params&lt;span class="Punctuation"&gt;[&lt;/span&gt;&lt;span class="Constant"&gt;&lt;span class="Punctuation"&gt;:&lt;/span&gt;email&lt;/span&gt;&lt;span class="Punctuation"&gt;]&lt;/span&gt;&lt;span class="Punctuation"&gt;)&lt;/span&gt;
    &lt;span class="Keyword"&gt;if&lt;/span&gt; &lt;span class="Variable"&gt;&lt;span class="Punctuation"&gt;@&lt;/span&gt;user&lt;/span&gt;
      &lt;span class="Variable"&gt;&lt;span class="Punctuation"&gt;@&lt;/span&gt;user&lt;/span&gt;&lt;span class="FunctionCall"&gt;&lt;span class="Punctuation"&gt;.&lt;/span&gt;&lt;span class="Entity"&gt;deliver_password_reset_instructions!&lt;/span&gt;&lt;/span&gt;
      flash&lt;span class="Punctuation"&gt;[&lt;/span&gt;&lt;span class="Constant"&gt;&lt;span class="Punctuation"&gt;:&lt;/span&gt;notice&lt;/span&gt;&lt;span class="Punctuation"&gt;]&lt;/span&gt; &lt;span class="Keyword"&gt;=&lt;/span&gt; &lt;span class="String"&gt;&lt;span class="Punctuation"&gt;&amp;quot;&lt;/span&gt;Instructions to reset your password have been emailed to you. &lt;span class="Punctuation"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class="Keyword"&gt;+&lt;/span&gt;
        &lt;span class="String"&gt;&lt;span class="Punctuation"&gt;&amp;quot;&lt;/span&gt;Please check your email.&lt;span class="Punctuation"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
      &lt;span class="SupportFunction"&gt;redirect_to&lt;/span&gt; root_url
    &lt;span class="Keyword"&gt;else&lt;/span&gt;
      flash&lt;span class="Punctuation"&gt;[&lt;/span&gt;&lt;span class="Constant"&gt;&lt;span class="Punctuation"&gt;:&lt;/span&gt;notice&lt;/span&gt;&lt;span class="Punctuation"&gt;]&lt;/span&gt; &lt;span class="Keyword"&gt;=&lt;/span&gt; &lt;span class="String"&gt;&lt;span class="Punctuation"&gt;&amp;quot;&lt;/span&gt;No user was found with that email address&lt;span class="Punctuation"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
      &lt;span class="SupportFunction"&gt;render&lt;/span&gt; &lt;span class="Constant"&gt;&lt;span class="Punctuation"&gt;:&lt;/span&gt;action&lt;/span&gt; &lt;span class="Punctuation"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="Constant"&gt;&lt;span class="Punctuation"&gt;:&lt;/span&gt;new&lt;/span&gt;
    &lt;span class="Keyword"&gt;end&lt;/span&gt;
  &lt;span class="Keyword"&gt;end&lt;/span&gt;
&lt;span class="Keyword"&gt;end&lt;/span&gt;
&lt;/pre&gt;

&lt;p&gt;Now update your routes:&lt;/p&gt;

&lt;pre class="cobalt"&gt;
&lt;span class="Comment"&gt;&lt;span class="Punctuation"&gt;#&lt;/span&gt; config/routes.rb&lt;/span&gt;
map&lt;span class="FunctionCall"&gt;&lt;span class="Punctuation"&gt;.&lt;/span&gt;&lt;span class="Entity"&gt;resources&lt;/span&gt;&lt;/span&gt; &lt;span class="Constant"&gt;&lt;span class="Punctuation"&gt;:&lt;/span&gt;password_resets&lt;/span&gt;
&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;What did I just do?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The deliver_password_reset_instructions! is a method I added, you can call it whatever you want. All that it does is reset the password reset token and send an email.&lt;/p&gt;

&lt;p&gt;Here is what I did in my own application:&lt;/p&gt;

&lt;pre class="cobalt"&gt;
&lt;span class="Comment"&gt;&lt;span class="Punctuation"&gt;#&lt;/span&gt; app/models/user.rb&lt;/span&gt;
&lt;span class="Keyword"&gt;class&lt;/span&gt; &lt;span class="Entity"&gt;User&lt;span class="EntityInheritedClass"&gt; &lt;span class="Punctuation"&gt;&amp;lt;&lt;/span&gt; ActiveRecord::Base&lt;/span&gt;&lt;/span&gt;
  &lt;span class="Keyword"&gt;def&lt;/span&gt; &lt;span class="Entity"&gt;deliver_password_reset_instructions!&lt;/span&gt;
    reset_perishable_token!
    &lt;span class="Support"&gt;Notifier&lt;/span&gt;&lt;span class="FunctionCall"&gt;&lt;span class="Punctuation"&gt;.&lt;/span&gt;&lt;span class="Entity"&gt;deliver_password_reset_instructions&lt;/span&gt;&lt;/span&gt;&lt;span class="Punctuation"&gt;(&lt;/span&gt;&lt;span class="LangVariable"&gt;self&lt;/span&gt;&lt;span class="Punctuation"&gt;)&lt;/span&gt;
  &lt;span class="Keyword"&gt;end&lt;/span&gt;
&lt;span class="Keyword"&gt;end&lt;/span&gt;
&lt;/pre&gt;

&lt;p&gt;The reset_perishable_token! is a handy method Authlogic gives you. It basically resets the field to a unique "friendly" token and then saves the record.&lt;/p&gt;

&lt;p&gt;My Notifier action looks like this:&lt;/p&gt;

&lt;pre class="cobalt"&gt;
&lt;span class="Comment"&gt;&lt;span class="Punctuation"&gt;#&lt;/span&gt; app/models/notifier.rb&lt;/span&gt;
&lt;span class="Keyword"&gt;class&lt;/span&gt; &lt;span class="Entity"&gt;Notifier&lt;span class="EntityInheritedClass"&gt; &lt;span class="Punctuation"&gt;&amp;lt;&lt;/span&gt; ActionMailer::Base&lt;/span&gt;&lt;/span&gt;
  default_url_options&lt;span class="Punctuation"&gt;[&lt;/span&gt;&lt;span class="Constant"&gt;&lt;span class="Punctuation"&gt;:&lt;/span&gt;host&lt;/span&gt;&lt;span class="Punctuation"&gt;]&lt;/span&gt; &lt;span class="Keyword"&gt;=&lt;/span&gt; &lt;span class="String"&gt;&lt;span class="Punctuation"&gt;&amp;quot;&lt;/span&gt;authlogic_example.binarylogic.com&lt;span class="Punctuation"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;

  &lt;span class="Keyword"&gt;def&lt;/span&gt; &lt;span class="Entity"&gt;password_reset_instructions&lt;/span&gt;&lt;span class="Punctuation"&gt;(&lt;/span&gt;&lt;span class="Variable"&gt;user&lt;/span&gt;&lt;span class="Punctuation"&gt;)&lt;/span&gt;
    subject       &lt;span class="String"&gt;&lt;span class="Punctuation"&gt;&amp;quot;&lt;/span&gt;Password Reset Instructions&lt;span class="Punctuation"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
    from          &lt;span class="String"&gt;&lt;span class="Punctuation"&gt;&amp;quot;&lt;/span&gt;Binary Logic Notifier &amp;lt;noreply@binarylogic.com&amp;gt;&lt;span class="Punctuation"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
    recipients    user&lt;span class="FunctionCall"&gt;&lt;span class="Punctuation"&gt;.&lt;/span&gt;&lt;span class="Entity"&gt;email&lt;/span&gt;&lt;/span&gt;
    sent_on       &lt;span class="Support"&gt;Time&lt;/span&gt;&lt;span class="FunctionCall"&gt;&lt;span class="Punctuation"&gt;.&lt;/span&gt;&lt;span class="Entity"&gt;now&lt;/span&gt;&lt;/span&gt;
    body          &lt;span class="Constant"&gt;&lt;span class="Punctuation"&gt;:&lt;/span&gt;edit_password_reset_url&lt;/span&gt; &lt;span class="Punctuation"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="FunctionCall"&gt;&lt;span class="Entity"&gt;edit_password_reset_url&lt;/span&gt;&lt;/span&gt;&lt;span class="Punctuation"&gt;(&lt;/span&gt;user&lt;span class="FunctionCall"&gt;&lt;span class="Punctuation"&gt;.&lt;/span&gt;&lt;span class="Entity"&gt;perishable_token&lt;/span&gt;&lt;/span&gt;&lt;span class="Punctuation"&gt;)&lt;/span&gt;
  &lt;span class="Keyword"&gt;end&lt;/span&gt;
&lt;span class="Keyword"&gt;end&lt;/span&gt;
&lt;/pre&gt;

&lt;p&gt;Then the email looks like:&lt;/p&gt;

&lt;pre class="cobalt"&gt;
# app/views/notifier/password_reset_instructions.erb
A request to reset your password has been made.
If you did not make this request, simply ignore this email.
If you did make this request just click the link below:

&lt;span class="EmbeddedSource"&gt;&lt;span class="Punctuation"&gt;&amp;lt;%=&lt;/span&gt; &lt;span class="Variable"&gt;&lt;span class="Punctuation"&gt;@&lt;/span&gt;edit_password_reset_url&lt;/span&gt; &lt;span class="Punctuation"&gt;%&amp;gt;&lt;/span&gt;&lt;/span&gt;

If the above URL does not work try copying and pasting it into your browser.
If you continue to have problem please feel free to contact us.
&lt;/pre&gt;

&lt;p&gt;You can do the above any way you want. I actually recommend creating a text and html version of this email, but for the sake of brevity I only included the text version.&lt;/p&gt;

&lt;h2&gt;3. Let users reset their password&lt;/h2&gt;

&lt;p&gt;Once they get that email and click the link in it, it needs to take them somewhere. So let's add some methods to our PasswordResetsController:&lt;/p&gt;

&lt;pre class="cobalt"&gt;
&lt;span class="Comment"&gt;&lt;span class="Punctuation"&gt;#&lt;/span&gt; app/controllers/password_resets_controller.rb&lt;/span&gt;
&lt;span class="SupportFunction"&gt;before_filter&lt;/span&gt; &lt;span class="Constant"&gt;&lt;span class="Punctuation"&gt;:&lt;/span&gt;load_user_using_perishable_token&lt;/span&gt;&lt;span class="Punctuation"&gt;,&lt;/span&gt; &lt;span class="Constant"&gt;&lt;span class="Punctuation"&gt;:&lt;/span&gt;only&lt;/span&gt; &lt;span class="Punctuation"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="Punctuation"&gt;[&lt;/span&gt;&lt;span class="Constant"&gt;&lt;span class="Punctuation"&gt;:&lt;/span&gt;edit&lt;/span&gt;&lt;span class="Punctuation"&gt;,&lt;/span&gt; &lt;span class="Constant"&gt;&lt;span class="Punctuation"&gt;:&lt;/span&gt;update&lt;/span&gt;&lt;span class="Punctuation"&gt;]&lt;/span&gt;

&lt;span class="Keyword"&gt;def&lt;/span&gt; &lt;span class="Entity"&gt;edit&lt;/span&gt;
  &lt;span class="SupportFunction"&gt;render&lt;/span&gt;
&lt;span class="Keyword"&gt;end&lt;/span&gt;

&lt;span class="Keyword"&gt;def&lt;/span&gt; &lt;span class="Entity"&gt;update&lt;/span&gt;
  &lt;span class="Variable"&gt;&lt;span class="Punctuation"&gt;@&lt;/span&gt;user&lt;/span&gt;&lt;span class="FunctionCall"&gt;&lt;span class="Punctuation"&gt;.&lt;/span&gt;&lt;span class="Entity"&gt;password&lt;/span&gt;&lt;/span&gt; &lt;span class="Keyword"&gt;=&lt;/span&gt; params&lt;span class="Punctuation"&gt;[&lt;/span&gt;&lt;span class="Constant"&gt;&lt;span class="Punctuation"&gt;:&lt;/span&gt;user&lt;/span&gt;&lt;span class="Punctuation"&gt;]&lt;/span&gt;&lt;span class="Punctuation"&gt;[&lt;/span&gt;&lt;span class="Constant"&gt;&lt;span class="Punctuation"&gt;:&lt;/span&gt;password&lt;/span&gt;&lt;span class="Punctuation"&gt;]&lt;/span&gt;
  &lt;span class="Variable"&gt;&lt;span class="Punctuation"&gt;@&lt;/span&gt;user&lt;/span&gt;&lt;span class="FunctionCall"&gt;&lt;span class="Punctuation"&gt;.&lt;/span&gt;&lt;span class="Entity"&gt;password_confirmation&lt;/span&gt;&lt;/span&gt; &lt;span class="Keyword"&gt;=&lt;/span&gt; params&lt;span class="Punctuation"&gt;[&lt;/span&gt;&lt;span class="Constant"&gt;&lt;span class="Punctuation"&gt;:&lt;/span&gt;user&lt;/span&gt;&lt;span class="Punctuation"&gt;]&lt;/span&gt;&lt;span class="Punctuation"&gt;[&lt;/span&gt;&lt;span class="Punctuation"&gt;:&lt;/span&gt; password_confirmation&lt;span class="Punctuation"&gt;]&lt;/span&gt;
  &lt;span class="Keyword"&gt;if&lt;/span&gt; &lt;span class="Variable"&gt;&lt;span class="Punctuation"&gt;@&lt;/span&gt;user&lt;/span&gt;&lt;span class="FunctionCall"&gt;&lt;span class="Punctuation"&gt;.&lt;/span&gt;&lt;span class="Entity"&gt;save&lt;/span&gt;&lt;/span&gt;
    flash&lt;span class="Punctuation"&gt;[&lt;/span&gt;&lt;span class="Constant"&gt;&lt;span class="Punctuation"&gt;:&lt;/span&gt;notice&lt;/span&gt;&lt;span class="Punctuation"&gt;]&lt;/span&gt; &lt;span class="Keyword"&gt;=&lt;/span&gt; &lt;span class="String"&gt;&lt;span class="Punctuation"&gt;&amp;quot;&lt;/span&gt;Password successfully updated&lt;span class="Punctuation"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class="SupportFunction"&gt;redirect_to&lt;/span&gt; account_url
  &lt;span class="Keyword"&gt;else&lt;/span&gt;
    &lt;span class="SupportFunction"&gt;render&lt;/span&gt; &lt;span class="Constant"&gt;&lt;span class="Punctuation"&gt;:&lt;/span&gt;action&lt;/span&gt; &lt;span class="Punctuation"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="Constant"&gt;&lt;span class="Punctuation"&gt;:&lt;/span&gt;edit&lt;/span&gt;
  &lt;span class="Keyword"&gt;end&lt;/span&gt;
&lt;span class="Keyword"&gt;end&lt;/span&gt;

&lt;span class="Keyword"&gt;private&lt;/span&gt;
  &lt;span class="Keyword"&gt;def&lt;/span&gt; &lt;span class="Entity"&gt;load_user_using_perishable_token&lt;/span&gt;
    &lt;span class="Variable"&gt;&lt;span class="Punctuation"&gt;@&lt;/span&gt;user&lt;/span&gt; &lt;span class="Keyword"&gt;=&lt;/span&gt; &lt;span class="Support"&gt;User&lt;/span&gt;&lt;span class="FunctionCall"&gt;&lt;span class="Punctuation"&gt;.&lt;/span&gt;&lt;span class="Entity"&gt;find_using_perishable_token&lt;/span&gt;&lt;/span&gt;&lt;span class="Punctuation"&gt;(&lt;/span&gt;params&lt;span class="Punctuation"&gt;[&lt;/span&gt;&lt;span class="Constant"&gt;&lt;span class="Punctuation"&gt;:&lt;/span&gt;id&lt;/span&gt;&lt;span class="Punctuation"&gt;]&lt;/span&gt;&lt;span class="Punctuation"&gt;)&lt;/span&gt;
    &lt;span class="Keyword"&gt;unless&lt;/span&gt; &lt;span class="Variable"&gt;&lt;span class="Punctuation"&gt;@&lt;/span&gt;user&lt;/span&gt;
      flash&lt;span class="Punctuation"&gt;[&lt;/span&gt;&lt;span class="Constant"&gt;&lt;span class="Punctuation"&gt;:&lt;/span&gt;notice&lt;/span&gt;&lt;span class="Punctuation"&gt;]&lt;/span&gt; &lt;span class="Keyword"&gt;=&lt;/span&gt; &lt;span class="String"&gt;&lt;span class="Punctuation"&gt;&amp;quot;&lt;/span&gt;We're sorry, but we could not locate your account. &lt;span class="Punctuation"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class="Keyword"&gt;+&lt;/span&gt;
        &lt;span class="String"&gt;&lt;span class="Punctuation"&gt;&amp;quot;&lt;/span&gt;If you are having issues try copying and pasting the URL &lt;span class="Punctuation"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class="Keyword"&gt;+&lt;/span&gt;
        &lt;span class="String"&gt;&lt;span class="Punctuation"&gt;&amp;quot;&lt;/span&gt;from your email into your browser or restarting the &lt;span class="Punctuation"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class="Keyword"&gt;+&lt;/span&gt;
        &lt;span class="String"&gt;&lt;span class="Punctuation"&gt;&amp;quot;&lt;/span&gt;reset password process.&lt;span class="Punctuation"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
      &lt;span class="SupportFunction"&gt;redirect_to&lt;/span&gt; root_url
    &lt;span class="Keyword"&gt;end&lt;/span&gt;
  &lt;span class="Keyword"&gt;end&lt;/span&gt;
&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;What did I just do?&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;You really don't need to add the edit method because its a blank method, the before_filter takes care of everything we need to do there. There is only a view for this method.&lt;/li&gt;
&lt;li&gt;The update method is nice, because if the user is successfully saved, Authlogic will automatically log them in, keeping your PasswordResetsController focused on resetting passwords, not sessions.&lt;/li&gt;
&lt;li&gt;The load_user_using_perishable_token has a unique method: find_using_perishable_token. This is a special method that Authlogic gives you. Here is what it does for extra security:
&lt;ol&gt;
&lt;li&gt;Ignores blank tokens&lt;/li&gt;
&lt;li&gt;Only finds records that match the token and have an updated_at (if present) value that is not older than 10 minutes. This way, if someone gets the data in your database any valid perishable tokens will expire in 10 minutes. Chances are they will expire quicker because the token is changing during user activity as well.&lt;/li&gt;
&lt;/ol&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;4. Restrict access&lt;/h2&gt;

&lt;p&gt;Now we just need to make sure the user is logged out when accessing these methods. Modify your before filters in your PasswordResetsController to look like:&lt;/p&gt;

&lt;pre class="cobalt"&gt;
  &lt;span class="SupportFunction"&gt;before_filter&lt;/span&gt; &lt;span class="Constant"&gt;&lt;span class="Punctuation"&gt;:&lt;/span&gt;require_no_user&lt;/span&gt;
&lt;/pre&gt;

&lt;h2&gt;Where are the views?&lt;/h2&gt;

&lt;p&gt;Instead of cluttering up this tutorial with a bunch of basic views, I left them out. There is nothing crazy going on in the views, nor do I really need to explain anything. If you noticed in the helpful links section I have a live example of this tutorial.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://github.com/binarylogic/authlogic_example/tree/with-password-resets/app/views"&gt;Here is a direct link to the users views source code, you can copy the views over from here&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;Why not reset passwords this way...?&lt;/h2&gt;

&lt;p&gt;If you care, here are my thoughts behind this tutorial and ultimately why I recommend resetting passwords this way...&lt;/p&gt;

&lt;p&gt;My goal with Authlogic was to stay away from generating code and give you the proper tools so that you could easily and effectively write the code yourself. If you noticed, in this tutorial, all that we really did was add a simple PasswordResetsController. Most of this tutorial was explaining what was going on, so you could understand what you were doing. I can't write that controller for you, because it is application specific. I want to keep the authentication logic in Authlogic and your application logic in your application. The tutorial above produces simpler and cleaner code than a generator. The most important part is that you understand what is going on and it works the way you want. I am basically laying out tools for you to use and explaining them. You get to use them how you wish. There is no "Surprise! Here are hundreds of lines of code, hope you like it". If you want to change passwords a different way, go for it, you now know how Authlogic can assist you in your journey to resetting passwords.&lt;/p&gt;

&lt;p&gt;Lastly, I know there are a few other common ways to reset passwords, so I will address those and why I decided against them:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Changing / randomizing the password during the first step and then emailing them their new password&lt;/strong&gt;&lt;br /&gt;You should NEVER change anyone's password until they have proven they are that user. What if Billy 13 year old starts typing in random logins and resetting peoples passwords? Those people aren't going to be happy.&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Using an already existing token that is not unique or perishable&lt;/strong&gt;&lt;br /&gt;A lot of people are tempted to use the remember_token, single_access_token, or even the crypted_password for authenticating the user for a password change. There is a reason we have all of these and none of these should be used for resetting password. What if Billy 13 year old gets ahold of any of these, he will have full access to resetting that user's password, and then have full access to their account. If for some reason he gets any of these things, your users should still be protected, which is why we need a unique and perishable token.&lt;/li&gt;
&lt;/ol&gt;
          &lt;img src="http://feeds.binarylogic.com/~r/binarylogic/~4/455237010" height="1" width="1"/&gt;</content>  <feedburner:origLink>http://www.binarylogic.com/2008/11/16/tutorial-reset-passwords-with-authlogic</feedburner:origLink></entry>
  <entry xml:base="http://www.binarylogic.com/">
    <author>
      <name>benjohnson</name>
    </author>
    <id>tag:www.binarylogic.com,2008-11-03:147</id>
    <published>2008-11-03T12:48:00Z</published>
    <updated>2008-11-21T05:36:26Z</updated>
    <category term="Authlogic" />
    <category term="auth" />
    <category term="authlogic" />
    <category term="rails" />
    <category term="restful authentication" />
    <category term="ruby" />
    <link href="http://feeds.binarylogic.com/~r/binarylogic/~3/441214373/tutorial-authlogic-basic-setup" rel="alternate" type="text/html" />
    <title>Tutorial: Authlogic Basic Setup</title>
<summary type="html">&lt;p&gt;I'm a machine today! 3 blog posts in one day. I can't be stopped.&lt;/p&gt;

&lt;p&gt;Anyways, this past week I released &lt;a href="http://github.com/binarylogic/authlogic"&gt;Authlogic&lt;/a&gt; and it has been great. I've been getting a lot of positive feedback and it seems like people enjoy using it. That's the reason I release any of my libraries, to try and make your life a little easier. Awwww, how sweet. But I've also been getting emails asking me to put together a setup tutorial. So here we go...&lt;/p&gt;</summary><content type="html">
            &lt;p&gt;I'm a machine today! 3 blog posts in one day. I can't be stopped.&lt;/p&gt;

&lt;p&gt;Anyways, this past week I released &lt;a href="http://github.com/binarylogic/authlogic"&gt;Authlogic&lt;/a&gt; and it has been great. I've been getting a lot of positive feedback and it seems like people enjoy using it. That's the reason I release any of my libraries, to try and make your life a little easier. Awwww, how sweet. But I've also been getting emails asking me to put together a setup tutorial. So here we go...&lt;/p&gt;
&lt;h2&gt;What am I about to build?&lt;/h2&gt;

&lt;p&gt;Why not check it out for yourself...&lt;/p&gt;

&lt;h3&gt;&lt;a href="http://authlogic_example.binarylogic.com"&gt;A live example of this tutorial&lt;/a&gt;&lt;/h3&gt;

&lt;p&gt;To put it into words, we are going to setup basic user authentication for a new rails app. When it's all said and done, you will have an authentication system that provides:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;User registration.&lt;/li&gt;
&lt;li&gt;Automatically log users in upon successful registration.&lt;/li&gt;
&lt;li&gt;A my account area where the user can view / change details about their account, including their password.&lt;/li&gt;
&lt;li&gt;Automatically update the users session when they change their password.&lt;/li&gt;
&lt;li&gt;Logout functionality.&lt;/li&gt;
&lt;li&gt;Login functionality with a "remember me" option.&lt;/li&gt;
&lt;li&gt;Secure password / token system, based on proven principals used in ruby / rails for years.&lt;/li&gt;
&lt;li&gt;Automatically store information on the users and their session in the databases. Such as login count, IP address, when they logged in last, and when their last activity occurred.&lt;/li&gt;
&lt;li&gt;Count how many users are logged in / out in your system.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;Assumptions&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;You know how to set up a rails app&lt;/li&gt;
&lt;li&gt;This is a basic tutorial, therefore I won't cover advanced situations.&lt;/li&gt;
&lt;li&gt;You are familiar with basic authentication in rails and understand the "gist" of it.&lt;/li&gt;
&lt;li&gt;You are familiar with the RESTful development style and get the basic idea behind it. (you can set up a RESTful route and controller)&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;Helpful links&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="http://github.com/binarylogic/authlogic_example"&gt;This tutorial's source code&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://authlogic_example.binarylogic.com"&gt;Live example of this tutorial&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://authlogic.rubyforge.org"&gt;Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://binarylogic.lighthouseapp.com/projects/18752-authlogic"&gt;Bugs / feature suggestions&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.binarylogic.com/2008/11/16/tutorial-reset-passwords-with-authlogic#comments"&gt;Follow up tutorial: resetting password with Authlogic&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.binarylogic.com/2008/11/21/tutorial-using-openid-with-authlogic"&gt;Follow up tutorial: Using OpenID with Authlogic&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.binarylogic.com/2008/11/23/tutorial-easily-migrate-from-restful_authentication-to-authlogic"&gt;Follow up tutorial: Migrating from restful_authentication&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;Migrating an existing app from restful_authentication?&lt;/h2&gt;

&lt;p&gt;It's simple, &lt;a href="http://www.binarylogic.com/2008/11/23/tutorial-easily-migrate-from-restful_authentication-to-authlogic"&gt;checkout my blog post about this&lt;/a&gt;. Also, keep reading this tutorial as this will help you understand the implementation.&lt;/p&gt;

&lt;h2&gt;1. Install Authglogic&lt;/h2&gt;

&lt;p&gt;Install the gem / plugin (recommended)&lt;/p&gt;

&lt;pre class="cobalt"&gt;
$ sudo gem install authlogic
&lt;/pre&gt;

&lt;pre class="cobalt"&gt;
&lt;span class="Comment"&gt;&lt;span class="Punctuation"&gt;#&lt;/span&gt; config/environment.rb&lt;/span&gt;
config&lt;span class="FunctionCall"&gt;&lt;span class="Punctuation"&gt;.&lt;/span&gt;&lt;span class="Entity"&gt;gem&lt;/span&gt;&lt;/span&gt; &lt;span class="String"&gt;&lt;span class="Punctuation"&gt;&amp;quot;&lt;/span&gt;authlogic&lt;span class="Punctuation"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;/pre&gt;

&lt;p&gt;Or as a plugin (you must have git installed to do this)&lt;/p&gt;

&lt;pre class="cobalt"&gt;
$ script/plugin install git://github.com/binarylogic/authlogic.git
&lt;/pre&gt;

&lt;h2&gt;2. Create your UserSession model&lt;/h2&gt;

&lt;p&gt;Now we need to create the user session model:&lt;/p&gt;

&lt;pre class="cobalt"&gt;
$ script/generate session user_session
&lt;/pre&gt;

&lt;p&gt;This will create a file that looks like:&lt;/p&gt;

&lt;pre class="cobalt"&gt;
&lt;span class="Comment"&gt;&lt;span class="Punctuation"&gt;#&lt;/span&gt; app/models/user_session.rb&lt;/span&gt;
&lt;span class="Keyword"&gt;class&lt;/span&gt; &lt;span class="Entity"&gt;UserSession&lt;span class="EntityInheritedClass"&gt; &lt;span class="Punctuation"&gt;&amp;lt;&lt;/span&gt; Authlogic::Session::Base&lt;/span&gt;&lt;/span&gt;
&lt;span class="Comment"&gt;  &lt;span class="Punctuation"&gt;#&lt;/span&gt; various configuration goes here, see AuthLogic::Session::Config for more details&lt;/span&gt;
&lt;span class="Keyword"&gt;end&lt;/span&gt;
&lt;/pre&gt;

&lt;p&gt;Remember all of those repetitive authentication methods you added in your controllers? All of that "cruft" is taken care of in this file. It basically sits in between you and the cookies. Similar to how ActiveRecord sits in between you and the database.&lt;/p&gt;

&lt;h2&gt;3. Create your UserSessions controller&lt;/h2&gt;

&lt;pre class=