<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>The Napkin ~ A Blog By Highgroove Studios comments on Simple Subdomain Authentication In Ruby on Rails</title>
    <link>http://cleanair.highgroove.com/</link>
    <language>en-us</language>
    <ttl>40</ttl>
    <description>The Napkin ~ A Blog By Highgroove Studios comments</description>
    <item>
      <title>"Simple Subdomain Authentication In Ruby on Rails": comment by Benjamin</title>
      <description>&lt;p&gt;Using the subdomains as a key is definetely clever. It may not have a huge variety of applications because it is not needed all too often, but I can see the value in doing it as an alternate in some specialty cases. I&amp;#8217;d be interested in hearing what applications you&amp;#8217;d use it in. &amp;#8211; ben @ http://rubyonrailsblog.com/&lt;/p&gt;</description>
      <pubDate>Wed, 16 Aug 2006 03:51:32 EST</pubDate>
      <guid>http://cleanair.highgroove.com/articles/2006/08/14/simplied-subdomain-authentication-in-ruby-on-rails#comment-80</guid>
      <link>http://cleanair.highgroove.com/articles/2006/08/14/simplied-subdomain-authentication-in-ruby-on-rails#comment-80</link>
    </item>
    <item>
      <title>"Simple Subdomain Authentication In Ruby on Rails" by derek</title>
      <description>&lt;p&gt;Using a subdomain as an account key (ie &amp;#8211; highgroove.heartbeathq.com where &amp;#8220;highgroove&amp;#8221; is the account key) is a great way to personalize a web application. Rails has a nifty plugin written just for this, but the implementation information is a bit scattered. Here&amp;#8217;s a step-by-step guide for implementing, testing, and simulating this powerful feature.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. &lt;a href="http://dev.rubyonrails.org/svn/rails/plugins/account_location/"&gt;Take a look at the Account Location Plugin&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;


	&lt;p&gt;Coming in at a concise 30 lines of code, it&amp;#8217;s an easy read.&lt;/p&gt;


	&lt;p&gt;&lt;strong&gt;2. Customize the plugin for your needs&lt;/strong&gt;&lt;/p&gt;


	&lt;p&gt;The plugin assumes we&amp;#8217;re working with an Account model and that an instance variable named &lt;code&gt;@account&lt;/code&gt; is the Account associated with the current subdomain. In my case, I wasn&amp;#8217;t working with an Account class and I also didn&amp;#8217;t want to assign the associated object to an instance variable of the same name (For example, in some cases &lt;code&gt;@account&lt;/code&gt; could be assigned to a different account than the one associated with the subdomain).&lt;/p&gt;


	&lt;p&gt;I&amp;#8217;m working with a &lt;a href="http://heartbeat.highgroove.com"&gt;Heartbeat Dashboard&lt;/a&gt;. Here&amp;#8217;s my modified code. Instead of installing the plugin, I created a DashboardLocation module:&lt;/p&gt;


&lt;pre&gt;&lt;code&gt;
module DashboardLocation
  def self.included(controller)
    controller.helper_method(:dashboard_domain, :dashboard_subdomain, 
                             :dashboard_host, :dashboard_url, 
                             :current_dashboard, :current_subscription)
  end

  protected
    def default_dashboard_subdomain
     current_dashboard.subdomain if current_dashboard
    end

    def dashboard_url(dashboard_subdomain = default_dashboard_subdomain, use_ssl = request.ssl?)
      (use_ssl ? "https://" : "http://") + dashboard_host(dashboard_subdomain)
    end

    def dashboard_host(dashboard_subdomain = default_dashboard_subdomain)
      dashboard_host = "" 
      dashboard_host &amp;lt;&amp;lt; dashboard_subdomain + "." 
      dashboard_host &amp;lt;&amp;lt; dashboard_domain
    end

    def dashboard_domain
      dashboard_domain = "" 
      dashboard_domain &amp;lt;&amp;lt; request.subdomains[1..-1].join(".") + "." if request.subdomains.size &amp;gt; 1
      dashboard_domain &amp;lt;&amp;lt; request.domain + request.port_string
    end

    def dashboard_subdomain
      request.subdomains.first
    end

    def current_dashboard
      Dashboard.find(:first, 
                     :conditions =&amp;gt; ["subdomain = ? and subdomain IS NOT NULL",dashboard_subdomain])
    end

    def ensure_current_dashboard
      return true if current_dashboard
      flash[:warning] = "Please select a dashboard to login." 
      redirect_to(:controller =&amp;gt; '/home') and return false
    end
end
&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;&lt;strong&gt;3. Install the plugin (or your own module)&lt;/strong&gt;&lt;/p&gt;


	&lt;p&gt;If you don&amp;#8217;t need to make any modifications, install the plugin straight-up:&lt;/p&gt;


&lt;pre&gt;
&lt;code&gt;ruby script/plugin install http://dev.rubyonrails.org/svn/rails/plugins/account_location/&lt;/code&gt;
&lt;/pre&gt;
If you need a customized module like me, put it in your lib folder (i.e. lib/dashboard_locaton.rb) and require it in your environment.rb file (require &amp;#8216;dashboard_location&amp;#8217;).

	&lt;p&gt;&lt;strong&gt;4. Add some Test Helpers&lt;/strong&gt;&lt;/p&gt;


	&lt;p&gt;I added the methods below to &lt;code&gt;TestHelper&lt;/code&gt; to make it easier to test our subdomain functionality. Remember I&amp;#8217;m using &lt;code&gt;current_dashboard&lt;/code&gt; instead of &lt;code&gt;@account&lt;/code&gt; to represent the subdomain record.&lt;/p&gt;


&lt;pre&gt;&lt;code&gt;
class Test::Unit::TestCase
  ...
   # Puts a dashboard into the subdomain
  def dashboard_setup(dashboard = dashboards(:derek_dashboard) )
     @request.host = "#{dashboard.subdomain}.local.host" 
     assert_equal dashboard, current_dashboard
  end

  def clear_dashboard
    @request.host = "local.host" 
    assert_nil current_dashboard, 
               "There is a current dashboard when there shouldn't be: #{current_dashboard}" 
  end

  def current_dashboard
     Dashboard.find(:first, :conditions =&amp;gt; ["subdomain = ? and subdomain IS NOT NULL",dashboard_subdomain])
  end

  def dashboard_subdomain
    @request.subdomains.first
  end
&lt;/code&gt;&lt;/pre&gt;

5. Add some Functional Tests
&lt;pre&gt;&lt;code&gt;
# failure - invalid subdomain
@request.host = "invalid.local.host" 
get :index
assert_redirected_to :controller =&amp;gt; 'home'
assert_not_nil flash[:warning]

# success
dashboard_setup
get :index
assert_response :success
assert_template "dashboard/index" 
&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;&lt;strong&gt;6. Implement the functionality in our controllers&lt;/strong&gt;&lt;/p&gt;


&lt;pre&gt;&lt;code&gt;
class ApplicationController &amp;lt; ActionController::Base
  include DashboardLocation
  ...
&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;&lt;strong&gt;7. Verify the tests pass&lt;/strong&gt;&lt;/p&gt;


	&lt;p&gt;&lt;strong&gt;8. Simulate the environment on your development machine.&lt;/strong&gt;&lt;/p&gt;


	&lt;p&gt;Alter your &amp;#8220;hosts&amp;#8221; file to re-route domain lookups to your local machine (127.0.0.1).&lt;/p&gt;


	&lt;p&gt;&lt;em&gt;On Mac &lt;span class="caps"&gt;OSX&lt;/span&gt; and Linux:&lt;/em&gt;&lt;/p&gt;


&lt;pre&gt;&lt;code&gt;
$ sudo vi /etc/hosts
&lt;/pre&gt;&lt;/code&gt;

	&lt;p&gt;&lt;em&gt;On Windows:&lt;/em&gt;&lt;/p&gt;


&lt;pre&gt;&lt;code&gt;
C:\WINDOWS\SYSTEM32\DRIVERS\etc\hosts 
&lt;/pre&gt;&lt;/code&gt;

	&lt;p&gt;Add an entry for your application domain (i.e. heartbeathq.com):&lt;/p&gt;


&lt;pre&gt;&lt;code&gt;
127.0.0.1 heartbeathq.com
&lt;/pre&gt;&lt;/code&gt;

Add entries for any subdomain you want to test:
&lt;pre&gt;&lt;code&gt;
127.0.0.1 highgroove.heartbeathq.com
127.0.0.1 rubyonrails.heartbeathq.com
&lt;/pre&gt;&lt;/code&gt;

	&lt;p&gt;Refresh and clear your cache to make sure lookups are re-routed:&lt;/p&gt;


	&lt;p&gt;&lt;em&gt;On Mac &lt;span class="caps"&gt;OSX&lt;/span&gt;:&lt;/em&gt;&lt;/p&gt;


	&lt;p&gt;Issue the command in the terminal:&lt;/p&gt;


&lt;pre&gt;&lt;code&gt;
$ sudo lookupd -flushcache
&lt;/pre&gt;&lt;/code&gt;

	&lt;p&gt;&lt;em&gt;On Linux:&lt;/em&gt;&lt;/p&gt;


	&lt;p&gt;Linux is pretty good about reading your /etc/hosts file, but to be on the safe side, restart ncsd if it&amp;#8217;s running:&lt;/p&gt;


&lt;pre&gt;&lt;code&gt;
$ sudo /etc/init.d/ncsd restart
&lt;/pre&gt;&lt;/code&gt;

	&lt;p&gt;&lt;em&gt;On Windows:&lt;/em&gt;&lt;/p&gt;


	&lt;p&gt;Issue the command at the command prompt:&lt;/p&gt;


&lt;pre&gt;&lt;code&gt;
C:\&amp;gt;ipconfig /flushdns
&lt;/pre&gt;&lt;/code&gt;

	&lt;p&gt;You&amp;#8217;ll now be able to access your application through a pretty &lt;span class="caps"&gt;URL&lt;/span&gt; like: &lt;code&gt;http://highgroove.heartbeat.com&lt;/code&gt;.&lt;/p&gt;


&lt;strong&gt;9. Don&amp;#8217;t forget&amp;#8230;&lt;/strong&gt;
	&lt;ul&gt;
	&lt;li&gt;If you&amp;#8217;re like me, you may be dealing with 2 records &amp;#8211; a record authenticated via the subdomain and a user authenticated and placed in the session. Don&amp;#8217;t forget to ensure that the user in the session has access to the subdomain record.&lt;/li&gt;
		&lt;li&gt;Remove the entries we added to &lt;code&gt;/etc/hosts&lt;/code&gt; before your site launches.&lt;/li&gt;
		&lt;li&gt;Setup your real &lt;span class="caps"&gt;DNS&lt;/span&gt; server with a &lt;span class="caps"&gt;CNAME&lt;/span&gt; or other wildcard entry and your webserver of choice with the same wildcard mapping for your application.&lt;/li&gt;
	&lt;/ul&gt;


	&lt;p&gt;That&amp;#8217;s it! It&amp;#8217;s another &amp;#8220;why I love Rails&amp;#8221; moment &amp;#8211; subdomain-as-account-key functionality in 30 lines of code tested and ready for production.&lt;/p&gt;


	&lt;p&gt;&lt;strong&gt;P.S.&lt;/strong&gt;
&lt;a href="http://heartbeat.highgroove.com"&gt;Heartbeat&lt;/a&gt;, our Ruby on Rails control panel built during &lt;a href="http://www.railsday2006.com"&gt;RailsDay 2006&lt;/a&gt;, is getting ready to emerge with some very powerful new features. Videos to come late this week.&lt;/p&gt;</description>
      <pubDate>Mon, 14 Aug 2006 20:27:00 EST</pubDate>
      <guid>&lt;a href="/articles/2006/08/14/simplied-subdomain-authentication-in-ruby-on-rails"&gt;Simple Subdomain Authentication In Ruby on Rails&lt;/a&gt;</guid>
      <link>&lt;a href="/articles/2006/08/14/simplied-subdomain-authentication-in-ruby-on-rails"&gt;Simple Subdomain Authentication In Ruby on Rails&lt;/a&gt;</link>
    </item>
  </channel>
</rss>
