<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">

 <title>Artur Roszczyk</title>
 <link href="http://sevos.github.com/atom.xml" rel="self"/>
 <link href="http://sevos.github.com/"/>
 <updated>2013-08-12T11:22:50-07:00</updated>
 <id>http://sevos.github.com/</id>
 <author>
   <name>Artur Roszczyk</name>
   <email>artur.roszczyk+blog@gmail.com</email>
 </author>

 
 <entry>
   <title>Subscription tracking in Sendgrid and Rails 4</title>
   <link href="http://sevos.github.com/2013/08/03/sendgrid-and-rails-4.html"/>
   <updated>2013-08-03T00:00:00-07:00</updated>
   <id>http://sevos.github.com/2013/08/03/sendgrid-and-rails-4</id>
   <content type="html">&lt;h1 id='subscription_tracking_in_sendgrid_and_rails_4'&gt;Subscription tracking in Sendgrid and Rails 4&lt;/h1&gt;

&lt;p&gt;Few days ago I extracted mailer classes out of our monolith app. I created a new, small Rails 4 application which consumes RabbitMQ queue and sends emails to users. We use Sendgrid&amp;#8217;s subscription tracking. We use particularly a placeholder, which Sendgrid replaces by unsubscription url.&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;  &lt;span class='c1'&gt;# in mailer&lt;/span&gt;

  &lt;span class='n'&gt;sendgrid_subscriptiontrack_text&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='ss'&gt;:replace&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;[unsubscribe]&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;

  &lt;span class='c1'&gt;# in template&lt;/span&gt;

  &lt;span class='o'&gt;&amp;lt;&lt;/span&gt;&lt;span class='n'&gt;a&lt;/span&gt; &lt;span class='n'&gt;href&lt;/span&gt;&lt;span class='o'&gt;=&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;\[unsubscribe\]&amp;quot;&lt;/span&gt;&lt;span class='o'&gt;&amp;gt;&lt;/span&gt;&lt;span class='n'&gt;click&lt;/span&gt; &lt;span class='n'&gt;here&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;&amp;lt;&lt;/span&gt;&lt;span class='sr'&gt;/a&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The problem was, that the placeholder &lt;em&gt;[unsubscribe]&lt;/em&gt; was replaced by a bogus URL like &lt;code&gt;x-msg://447/\[unsubscribe\]&lt;/code&gt;. It turns out, that Rails 4 encodes automatically all URLs in emails.&lt;/p&gt;

&lt;h2 id='the_fix'&gt;The fix&lt;/h2&gt;

&lt;p&gt;Sendgrid does not decode these URLs, so I needed to encode the placeholder.&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;  &lt;span class='c1'&gt;# in mailer&lt;/span&gt;

  &lt;span class='n'&gt;sendgrid_subscriptiontrack_text&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='ss'&gt;:replace&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;%5Bunsubscribe%5D&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I hope that this will save you some time.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>New Year's resolutions</title>
   <link href="http://sevos.github.com/2013/01/01/resolutions.html"/>
   <updated>2013-01-01T00:00:00-08:00</updated>
   <id>http://sevos.github.com/2013/01/01/resolutions</id>
   <content type="html">&lt;h1 id='new_years_resolutions'&gt;New Year&amp;#8217;s resolutions&lt;/h1&gt;

&lt;p&gt;It&amp;#8217;s common to say, that resolutions made at beggining of year just don&amp;#8217;t work. Although I would like to set directions of improving myself for coming year. I hope to revisit them by end of 2013 ;-).&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;pay off debts&lt;/li&gt;

&lt;li&gt;establish security savings&lt;/li&gt;

&lt;li&gt;have true vacation&lt;/li&gt;

&lt;li&gt;write more&lt;/li&gt;

&lt;li&gt;spend more time with family&lt;/li&gt;

&lt;li&gt;shift from 8am-1am day to 6am-22pm day&lt;/li&gt;

&lt;li&gt;quit tv-series addiction&lt;/li&gt;

&lt;li&gt;start doing some sport&lt;/li&gt;
&lt;/ul&gt;</content>
 </entry>
 
 <entry>
   <title>Basics of fog and AWS for Rails apps</title>
   <link href="http://sevos.github.com/2012/12/31/basics-of-fog-and-aws-for-rails-apps.html"/>
   <updated>2012-12-31T00:00:00-08:00</updated>
   <id>http://sevos.github.com/2012/12/31/basics-of-fog-and-aws-for-rails-apps</id>
   <content type="html">&lt;h1 id='basics_of_fog_and_aws_for_rails_apps'&gt;Basics of fog and AWS for Rails apps&lt;/h1&gt;

&lt;p&gt;All successful projects grow. In the beginning we usually don&amp;#8217;t care about scalability so much. The need of it comes often suddenly. You cannot predict effects of being advertised on popular blog or going viral. Then you need to scale up to serve the traffic.&lt;/p&gt;

&lt;p&gt;There are many options to fix this. You can start with Heroku, but you might need more flexibility later and move to bare servers on Hetzner. And Hetzner might be a fit for you for several months. But suddenly you meet server&amp;#8217;s limits, like we did recently, and you have to decide whether to buy another metal or go back into the cloud. Buying second server has own pitfalls and might be tricky to maintain. Amazon&amp;#8217;s EC2 might be an option, but manual management might be annoying (it was to me).&lt;/p&gt;

&lt;p&gt;Here I wan&amp;#8217;t to show you, how to manage EC2 instances using &lt;a href='http://fog.io/'&gt;fog&lt;/a&gt;. I believe that crafting own, custom solution for such thing is good idea, because you can expect to have effects pretty fast.&lt;/p&gt;

&lt;p&gt;In following posts I want to share knowledge which should help you to establish own toolset for managing your own mini-cloud based on AWS.&lt;/p&gt;

&lt;h2 id='goals'&gt;Goals&lt;/h2&gt;

&lt;p&gt;Each a little larger application can be divided into some logic parts, which might need to scale. In case of our app I&amp;#8217;d do following split:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;web workers&lt;/li&gt;

&lt;li&gt;email workers (sending emails in background)&lt;/li&gt;

&lt;li&gt;other background job workers&lt;/li&gt;

&lt;li&gt;PostgreSQL&lt;/li&gt;

&lt;li&gt;memcache&lt;/li&gt;

&lt;li&gt;redis&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In the beginning we will focus on scaling web and background workers. Problems with scaling databases come later, so we will deal with them in following posts.&lt;/p&gt;

&lt;h2 id='project_setup'&gt;Project setup&lt;/h2&gt;

&lt;p&gt;For our custom tool we will use Thor. It’s nicer than Rake and have more feature while it doesn’t have odd DSL in favor of ruby classes. Let’s create a project!&lt;/p&gt;
&lt;pre class='terminal'&gt;&lt;code&gt;
$ cd ~ &amp;amp;&amp;amp; mkdir -p projects/mycloud
$ cd projects/mycloud

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I use RVM, so I’ll setup RVM gemset:&lt;/p&gt;
&lt;pre class='terminal'&gt;&lt;code&gt;
$ rvm use 1.9.3-p327@mycloud --create
$ echo &quot;rvm 1.9.3-p327@mycloud --create&quot; &gt; .rvmrc

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I like bundler:&lt;/p&gt;
&lt;pre class='terminal'&gt;&lt;code&gt;
$ gem install bundler
$ bundle init

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We need to install thor and fog, so put them into &lt;code&gt;Gemfile&lt;/code&gt; and do &lt;code&gt;bundle install&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Let’s test thor. Create a &lt;code&gt;node.thor&lt;/code&gt; file:&lt;/p&gt;
&lt;pre class='terminal'&gt;&lt;code&gt;
$ mkdir -p lib/tasks
$ touch lib/tasks/node.thor

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here is content for &lt;code&gt;node.thor&lt;/code&gt; file:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='k'&gt;class&lt;/span&gt; &lt;span class='nc'&gt;Node&lt;/span&gt; &lt;span class='o'&gt;&amp;lt;&lt;/span&gt; &lt;span class='no'&gt;Thor&lt;/span&gt;
  &lt;span class='n'&gt;desc&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;up&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;Creates an instance&amp;quot;&lt;/span&gt;
  &lt;span class='k'&gt;def&lt;/span&gt; &lt;span class='nf'&gt;up&lt;/span&gt;
    &lt;span class='nb'&gt;puts&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;Instance created&amp;quot;&lt;/span&gt;
  &lt;span class='k'&gt;end&lt;/span&gt;
&lt;span class='k'&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;You can easily test it in the terminal:&lt;/p&gt;
&lt;pre class='terminal'&gt;&lt;code&gt;
$ thor node:up
Instance created
$

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And that&amp;#8217;s it. We have simple project ready to grow.&lt;/p&gt;

&lt;h2 id='configuration'&gt;Configuration&lt;/h2&gt;

&lt;p&gt;Our first task would be to boot an instance and ensure it&amp;#8217;s connectivity. Before that we need to prepare configuration.&lt;/p&gt;

&lt;h3 id='ssh_keys'&gt;SSH keys&lt;/h3&gt;

&lt;p&gt;Go to &lt;a href='https://console.aws.amazon.com/ec2/home?region=eu-west-1#s=KeyPairs'&gt;Key Pairs section of Management Console&lt;/a&gt; (warning: link leads to EU West 1 zone!) and create new key pair. You will be prompted for name for keypair. Keys are created on per-region basis. My convention is to provide region name followed by user name (&lt;code&gt;euwest1_sevos&lt;/code&gt; in my case).&lt;/p&gt;

&lt;p&gt;Download your private key (I will use &lt;code&gt;euwest1_sevos.pem&lt;/code&gt; as key file name) and place it in &lt;code&gt;config/keys/&lt;/code&gt; directory in our project. Remember to change rights to the key file to 600:&lt;/p&gt;
&lt;pre class='terminal'&gt;&lt;code&gt;
$ chmod 600 config/keys/*

&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id='credentialsyml'&gt;credentials.yml&lt;/h3&gt;

&lt;p&gt;Go &lt;a href='https://portal.aws.amazon.com/gp/aws/securityCredentials'&gt;here&lt;/a&gt; and scroll to &lt;em&gt;Access Credentials&lt;/em&gt; section. Grab AccessKey ID and Secret Access Key. We will need those to make API calls to AWS.&lt;/p&gt;

&lt;p&gt;Create &lt;code&gt;config/credentials.yml&lt;/code&gt; file for our credentials and commons:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='yaml'&gt;&lt;span class='l-Scalar-Plain'&gt;aws_access_key_id&lt;/span&gt;&lt;span class='p-Indicator'&gt;:&lt;/span&gt; &lt;span class='l-Scalar-Plain'&gt;&amp;lt;your access key id&amp;gt;&lt;/span&gt;
&lt;span class='l-Scalar-Plain'&gt;aws_secret_access_key&lt;/span&gt;&lt;span class='p-Indicator'&gt;:&lt;/span&gt; &lt;span class='l-Scalar-Plain'&gt;&amp;lt;your secret access key&amp;gt;&lt;/span&gt;
&lt;span class='l-Scalar-Plain'&gt;region&lt;/span&gt;&lt;span class='p-Indicator'&gt;:&lt;/span&gt; &lt;span class='l-Scalar-Plain'&gt;eu-west-1&lt;/span&gt;
&lt;span class='l-Scalar-Plain'&gt;key_name&lt;/span&gt;&lt;span class='p-Indicator'&gt;:&lt;/span&gt; &lt;span class='l-Scalar-Plain'&gt;euwest1_sevos&lt;/span&gt;
&lt;span class='l-Scalar-Plain'&gt;ami&lt;/span&gt;&lt;span class='p-Indicator'&gt;:&lt;/span&gt; &lt;span class='s'&gt;&amp;#39;ami-c1aaabb5&amp;#39;&lt;/span&gt;
&lt;span class='l-Scalar-Plain'&gt;instance_type&lt;/span&gt;&lt;span class='p-Indicator'&gt;:&lt;/span&gt; &lt;span class='s'&gt;&amp;#39;t1.micro&amp;#39;&lt;/span&gt;
&lt;span class='l-Scalar-Plain'&gt;security_group_name&lt;/span&gt;&lt;span class='p-Indicator'&gt;:&lt;/span&gt; &lt;span class='s'&gt;&amp;#39;mycloud&amp;#39;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now, we can use these data to manage instances.&lt;/p&gt;

&lt;h4 id='on_ami'&gt;On AMI&lt;/h4&gt;

&lt;p&gt;I use current (as of writing this article) Ubuntu 12.04 64-bit AMI from EU West datacenter&lt;/p&gt;

&lt;h4 id='on_security_group'&gt;On security group&lt;/h4&gt;

&lt;p&gt;Amazon uses security groups to protect instances from unwanted traffic. For sake of simplicity let&amp;#8217;s create one security group opening port 22 (SSH) for world. Go to &lt;a href='https://console.aws.amazon.com/ec2/home?region=eu-west-1#s=SecurityGroups'&gt;Security Groups&lt;/a&gt; and crete new group. Name it &lt;code&gt;mycloud&lt;/code&gt; or whatever you&amp;#8217;ll use later as &lt;code&gt;security_group_name&lt;/code&gt;, provide description and leave VPC setting unchanged.&lt;/p&gt;

&lt;p&gt;After creating security group set it up for accepting SSH connection.&lt;/p&gt;

&lt;p&gt;&lt;img alt='The Passionate Programmer book' src='/img/2012/12/31/basics-of-fog-and-aws-for-rails-apps/security-group-setup.png' /&gt;&lt;/p&gt;

&lt;p&gt;Remember to click &lt;em&gt;Add Rule&lt;/em&gt; and apply changes!&lt;/p&gt;

&lt;h2 id='booting_an_instance'&gt;Booting an instance&lt;/h2&gt;

&lt;p&gt;Let&amp;#8217;s edit &lt;code&gt;up&lt;/code&gt; method and do some magic!&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='nb'&gt;require&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;yaml&amp;#39;&lt;/span&gt;
&lt;span class='nb'&gt;require&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;fog&amp;#39;&lt;/span&gt;

&lt;span class='k'&gt;class&lt;/span&gt; &lt;span class='nc'&gt;Node&lt;/span&gt; &lt;span class='o'&gt;&amp;lt;&lt;/span&gt; &lt;span class='no'&gt;Thor&lt;/span&gt;
  &lt;span class='n'&gt;desc&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;up NAME&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;Creates an instance&amp;quot;&lt;/span&gt;
  &lt;span class='k'&gt;def&lt;/span&gt; &lt;span class='nf'&gt;up&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;instance_name&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
    &lt;span class='n'&gt;server&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='n'&gt;compute&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;servers&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;create&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;
        &lt;span class='n'&gt;image_id&lt;/span&gt;&lt;span class='p'&gt;:&lt;/span&gt;         &lt;span class='n'&gt;config&lt;/span&gt;&lt;span class='o'&gt;[&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;ami&amp;#39;&lt;/span&gt;&lt;span class='o'&gt;]&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;
        &lt;span class='n'&gt;flavor_id&lt;/span&gt;&lt;span class='p'&gt;:&lt;/span&gt;        &lt;span class='n'&gt;config&lt;/span&gt;&lt;span class='o'&gt;[&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;instance_type&amp;#39;&lt;/span&gt;&lt;span class='o'&gt;]&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;
        &lt;span class='n'&gt;key_name&lt;/span&gt;&lt;span class='p'&gt;:&lt;/span&gt;         &lt;span class='n'&gt;config&lt;/span&gt;&lt;span class='o'&gt;[&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;key_name&amp;#39;&lt;/span&gt;&lt;span class='o'&gt;]&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;
        &lt;span class='ss'&gt;tags&lt;/span&gt;&lt;span class='p'&gt;:&lt;/span&gt;             &lt;span class='p'&gt;{&lt;/span&gt;
                            &lt;span class='s1'&gt;&amp;#39;Name&amp;#39;&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='n'&gt;instance_name&lt;/span&gt;
                          &lt;span class='p'&gt;},&lt;/span&gt;
        &lt;span class='ss'&gt;groups&lt;/span&gt;&lt;span class='p'&gt;:&lt;/span&gt;           &lt;span class='n'&gt;config&lt;/span&gt;&lt;span class='o'&gt;[&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;security_group_name&amp;#39;&lt;/span&gt;&lt;span class='o'&gt;]&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;
        &lt;span class='n'&gt;private_key_path&lt;/span&gt;&lt;span class='p'&gt;:&lt;/span&gt; &lt;span class='n'&gt;private_key_path&lt;/span&gt;
    &lt;span class='p'&gt;)&lt;/span&gt;

    &lt;span class='n'&gt;server&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;wait_for&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt;
      &lt;span class='n'&gt;ready?&lt;/span&gt;
    &lt;span class='k'&gt;end&lt;/span&gt;

    &lt;span class='n'&gt;say&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;Instance ready. You can connect to it using following command:&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='ss'&gt;:green&lt;/span&gt;
    &lt;span class='n'&gt;say&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;  ssh -i &lt;/span&gt;&lt;span class='si'&gt;#{&lt;/span&gt;&lt;span class='n'&gt;private_key_path&lt;/span&gt;&lt;span class='si'&gt;}&lt;/span&gt;&lt;span class='s2'&gt; ubuntu@&lt;/span&gt;&lt;span class='si'&gt;#{&lt;/span&gt;&lt;span class='n'&gt;server&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;dns_name&lt;/span&gt;&lt;span class='si'&gt;}&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;&lt;/span&gt;
  &lt;span class='k'&gt;end&lt;/span&gt;

  &lt;span class='kp'&gt;private&lt;/span&gt;

  &lt;span class='k'&gt;def&lt;/span&gt; &lt;span class='nf'&gt;compute&lt;/span&gt;
    &lt;span class='vi'&gt;@compute&lt;/span&gt; &lt;span class='o'&gt;||=&lt;/span&gt; &lt;span class='ss'&gt;Fog&lt;/span&gt;&lt;span class='p'&gt;:&lt;/span&gt;&lt;span class='ss'&gt;:Compute&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;new&lt;/span&gt; &lt;span class='ss'&gt;provider&lt;/span&gt;&lt;span class='p'&gt;:&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;AWS&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;
                                  &lt;span class='ss'&gt;region&lt;/span&gt;&lt;span class='p'&gt;:&lt;/span&gt; &lt;span class='n'&gt;config&lt;/span&gt;&lt;span class='o'&gt;[&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;region&amp;#39;&lt;/span&gt;&lt;span class='o'&gt;]&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;
                                  &lt;span class='n'&gt;aws_access_key_id&lt;/span&gt;&lt;span class='p'&gt;:&lt;/span&gt; &lt;span class='n'&gt;config&lt;/span&gt;&lt;span class='o'&gt;[&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;aws_access_key_id&amp;#39;&lt;/span&gt;&lt;span class='o'&gt;]&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;
                                  &lt;span class='n'&gt;aws_secret_access_key&lt;/span&gt;&lt;span class='p'&gt;:&lt;/span&gt; &lt;span class='n'&gt;config&lt;/span&gt;&lt;span class='o'&gt;[&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;aws_secret_access_key&amp;#39;&lt;/span&gt;&lt;span class='o'&gt;]&lt;/span&gt;
  &lt;span class='k'&gt;end&lt;/span&gt;

  &lt;span class='k'&gt;def&lt;/span&gt; &lt;span class='nf'&gt;config&lt;/span&gt;
    &lt;span class='vi'&gt;@config&lt;/span&gt; &lt;span class='o'&gt;||=&lt;/span&gt; &lt;span class='no'&gt;YAML&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;load&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='no'&gt;File&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;read&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='no'&gt;File&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;join&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;config&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;credentials.yml&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;)))&lt;/span&gt;
  &lt;span class='k'&gt;end&lt;/span&gt;

  &lt;span class='k'&gt;def&lt;/span&gt; &lt;span class='nf'&gt;private_key_path&lt;/span&gt;
    &lt;span class='no'&gt;File&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;expand_path&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='no'&gt;File&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;join&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;config&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;keys&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;&lt;/span&gt;&lt;span class='si'&gt;#{&lt;/span&gt;&lt;span class='n'&gt;config&lt;/span&gt;&lt;span class='o'&gt;[&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;key_name&amp;#39;&lt;/span&gt;&lt;span class='o'&gt;]&lt;/span&gt;&lt;span class='si'&gt;}&lt;/span&gt;&lt;span class='s2'&gt;.pem&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;))&lt;/span&gt;
  &lt;span class='k'&gt;end&lt;/span&gt;
&lt;span class='k'&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3 id='testing'&gt;Testing&lt;/h3&gt;

&lt;p&gt;Now it&amp;#8217;s time to check our code. Type in the console:&lt;/p&gt;
&lt;pre class='terminal'&gt;&lt;code&gt;
$ thor node:up blog

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;After several seconds you should see similar message:&lt;/p&gt;
&lt;pre class='terminal'&gt;&lt;code&gt;
Instance ready. You can connect to it using following command:
ssh -i /Users/sevos/Projects/mycloud/config/keys/euwest1_sevos.pem
ubuntu@ec2-79-125-87-82.eu-west-1.compute.amazonaws.com

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Just copy the SSH command and try to connect to the server. Note that even if server seems to be ready, sshd server might be not up yet. Just wait few seconds and try again.&lt;/p&gt;

&lt;h2 id='summary'&gt;Summary&lt;/h2&gt;

&lt;p&gt;That&amp;#8217;s it for today. Turn off instance manually using AWS Console. Select an instance and from Actions menu select Terminate command.&lt;/p&gt;

&lt;p&gt;We prepared a thor task for creating AWS instance from an AMI image. We still need some role-system, since we don&amp;#8217;t care about single instance.&lt;/p&gt;

&lt;p&gt;In next posts I will write also about provisioning and grouping instances.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Failing PostgreSQL on OS X</title>
   <link href="http://sevos.github.com/2012/09/17/failing-postgresql-on-os-x.html"/>
   <updated>2012-09-17T00:00:00-07:00</updated>
   <id>http://sevos.github.com/2012/09/17/failing-postgresql-on-os-x</id>
   <content type="html">&lt;h1 id='failing_postgresql_on_os_x'&gt;Failing PostgreSQL on OS X&lt;/h1&gt;

&lt;p&gt;Today there will be only quick tip. Have you ever come back to work on monday and seen following error after lanunching your Rails development:&lt;/p&gt;
&lt;pre class='terminal'&gt;
&lt;code&gt;
could not connect to server: Connection refused (PG::Error)
        Is the server running on host &quot;localhost&quot; (::1) and accepting
        TCP/IP connections on port 5432?
could not connect to server: Connection refused
        Is the server running on host &quot;localhost&quot; (127.0.0.1) and accepting
        TCP/IP connections on port 5432?
could not connect to server: Connection refused
        Is the server running on host &quot;localhost&quot; (fe80::1) and accepting
        TCP/IP connections on port 5432?
&lt;/code&gt;
&lt;/pre&gt;
&lt;p&gt;If you installed PostgreSQL via homebrew, you might want try removing postmaster.pid, what helped me:&lt;/p&gt;
&lt;pre class='terminal'&gt;
&lt;code&gt;
rm /usr/local/var/postgres/postmaster.pid
&lt;/code&gt;
&lt;/pre&gt;</content>
 </entry>
 
 <entry>
   <title>Separate your concerns</title>
   <link href="http://sevos.github.com/2012/01/13/separate-your-concerns.html"/>
   <updated>2012-01-13T00:00:00-08:00</updated>
   <id>http://sevos.github.com/2012/01/13/separate-your-concerns</id>
   <content type="html">&lt;h1 id='separate_your_concerns'&gt;Separate your concerns&lt;/h1&gt;

&lt;p&gt;&lt;em&gt;This post is written in response to &lt;a href='http://robots.thoughtbot.com/post/1986730994/keep-your-privates-close'&gt;Keep your privates close&lt;/a&gt; of Thoughtbot&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;At the beginning I must admit that previously I have never thought, that we could use private keyword in THIS way. First time I met this approach in my new outsourced project with code written by former devs. When I opened random file, I saw ugliness written in following style:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='k'&gt;class&lt;/span&gt; &lt;span class='nc'&gt;User&lt;/span&gt; &lt;span class='o'&gt;&amp;lt;&lt;/span&gt; &lt;span class='ss'&gt;ActiveRecord&lt;/span&gt;&lt;span class='p'&gt;:&lt;/span&gt;&lt;span class='ss'&gt;:Base&lt;/span&gt;
  &lt;span class='n'&gt;has_many&lt;/span&gt; &lt;span class='ss'&gt;:tickets&lt;/span&gt;
  &lt;span class='n'&gt;has_many&lt;/span&gt; &lt;span class='ss'&gt;:events&lt;/span&gt;

  &lt;span class='c1'&gt;# -------------------------------------&lt;/span&gt;
  &lt;span class='c1'&gt;# Recent tickets&lt;/span&gt;
  &lt;span class='c1'&gt;# -------------------------------------&lt;/span&gt;
  &lt;span class='k'&gt;def&lt;/span&gt; &lt;span class='nf'&gt;most_recent_ticket&lt;/span&gt;
    &lt;span class='c1'&gt;# huh, obviously code here&lt;/span&gt;
  &lt;span class='k'&gt;end&lt;/span&gt;

  &lt;span class='k'&gt;def&lt;/span&gt; &lt;span class='nf'&gt;recent_tickets&lt;/span&gt;

  &lt;span class='k'&gt;end&lt;/span&gt;
  &lt;span class='kp'&gt;private&lt;/span&gt; &lt;span class='ss'&gt;:recent_tickets&lt;/span&gt;

  &lt;span class='c1'&gt;# more public and private methods&lt;/span&gt;
  &lt;span class='c1'&gt;# …&lt;/span&gt;

  &lt;span class='c1'&gt;# -------------------------------------&lt;/span&gt;
  &lt;span class='c1'&gt;# API Keys&lt;/span&gt;
  &lt;span class='c1'&gt;# -------------------------------------&lt;/span&gt;
  &lt;span class='n'&gt;after_create&lt;/span&gt; &lt;span class='ss'&gt;:create_api_keys&lt;/span&gt;

  &lt;span class='k'&gt;def&lt;/span&gt; &lt;span class='nf'&gt;create_api_keys&lt;/span&gt;

  &lt;span class='k'&gt;end&lt;/span&gt;
  &lt;span class='kp'&gt;private&lt;/span&gt; &lt;span class='ss'&gt;:create_api_keys&lt;/span&gt;

  &lt;span class='k'&gt;def&lt;/span&gt; &lt;span class='nf'&gt;random_key&lt;/span&gt;

  &lt;span class='k'&gt;end&lt;/span&gt;
  &lt;span class='kp'&gt;private&lt;/span&gt; &lt;span class='ss'&gt;:random_key&lt;/span&gt;
&lt;span class='k'&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I hope, you&amp;#8217;ve got the idea. When I asked why do we need to follow this convention, I&amp;#8217;ve got answer that this solves problem of vertical distance between public and private methods related to each other. It was surprise for me, because usually I put &lt;code&gt;FIXME&lt;/code&gt; comment in large files.&lt;/p&gt;

&lt;p&gt;During discussion my opponent sent me a link to the mentioned blog post from Thoughtbot. After reading it I must agree with author at one point.&lt;/p&gt;

&lt;h2 id='vertical_distance_is_bad'&gt;Vertical distance is bad&lt;/h2&gt;

&lt;p&gt;First programs ever written had mostly one file. Developers were helping themselves by separating code with comments. Later file inclusion has been introduced enabling developers to split code into several files. Then came functions, namespaces, classes and modules. Everything what makes the code more readable and beautiful.&lt;/p&gt;

&lt;p&gt;It is not only about look&amp;amp;feel. The code, we write, should be maintainable.&lt;/p&gt;

&lt;p&gt;Someone said once that you should always keep in mind that developer coming after you is psychopath, who knows, where do you live. It might be just you, after few months. Making code maintainable reduces costs of project. It&amp;#8217;s okay to not care about that when prototyping, but is not when you write a real project, especially an for external client.&lt;/p&gt;

&lt;h2 id='lets_get_to_the_point'&gt;Let&amp;#8217;s get to the point&lt;/h2&gt;

&lt;p&gt;The need of grouping methods together exposes something to us. Usually we group them by some concern, which corresponds to &lt;em&gt;a part&lt;/em&gt; of object&amp;#8217;s responsibilities. This mean that object, when realizing those responsibilities, plays a role in our system. Yea, I know, you may think now, that I am next guy selling &lt;a href='http://en.wikipedia.org/wiki/Data,_Context,_and_Interaction'&gt;DCI&lt;/a&gt; or some other pattern. DCI is in fact quite nice solution, but I really don&amp;#8217;t care how do you split your code, unless it is technique from previous century.&lt;/p&gt;

&lt;p&gt;When your class is getting bigger, you can easily extract concerns into separate module. Your main file becomes a list of contents. First step of refactoring of example above would be following:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='c1'&gt;# app/models/user.rb&lt;/span&gt;
&lt;span class='k'&gt;class&lt;/span&gt; &lt;span class='nc'&gt;User&lt;/span&gt; &lt;span class='o'&gt;&amp;lt;&lt;/span&gt; &lt;span class='ss'&gt;ActiveRecord&lt;/span&gt;&lt;span class='p'&gt;:&lt;/span&gt;&lt;span class='ss'&gt;:Base&lt;/span&gt;
  &lt;span class='kp'&gt;include&lt;/span&gt; &lt;span class='no'&gt;Tickets&lt;/span&gt;
  &lt;span class='kp'&gt;include&lt;/span&gt; &lt;span class='no'&gt;ApiKeys&lt;/span&gt;

  &lt;span class='n'&gt;has_many&lt;/span&gt; &lt;span class='ss'&gt;:events&lt;/span&gt;
&lt;span class='k'&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='c1'&gt;# app/models/user/tickets.rb&lt;/span&gt;
&lt;span class='k'&gt;module&lt;/span&gt; &lt;span class='nn'&gt;User::Tickets&lt;/span&gt;
  &lt;span class='kp'&gt;extend&lt;/span&gt; &lt;span class='ss'&gt;ActiveSupport&lt;/span&gt;&lt;span class='p'&gt;:&lt;/span&gt;&lt;span class='ss'&gt;:Concern&lt;/span&gt;

  &lt;span class='n'&gt;included&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt;
    &lt;span class='n'&gt;has_many&lt;/span&gt; &lt;span class='ss'&gt;:tickets&lt;/span&gt;
  &lt;span class='k'&gt;end&lt;/span&gt;

  &lt;span class='k'&gt;def&lt;/span&gt; &lt;span class='nf'&gt;most_recent_ticket&lt;/span&gt;
    &lt;span class='c1'&gt;# huh, obviously code here&lt;/span&gt;
  &lt;span class='k'&gt;end&lt;/span&gt;

  &lt;span class='kp'&gt;private&lt;/span&gt;
    &lt;span class='k'&gt;def&lt;/span&gt; &lt;span class='nf'&gt;recent_tickets&lt;/span&gt;

    &lt;span class='k'&gt;end&lt;/span&gt;
&lt;span class='k'&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='c1'&gt;# app/models/user/api_keys.rb&lt;/span&gt;
&lt;span class='k'&gt;module&lt;/span&gt; &lt;span class='nn'&gt;User::ApiKeys&lt;/span&gt;
  &lt;span class='kp'&gt;extend&lt;/span&gt; &lt;span class='ss'&gt;ActiveSupport&lt;/span&gt;&lt;span class='p'&gt;:&lt;/span&gt;&lt;span class='ss'&gt;:Concern&lt;/span&gt;

  &lt;span class='n'&gt;included&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt;
    &lt;span class='n'&gt;after_create&lt;/span&gt; &lt;span class='ss'&gt;:create_api_keys&lt;/span&gt;
  &lt;span class='k'&gt;end&lt;/span&gt;

  &lt;span class='kp'&gt;private&lt;/span&gt;
    &lt;span class='k'&gt;def&lt;/span&gt; &lt;span class='nf'&gt;create_api_keys&lt;/span&gt;

    &lt;span class='k'&gt;end&lt;/span&gt;

    &lt;span class='k'&gt;def&lt;/span&gt; &lt;span class='nf'&gt;random_key&lt;/span&gt;

    &lt;span class='k'&gt;end&lt;/span&gt;
&lt;span class='k'&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;For me it is much better. Please note that this approach is in early stage and few things should be discussed, like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;should we use &lt;code&gt;ActiveSupport::Concern&lt;/code&gt; and extract relations to modules?&lt;/li&gt;

&lt;li&gt;should we include at class&amp;#8217; level or extend on object&amp;#8217;s level? (Personally if comes to AR classes I preffer includes - I agree that &lt;a href='http://andrzejonsoftware.blogspot.com/2012/01/dci-and-rails-lessons-learnt.html'&gt;DCI at AR level is wrong&lt;/a&gt;)&lt;/li&gt;

&lt;li&gt;how we deal with common code?&lt;/li&gt;

&lt;li&gt;how to deal with &lt;code&gt;load_missing_constant&lt;/code&gt; ambiguous behaviour?&lt;br /&gt;It happens when you name your nested models like classes or modules being visible in global scope, consider &lt;code&gt;User::Ticket&lt;/code&gt; and &lt;code&gt;Ticket&lt;/code&gt;. Rails somehow fallbacks to &lt;code&gt;::Ticket&lt;/code&gt; when including &lt;code&gt;User::Ticket&lt;/code&gt;. I bypass this by writing &lt;code&gt;require_relative &amp;#39;user/ticket&amp;#39; and include User::Ticket&lt;/code&gt;. I know, it is not perfect but good enough for now.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id='whats_next'&gt;What&amp;#8217;s next?&lt;/h2&gt;

&lt;p&gt;Often we get to the point, when a model in our projects grows too big. We did tend always to follow &lt;a href='http://weblog.jamisbuck.org/2006/10/18/skinny-controller-fat-model'&gt;Skinny controller, fat model principle&lt;/a&gt;, but models have got extremely big - I saw files with 300 LoC, who bids more? Of course, we can live with that. We can also live without dishwashers and RSS (both are big time savers to me).&lt;/p&gt;

&lt;p&gt;After separating your concerns, you may discover that persistence is also a concern. This will change the way you think about domain models drastically. I haven&amp;#8217;t get to this point or/and I am not brave enough yet to experiment with PORO models in projects for external clients, but for sure I will give it a try in my next side-project. However this is topic for next post ;-).&lt;/p&gt;

&lt;p&gt;Some of you may think, why bother? Ruby is beautiful. Most of use came here from Java, PHP and other languages. Ruby let us express our thoughts easier than many of them. Let&amp;#8217;s don&amp;#8217;t break this with ugly spaghetti code. Don&amp;#8217;t go back.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>DCI doubts</title>
   <link href="http://sevos.github.com/2011/10/06/dci-doubts.html"/>
   <updated>2011-10-06T00:00:00-07:00</updated>
   <id>http://sevos.github.com/2011/10/06/dci-doubts</id>
   <content type="html">&lt;h1 id='dci_doubts'&gt;DCI doubts&lt;/h1&gt;

&lt;blockquote&gt;
&lt;p&gt;Background: &lt;em&gt;I am working on an application which brings new user interface for legacy system used by customer. There is basic model in the legacy system: Department. My customer wants to see several statistics related to each of his departments. That&amp;#8217;s my duty.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;As I started modelling business domain in my app I wanted to keep things as simple as possible. I wanted also try out DCI finally. Time had come ;-)&lt;/p&gt;

&lt;p&gt;My first idea was to create Department model and let it to play roles in the app (bad idea, but keep reading):&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='k'&gt;class&lt;/span&gt; &lt;span class='nc'&gt;Department&lt;/span&gt; &lt;span class='o'&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class='ss'&gt;ActiveRecord&lt;/span&gt;&lt;span class='p'&gt;:&lt;/span&gt;&lt;span class='ss'&gt;:Base&lt;/span&gt;
&lt;span class='k'&gt;end&lt;/span&gt;

&lt;span class='k'&gt;class&lt;/span&gt; &lt;span class='nc'&gt;DepartmentsController&lt;/span&gt;
  &lt;span class='k'&gt;def&lt;/span&gt; &lt;span class='nf'&gt;update_stock_value&lt;/span&gt;
    &lt;span class='n'&gt;stock&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='no'&gt;Department&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;find&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;params&lt;/span&gt;&lt;span class='o'&gt;[&lt;/span&gt;&lt;span class='ss'&gt;:id&lt;/span&gt;&lt;span class='o'&gt;]&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;extend&lt;/span&gt; &lt;span class='ss'&gt;Roles&lt;/span&gt;&lt;span class='p'&gt;:&lt;/span&gt;&lt;span class='ss'&gt;:Stock&lt;/span&gt;
    &lt;span class='n'&gt;stock&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;update&lt;/span&gt;
  &lt;span class='k'&gt;end&lt;/span&gt;
&lt;span class='k'&gt;end&lt;/span&gt;

&lt;span class='k'&gt;module&lt;/span&gt; &lt;span class='nn'&gt;Roles&lt;/span&gt;
  &lt;span class='k'&gt;module&lt;/span&gt; &lt;span class='nn'&gt;Stock&lt;/span&gt;
    &lt;span class='k'&gt;def&lt;/span&gt; &lt;span class='nf'&gt;update&lt;/span&gt;
      &lt;span class='c1'&gt;# fetch value from external application and store&lt;/span&gt;
    &lt;span class='k'&gt;end&lt;/span&gt;

    &lt;span class='k'&gt;def&lt;/span&gt; &lt;span class='nf'&gt;value&lt;/span&gt;
      &lt;span class='n'&gt;stock_value&lt;/span&gt;
    &lt;span class='k'&gt;end&lt;/span&gt;
  &lt;span class='k'&gt;end&lt;/span&gt;
&lt;span class='k'&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;However I realized that there was something missing. Obviously there was missing a relation that Department certainly has one Stock. Just like that. I was copying business model from legacy app instead of creating new model for this domain.&lt;/p&gt;

&lt;p&gt;I am going to refactor that piece of code and I have two choices:&lt;/p&gt;

&lt;p&gt;Keep going with DCI and let only actors to play roles&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='k'&gt;class&lt;/span&gt; &lt;span class='nc'&gt;StocksController&lt;/span&gt;
  &lt;span class='k'&gt;def&lt;/span&gt; &lt;span class='nf'&gt;update&lt;/span&gt;
    &lt;span class='n'&gt;stock&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='no'&gt;Stock&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;where&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='ss'&gt;:department_id&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='n'&gt;params&lt;/span&gt;&lt;span class='o'&gt;[&lt;/span&gt;&lt;span class='ss'&gt;:department_id&lt;/span&gt;&lt;span class='o'&gt;]&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;first&lt;/span&gt;
    &lt;span class='n'&gt;current_user&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;extend&lt;/span&gt; &lt;span class='ss'&gt;Role&lt;/span&gt;&lt;span class='p'&gt;:&lt;/span&gt;&lt;span class='ss'&gt;:StockManager&lt;/span&gt;
    &lt;span class='n'&gt;current_user&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;update&lt;/span&gt; &lt;span class='n'&gt;stock&lt;/span&gt;
  &lt;span class='k'&gt;end&lt;/span&gt;
&lt;span class='k'&gt;end&lt;/span&gt;

&lt;span class='k'&gt;module&lt;/span&gt; &lt;span class='nn'&gt;Roles::StockManager&lt;/span&gt;
  &lt;span class='k'&gt;def&lt;/span&gt; &lt;span class='nf'&gt;update&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;stock&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
    &lt;span class='n'&gt;stock&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;update_attribute&lt;/span&gt; &lt;span class='ss'&gt;:value&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;
                           &lt;span class='ss'&gt;Legacy&lt;/span&gt;&lt;span class='p'&gt;:&lt;/span&gt;&lt;span class='ss'&gt;:Department&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;find&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;stock&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;department&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;id&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;stock_value&lt;/span&gt;
  &lt;span class='k'&gt;end&lt;/span&gt;
&lt;span class='k'&gt;end&lt;/span&gt;

&lt;span class='k'&gt;class&lt;/span&gt; &lt;span class='nc'&gt;Department&lt;/span&gt; &lt;span class='o'&gt;&amp;lt;&lt;/span&gt; &lt;span class='ss'&gt;ActiveRecord&lt;/span&gt;&lt;span class='p'&gt;:&lt;/span&gt;&lt;span class='ss'&gt;:Base&lt;/span&gt;
  &lt;span class='n'&gt;has_one&lt;/span&gt; &lt;span class='ss'&gt;:stock&lt;/span&gt;
&lt;span class='k'&gt;end&lt;/span&gt;

&lt;span class='k'&gt;class&lt;/span&gt; &lt;span class='nc'&gt;Stock&lt;/span&gt; &lt;span class='o'&gt;&amp;lt;&lt;/span&gt; &lt;span class='ss'&gt;ActiveRecord&lt;/span&gt;&lt;span class='p'&gt;:&lt;/span&gt;&lt;span class='ss'&gt;:Base&lt;/span&gt;
  &lt;span class='n'&gt;belongs_to&lt;/span&gt; &lt;span class='ss'&gt;:department&lt;/span&gt;
&lt;span class='k'&gt;end&lt;/span&gt;

&lt;span class='k'&gt;class&lt;/span&gt; &lt;span class='nc'&gt;Legacy&lt;/span&gt;&lt;span class='o'&gt;::&lt;/span&gt;&lt;span class='no'&gt;Department&lt;/span&gt; &lt;span class='o'&gt;&amp;lt;&lt;/span&gt; &lt;span class='ss'&gt;ActiveResource&lt;/span&gt;&lt;span class='p'&gt;:&lt;/span&gt;&lt;span class='ss'&gt;:Base&lt;/span&gt;
  &lt;span class='c1'&gt;# stuff here&lt;/span&gt;
&lt;span class='k'&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Second option was to go back to class-oriented paradighm:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='k'&gt;class&lt;/span&gt; &lt;span class='nc'&gt;Department&lt;/span&gt; &lt;span class='o'&gt;&amp;lt;&lt;/span&gt; &lt;span class='ss'&gt;ActiveRecord&lt;/span&gt;&lt;span class='p'&gt;:&lt;/span&gt;&lt;span class='ss'&gt;:Base&lt;/span&gt;
  &lt;span class='n'&gt;has_one&lt;/span&gt; &lt;span class='ss'&gt;:stock&lt;/span&gt;
&lt;span class='k'&gt;end&lt;/span&gt;

&lt;span class='k'&gt;class&lt;/span&gt; &lt;span class='nc'&gt;Stock&lt;/span&gt; &lt;span class='o'&gt;&amp;lt;&lt;/span&gt; &lt;span class='ss'&gt;ActiveRecord&lt;/span&gt;&lt;span class='p'&gt;:&lt;/span&gt;&lt;span class='ss'&gt;:Base&lt;/span&gt;
  &lt;span class='n'&gt;belongs_to&lt;/span&gt; &lt;span class='ss'&gt;:department&lt;/span&gt;

  &lt;span class='k'&gt;def&lt;/span&gt; &lt;span class='nf'&gt;update&lt;/span&gt;
    &lt;span class='n'&gt;update_attribute&lt;/span&gt; &lt;span class='ss'&gt;:value&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='ss'&gt;Legacy&lt;/span&gt;&lt;span class='p'&gt;:&lt;/span&gt;&lt;span class='ss'&gt;:Department&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;find&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;department&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;id&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;stock_value&lt;/span&gt;
  &lt;span class='k'&gt;end&lt;/span&gt;
&lt;span class='k'&gt;end&lt;/span&gt;

&lt;span class='k'&gt;class&lt;/span&gt; &lt;span class='nc'&gt;Legacy&lt;/span&gt;&lt;span class='o'&gt;::&lt;/span&gt;&lt;span class='no'&gt;Department&lt;/span&gt; &lt;span class='o'&gt;&amp;lt;&lt;/span&gt; &lt;span class='ss'&gt;ActiveResource&lt;/span&gt;&lt;span class='p'&gt;:&lt;/span&gt;&lt;span class='ss'&gt;:Base&lt;/span&gt;
  &lt;span class='c1'&gt;# stuff here&lt;/span&gt;
&lt;span class='k'&gt;end&lt;/span&gt;

&lt;span class='k'&gt;class&lt;/span&gt; &lt;span class='nc'&gt;StocksController&lt;/span&gt;
  &lt;span class='k'&gt;def&lt;/span&gt; &lt;span class='nf'&gt;update&lt;/span&gt;
    &lt;span class='no'&gt;Stock&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;where&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='ss'&gt;:department_id&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='n'&gt;params&lt;/span&gt;&lt;span class='o'&gt;[&lt;/span&gt;&lt;span class='ss'&gt;:department_id&lt;/span&gt;&lt;span class='o'&gt;]&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;first&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;udpate&lt;/span&gt;
  &lt;span class='k'&gt;end&lt;/span&gt;
&lt;span class='k'&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;My main concern is that DCI in those examples looks like to complex to me. Why we shouldn&amp;#8217;t place more emphasis on better model granulation? If comes to the classic example with e-commerce: an user as a buyer: why we can&amp;#8217;t use classic decorator pattern? Buyer might be a model being a decorator for User model. And that&amp;#8217;s it, no roles, no additional layer.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>KPI gem</title>
   <link href="http://sevos.github.com/2011/05/15/kpi-gem.html"/>
   <updated>2011-05-15T00:00:00-07:00</updated>
   <id>http://sevos.github.com/2011/05/15/kpi-gem</id>
   <content type="html">&lt;h1 id='kpi_gem'&gt;KPI gem&lt;/h1&gt;

&lt;p&gt;Clients for whom I worked, at some stage of the are almost always asked me to create statistics describing the status and dynamics of development. The simplest example is number of registered users, but with time it always get more complex.&lt;/p&gt;

&lt;p&gt;I decided to build a small library in order to have common way of defining the statistics among my projects. &lt;a href='https://github.com/acatighera/statistics'&gt;Gem statistics&lt;/a&gt; gives not enough freedom to me. I need to be able to define reports having complex row definitions and reports made of other reports.&lt;/p&gt;

&lt;p&gt;First I developed gem with ActionMailer support (with simple report email), but recently my another client asked me for statistics in rails 2.3.x project. Then problems with compatibility came up, so I decided to remove ActionMailer support completely. The gem delivers only possibility to build reports as ruby objects now. You should create views for those on your own.&lt;/p&gt;

&lt;p&gt;Example report:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='k'&gt;class&lt;/span&gt; &lt;span class='nc'&gt;DailyStatsReport&lt;/span&gt; &lt;span class='o'&gt;&amp;lt;&lt;/span&gt; &lt;span class='ss'&gt;KPI&lt;/span&gt;&lt;span class='p'&gt;:&lt;/span&gt;&lt;span class='ss'&gt;:Report&lt;/span&gt;
  &lt;span class='k'&gt;def&lt;/span&gt; &lt;span class='nf'&gt;users&lt;/span&gt;
    &lt;span class='n'&gt;result&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;Users&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='no'&gt;User&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;count&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='ss'&gt;:description&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;Total users count&amp;#39;&lt;/span&gt;
  &lt;span class='k'&gt;end&lt;/span&gt;

  &lt;span class='k'&gt;def&lt;/span&gt; &lt;span class='nf'&gt;premium_users&lt;/span&gt;
    &lt;span class='n'&gt;result&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;Premium users&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='no'&gt;User&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;premium&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;count&lt;/span&gt;
  &lt;span class='k'&gt;end&lt;/span&gt;

  &lt;span class='k'&gt;def&lt;/span&gt; &lt;span class='nf'&gt;premium_users_percentage&lt;/span&gt;
    &lt;span class='n'&gt;result&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;Premium users&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;premium_users&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;to_f&lt;/span&gt; &lt;span class='o'&gt;/&lt;/span&gt; &lt;span class='n'&gt;users&lt;/span&gt; &lt;span class='o'&gt;*&lt;/span&gt; &lt;span class='mi'&gt;100&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='ss'&gt;:unit&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;%&amp;#39;&lt;/span&gt;
  &lt;span class='k'&gt;end&lt;/span&gt;

  &lt;span class='k'&gt;def&lt;/span&gt; &lt;span class='nf'&gt;income&lt;/span&gt;
    &lt;span class='n'&gt;result&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;Total income&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='no'&gt;Order&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;paid&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;sum&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='ss'&gt;:total&lt;/span&gt;&lt;span class='p'&gt;),&lt;/span&gt; &lt;span class='ss'&gt;:unit&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;EUR&amp;#39;&lt;/span&gt;
  &lt;span class='k'&gt;end&lt;/span&gt;

  &lt;span class='k'&gt;def&lt;/span&gt; &lt;span class='nf'&gt;daily_income&lt;/span&gt;
    &lt;span class='n'&gt;result&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;Daily income&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='no'&gt;Order&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;paid&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;where&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='ss'&gt;:created_at&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='n'&gt;the_day&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;sum&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='ss'&gt;:total&lt;/span&gt;&lt;span class='p'&gt;),&lt;/span&gt; &lt;span class='ss'&gt;:unit&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;EUR&amp;#39;&lt;/span&gt;
  &lt;span class='k'&gt;end&lt;/span&gt;

  &lt;span class='kp'&gt;private&lt;/span&gt;

  &lt;span class='k'&gt;def&lt;/span&gt; &lt;span class='nf'&gt;the_day&lt;/span&gt;
    &lt;span class='vi'&gt;@yesterday&lt;/span&gt; &lt;span class='o'&gt;||=&lt;/span&gt; &lt;span class='k'&gt;begin&lt;/span&gt;
      &lt;span class='n'&gt;yesterday&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;time&lt;/span&gt; &lt;span class='o'&gt;-&lt;/span&gt; &lt;span class='mi'&gt;1&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;day&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
      &lt;span class='n'&gt;yesterday&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;beginning_of_day&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;.yesterday&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;end_of_day&lt;/span&gt;
    &lt;span class='k'&gt;end&lt;/span&gt;
  &lt;span class='k'&gt;end&lt;/span&gt;
&lt;span class='k'&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;You can get report by instantiating report class&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='n'&gt;report&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='no'&gt;DailyStatsReport&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;new&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Each value is cached after calculation while report object exists. Calling report methods will trigger calculation and return &lt;code&gt;KPI::Entry&lt;/code&gt; object:&lt;/p&gt;
&lt;pre class='terminal'&gt;
&lt;code&gt;
&amp;gt; report.users
=&amp;gt; #&amp;lt;KPI::Entry:0x10177f630 @name=&quot;Users&quot;, @unit=nil,
     @description=&quot;Total users count&quot;, @value=874&amp;gt;
&lt;/code&gt;
&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;KPI::Report&lt;/code&gt; provides enumerator &lt;code&gt;#entries&lt;/code&gt; allowing to iterate through report entries:&lt;/p&gt;
&lt;pre class='terminal'&gt;
&lt;code&gt;
&amp;gt; report.entries.map(&amp;amp;:value)
=&amp;gt; [874, 14, 138.6, 19.8]
&lt;/code&gt;
&lt;/pre&gt;
&lt;p&gt;In order to get report for previous day, you should pass :time option to report initializer:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='n'&gt;report&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='no'&gt;DailyStatsReport&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;new&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='ss'&gt;:time&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='mi'&gt;1&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;day&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;ago&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;em&gt;NOTE: In entry definitions you should not use &lt;code&gt;Time.now&lt;/code&gt; for determining current time, use &lt;code&gt;self.time&lt;/code&gt; instead.&lt;/em&gt;&lt;/p&gt;

&lt;h2 id='but_thats_not_all_stay_tuned'&gt;But that&amp;#8217;s not all! Stay tuned!&lt;/h2&gt;

&lt;p&gt;There is another class &lt;code&gt;KPI::MergedReport&lt;/code&gt;. It takes reports of the same type and merges them using function passed through block:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='n'&gt;report_today&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='no'&gt;DailyStatsReport&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;new&lt;/span&gt;
&lt;span class='n'&gt;report_yesterday&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='no'&gt;DailyStatsReport&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;new&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='ss'&gt;:time&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='mi'&gt;1&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;day&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;ago&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
&lt;span class='n'&gt;diff_report&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='ss'&gt;KPI&lt;/span&gt;&lt;span class='p'&gt;:&lt;/span&gt;&lt;span class='ss'&gt;:MergedReport&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;new&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;report_today&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;report_yesterday&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt; &lt;span class='o'&gt;|&lt;/span&gt;&lt;span class='n'&gt;entry_today&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;entry_yesterday&lt;/span&gt;&lt;span class='o'&gt;|&lt;/span&gt;
  &lt;span class='ss'&gt;KPI&lt;/span&gt;&lt;span class='p'&gt;:&lt;/span&gt;&lt;span class='ss'&gt;:Entry&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;new&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;$$ (change)&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;entry_today&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;value&lt;/span&gt; &lt;span class='o'&gt;-&lt;/span&gt; &lt;span class='n'&gt;entry_yesterday&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;value&lt;/span&gt;
&lt;span class='k'&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;em&gt;NOTE: For now unfortunately it is not possible to use result helper in that block. I am working on that.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Now, we can get differences between reports:&lt;/p&gt;
&lt;pre class='terminal'&gt;
&lt;code&gt;
&amp;gt; diff_report.premium_users
=&amp;gt; #&amp;lt;KPI::Entry:0x11577e319 @name=&quot;Premium users (change)&quot;,
     @unit=nil, @description=&quot;&quot;, @value=2&amp;gt;
&lt;/code&gt;
&lt;/pre&gt;
&lt;p&gt;Actually it is not problem to pass more reports and calculate average value for example:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='n'&gt;avg_report&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='ss'&gt;KPI&lt;/span&gt;&lt;span class='p'&gt;:&lt;/span&gt;&lt;span class='ss'&gt;:MergedReport&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;new&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='o'&gt;*&lt;/span&gt;&lt;span class='n'&gt;week_reports&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt; &lt;span class='o'&gt;|*&lt;/span&gt;&lt;span class='n'&gt;entries&lt;/span&gt;&lt;span class='o'&gt;|&lt;/span&gt;
  &lt;span class='ss'&gt;KPI&lt;/span&gt;&lt;span class='p'&gt;:&lt;/span&gt;&lt;span class='ss'&gt;:Entry&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;new&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;$$ (avg)&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;entries&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;map&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='o'&gt;&amp;amp;&lt;/span&gt;&lt;span class='ss'&gt;:value&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;inject&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='ss'&gt;:+&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;to_f&lt;/span&gt; &lt;span class='o'&gt;/&lt;/span&gt; &lt;span class='n'&gt;entries&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;size&lt;/span&gt;
&lt;span class='k'&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;When you have your report object, you might want to send an email with data provided by it or do something else. That&amp;#8217;s all for now. Check it out on Github! All ideas and comments are welcome!&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;a href='https://github.com/sevos/kpi'&gt;KPI gem sourcecode on github&lt;/a&gt;&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Facebook Integration In Rails 3 Using Omniauth</title>
   <link href="http://sevos.github.com/2011/02/10/facebook-integration-in-rails-3-using-omniauth.html"/>
   <updated>2011-02-10T00:00:00-08:00</updated>
   <id>http://sevos.github.com/2011/02/10/facebook-integration-in-rails-3-using-omniauth</id>
   <content type="html">&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Warning&lt;/strong&gt;: This blog post was originaly written in February 2011. Since that time OmniAuth 1.x has been released and it&amp;#8217;s API has been changed. Please refer to &lt;a href='https://github.com/intridea/omniauth/wiki/Upgrading-to-1.0'&gt;OmniAuth wiki&lt;/a&gt; for further details&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1 id='facebook_integration_in_rails_3_using_omniauth'&gt;Facebook integration in Rails 3 using OmniAuth&lt;/h1&gt;

&lt;p&gt;Recently I faced a task of integrating Facebook and Twitter into my application. I wanted to let users sign up and sign in by their social network accounts. My application does not require any special information to create an account - just an email address. I dug a bit and found that the best fit for me was &lt;a href='https://github.com/intridea/omniauth'&gt;OmniAuth&lt;/a&gt;. I also found great &lt;a href='http://railscasts.com/episodes/235-omniauth-part-1'&gt;railscast&lt;/a&gt; (and &lt;a href='http://railscasts.com/episodes/236-omniauth-part-2'&gt;part two&lt;/a&gt;) made by Ryan Bates. My solution is based mostly on these two screencasts.&lt;/p&gt;

&lt;p&gt;The code shown by Ryan was just a hint, how it should be done. Few cases, like attaching already used authentication, were not covered in the screencasts. And today I would like to share with you my solution. It covers most cases, except removing last authentication from user&amp;#8217;s account. It is up to you, what you will do with that. In my application, after removing last authentication, user can still reset his password via email. You might want to just remove account.&lt;/p&gt;

&lt;p&gt;Enjoy!&lt;/p&gt;

&lt;p&gt;app/controllers/authentications_controller.rb:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='k'&gt;class&lt;/span&gt; &lt;span class='nc'&gt;AuthenticationsController&lt;/span&gt; &lt;span class='o'&gt;&amp;lt;&lt;/span&gt; &lt;span class='no'&gt;ApplicationController&lt;/span&gt;
  &lt;span class='n'&gt;before_filter&lt;/span&gt; &lt;span class='ss'&gt;:authenticate_user!&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='ss'&gt;:only&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='ss'&gt;:destroy&lt;/span&gt;

  &lt;span class='k'&gt;def&lt;/span&gt; &lt;span class='nf'&gt;create&lt;/span&gt;
    &lt;span class='n'&gt;omniauth&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='n'&gt;request&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;env&lt;/span&gt;&lt;span class='o'&gt;[&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;omniauth.auth&amp;#39;&lt;/span&gt;&lt;span class='o'&gt;]&lt;/span&gt;
    &lt;span class='n'&gt;authentication&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='no'&gt;Authentication&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;find_by_provider_and_uid&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;omniauth&lt;/span&gt;&lt;span class='o'&gt;[&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;provider&amp;quot;&lt;/span&gt;&lt;span class='o'&gt;]&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;omniauth&lt;/span&gt;&lt;span class='o'&gt;[&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;uid&amp;quot;&lt;/span&gt;&lt;span class='o'&gt;]&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
    &lt;span class='k'&gt;if&lt;/span&gt; &lt;span class='n'&gt;current_user&lt;/span&gt;
      &lt;span class='k'&gt;if&lt;/span&gt; &lt;span class='n'&gt;authentication&lt;/span&gt; &lt;span class='o'&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class='n'&gt;authentication&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;try&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='ss'&gt;:user&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='o'&gt;!=&lt;/span&gt; &lt;span class='n'&gt;current_user&lt;/span&gt;
        &lt;span class='n'&gt;flash&lt;/span&gt;&lt;span class='o'&gt;[&lt;/span&gt;&lt;span class='ss'&gt;:error&lt;/span&gt;&lt;span class='o'&gt;]&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='no'&gt;I18n&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;t&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;This %{provider} account is already connected to another account in our service&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='ss'&gt;:provider&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='n'&gt;authentication&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;provider&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
      &lt;span class='k'&gt;elsif&lt;/span&gt; &lt;span class='n'&gt;authentication&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;nil?&lt;/span&gt;
        &lt;span class='n'&gt;current_user&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;authentications&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;create!&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='ss'&gt;:provider&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='n'&gt;omniauth&lt;/span&gt;&lt;span class='o'&gt;[&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;provider&amp;quot;&lt;/span&gt;&lt;span class='o'&gt;]&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='ss'&gt;:uid&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='n'&gt;omniauth&lt;/span&gt;&lt;span class='o'&gt;[&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;uid&amp;quot;&lt;/span&gt;&lt;span class='o'&gt;]&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
      &lt;span class='k'&gt;end&lt;/span&gt;
      &lt;span class='n'&gt;redirect_to&lt;/span&gt; &lt;span class='n'&gt;edit_user_registration_path&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;current_user&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
    &lt;span class='k'&gt;else&lt;/span&gt; &lt;span class='c1'&gt;# user logged out&lt;/span&gt;
      &lt;span class='k'&gt;if&lt;/span&gt; &lt;span class='n'&gt;authentication&lt;/span&gt; &lt;span class='c1'&gt;# sign in user&lt;/span&gt;
        &lt;span class='n'&gt;sign_in_and_redirect&lt;/span&gt; &lt;span class='ss'&gt;:user&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;authentication&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;user&lt;/span&gt;
      &lt;span class='k'&gt;else&lt;/span&gt; &lt;span class='c1'&gt;# create new user&lt;/span&gt;
        &lt;span class='n'&gt;user&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='no'&gt;User&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;new&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;tap&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt;&lt;span class='o'&gt;|&lt;/span&gt;&lt;span class='n'&gt;user&lt;/span&gt;&lt;span class='o'&gt;|&lt;/span&gt; &lt;span class='n'&gt;user&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;apply_authentication&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;omniauth&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='p'&gt;}&lt;/span&gt;
        &lt;span class='k'&gt;if&lt;/span&gt; &lt;span class='n'&gt;user&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;save&lt;/span&gt;
          &lt;span class='n'&gt;sign_in_and_redirect&lt;/span&gt; &lt;span class='ss'&gt;:user&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;user&lt;/span&gt;
        &lt;span class='k'&gt;else&lt;/span&gt;
          &lt;span class='n'&gt;session&lt;/span&gt;&lt;span class='o'&gt;[&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;omniauth&amp;quot;&lt;/span&gt;&lt;span class='o'&gt;]&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='n'&gt;omniauth&lt;/span&gt;
          &lt;span class='n'&gt;redirect_to&lt;/span&gt; &lt;span class='n'&gt;new_user_registration_path&lt;/span&gt;
        &lt;span class='k'&gt;end&lt;/span&gt;
      &lt;span class='k'&gt;end&lt;/span&gt;
    &lt;span class='k'&gt;end&lt;/span&gt;
  &lt;span class='k'&gt;end&lt;/span&gt;

  &lt;span class='k'&gt;def&lt;/span&gt; &lt;span class='nf'&gt;destroy&lt;/span&gt;
    &lt;span class='vi'&gt;@authentication&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='n'&gt;current_user&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;authentications&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;find&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;params&lt;/span&gt;&lt;span class='o'&gt;[&lt;/span&gt;&lt;span class='ss'&gt;:id&lt;/span&gt;&lt;span class='o'&gt;]&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
    &lt;span class='vi'&gt;@authentication&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;destroy&lt;/span&gt;
    &lt;span class='n'&gt;redirect_to&lt;/span&gt; &lt;span class='ss'&gt;:back&lt;/span&gt;
  &lt;span class='k'&gt;end&lt;/span&gt;
&lt;span class='k'&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;app/models/authentication.rb:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='c1'&gt;#  create_table &amp;quot;authentications&amp;quot;, :force =&amp;gt; true do |t|&lt;/span&gt;
&lt;span class='c1'&gt;#    t.integer  &amp;quot;user_id&amp;quot;&lt;/span&gt;
&lt;span class='c1'&gt;#    t.string   &amp;quot;provider&amp;quot;&lt;/span&gt;
&lt;span class='c1'&gt;#    t.string   &amp;quot;uid&amp;quot;&lt;/span&gt;
&lt;span class='c1'&gt;#    t.datetime &amp;quot;created_at&amp;quot;&lt;/span&gt;
&lt;span class='c1'&gt;#    t.datetime &amp;quot;updated_at&amp;quot;&lt;/span&gt;
&lt;span class='c1'&gt;#  end&lt;/span&gt;

&lt;span class='k'&gt;class&lt;/span&gt; &lt;span class='nc'&gt;Authentication&lt;/span&gt; &lt;span class='o'&gt;&amp;lt;&lt;/span&gt; &lt;span class='ss'&gt;ActiveRecord&lt;/span&gt;&lt;span class='p'&gt;:&lt;/span&gt;&lt;span class='ss'&gt;:Base&lt;/span&gt;
  &lt;span class='n'&gt;belongs_to&lt;/span&gt; &lt;span class='ss'&gt;:user&lt;/span&gt;
  &lt;span class='n'&gt;validates&lt;/span&gt; &lt;span class='ss'&gt;:uid&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='ss'&gt;:provider&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='ss'&gt;:presence&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='kp'&gt;true&lt;/span&gt;
  &lt;span class='kp'&gt;attr_accessor&lt;/span&gt; &lt;span class='ss'&gt;:raw&lt;/span&gt;

  &lt;span class='k'&gt;def&lt;/span&gt; &lt;span class='nf'&gt;email&lt;/span&gt;
    &lt;span class='nb'&gt;self&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;raw&lt;/span&gt;&lt;span class='o'&gt;[&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;user_info&amp;quot;&lt;/span&gt;&lt;span class='o'&gt;][&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;email&amp;quot;&lt;/span&gt;&lt;span class='o'&gt;]&lt;/span&gt;
  &lt;span class='k'&gt;rescue&lt;/span&gt;
  &lt;span class='k'&gt;end&lt;/span&gt;
&lt;span class='k'&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;config/initializers/omniauth.rb&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='n'&gt;file_name&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='no'&gt;File&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;join&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='no'&gt;File&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;dirname&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='bp'&gt;__FILE__&lt;/span&gt;&lt;span class='p'&gt;),&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;..&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;authentication_services.yml&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
&lt;span class='no'&gt;OMNIAUTH_KEYS&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='no'&gt;YAML&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;load&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='no'&gt;ERB&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;new&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='no'&gt;File&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;new&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;file_name&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;read&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;result&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;&lt;span class='o'&gt;[&lt;/span&gt;&lt;span class='no'&gt;Rails&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;env&lt;/span&gt;&lt;span class='o'&gt;].&lt;/span&gt;&lt;span class='n'&gt;freeze&lt;/span&gt;

&lt;span class='no'&gt;Rails&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;application&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;config&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;middleware&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;use&lt;/span&gt; &lt;span class='ss'&gt;OmniAuth&lt;/span&gt;&lt;span class='p'&gt;:&lt;/span&gt;&lt;span class='ss'&gt;:Builder&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt;
  &lt;span class='no'&gt;OMNIAUTH_KEYS&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;each&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt; &lt;span class='o'&gt;|&lt;/span&gt;&lt;span class='n'&gt;prov&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;config&lt;/span&gt;&lt;span class='o'&gt;|&lt;/span&gt;
    &lt;span class='n'&gt;provider&lt;/span&gt; &lt;span class='n'&gt;prov&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='o'&gt;*&lt;/span&gt;&lt;span class='n'&gt;config&lt;/span&gt;
  &lt;span class='k'&gt;end&lt;/span&gt;
&lt;span class='k'&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;config/authentication_services.yml&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='yaml'&gt;&lt;span class='l-Scalar-Plain'&gt;development&lt;/span&gt;&lt;span class='p-Indicator'&gt;:&lt;/span&gt;
  &lt;span class='l-Scalar-Plain'&gt;facebook&lt;/span&gt;&lt;span class='p-Indicator'&gt;:&lt;/span&gt;
    &lt;span class='p-Indicator'&gt;-&lt;/span&gt; &lt;span class='s'&gt;&amp;#39;55a66eefce926c2eb1412222bc04f2787&amp;#39;&lt;/span&gt;
    &lt;span class='p-Indicator'&gt;-&lt;/span&gt; &lt;span class='s'&gt;&amp;#39;2f64ae3613398a553ecccc0da9f75a2b&amp;#39;&lt;/span&gt;
    &lt;span class='p-Indicator'&gt;-&lt;/span&gt; &lt;span class='l-Scalar-Plain'&gt;scope&lt;/span&gt;&lt;span class='p-Indicator'&gt;:&lt;/span&gt; &lt;span class='s'&gt;&amp;#39;email&amp;#39;&lt;/span&gt;
  &lt;span class='l-Scalar-Plain'&gt;twitter&lt;/span&gt;&lt;span class='p-Indicator'&gt;:&lt;/span&gt;
    &lt;span class='p-Indicator'&gt;-&lt;/span&gt; &lt;span class='s'&gt;&amp;#39;j7WltZaDVaNcGB8n28aa&amp;#39;&lt;/span&gt;
    &lt;span class='p-Indicator'&gt;-&lt;/span&gt; &lt;span class='s'&gt;&amp;#39;Rs0zOf1yUaybs1AMW77Ahc2x11KaZWfX2q7ohU&amp;#39;&lt;/span&gt;
&lt;span class='l-Scalar-Plain'&gt;test&lt;/span&gt;&lt;span class='p-Indicator'&gt;:&lt;/span&gt;
  &lt;span class='l-Scalar-Plain'&gt;facebook&lt;/span&gt;&lt;span class='p-Indicator'&gt;:&lt;/span&gt;
    &lt;span class='p-Indicator'&gt;-&lt;/span&gt; &lt;span class='s'&gt;&amp;#39;test&amp;#39;&lt;/span&gt;
    &lt;span class='p-Indicator'&gt;-&lt;/span&gt; &lt;span class='s'&gt;&amp;#39;test&amp;#39;&lt;/span&gt;
&lt;span class='l-Scalar-Plain'&gt;production&lt;/span&gt;&lt;span class='p-Indicator'&gt;:&lt;/span&gt;
  &lt;span class='l-Scalar-Plain'&gt;facebook&lt;/span&gt;&lt;span class='p-Indicator'&gt;:&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;spec/controllers/authentications_controller_spec.rb:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='nb'&gt;require&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;spec_helper&amp;#39;&lt;/span&gt;

&lt;span class='n'&gt;describe&lt;/span&gt; &lt;span class='no'&gt;AuthenticationsController&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt;
  &lt;span class='n'&gt;before&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt; &lt;span class='vi'&gt;@user&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='no'&gt;Factory&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='ss'&gt;:user&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='p'&gt;}&lt;/span&gt;

  &lt;span class='n'&gt;describe&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;POST / from facebook&amp;quot;&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt;
    &lt;span class='n'&gt;before&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt;
      &lt;span class='vi'&gt;@omniauth&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt;
        &lt;span class='s1'&gt;&amp;#39;uid&amp;#39;&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;12345&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;
        &lt;span class='s1'&gt;&amp;#39;provider&amp;#39;&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;facebook&amp;quot;&lt;/span&gt;
      &lt;span class='p'&gt;}&lt;/span&gt;
      &lt;span class='n'&gt;request&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;env&lt;/span&gt;&lt;span class='o'&gt;[&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;omniauth.auth&amp;quot;&lt;/span&gt;&lt;span class='o'&gt;]&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='vi'&gt;@omniauth&lt;/span&gt;
    &lt;span class='k'&gt;end&lt;/span&gt;

    &lt;span class='n'&gt;context&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;user logged in&amp;quot;&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt;
      &lt;span class='n'&gt;before&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt;
        &lt;span class='n'&gt;sign_in&lt;/span&gt; &lt;span class='vi'&gt;@user&lt;/span&gt;
      &lt;span class='k'&gt;end&lt;/span&gt;
      &lt;span class='n'&gt;context&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;having no authentications&amp;quot;&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt;
        &lt;span class='n'&gt;it&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;should create authentication &amp;quot;&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt;
          &lt;span class='n'&gt;post&lt;/span&gt; &lt;span class='ss'&gt;:create&lt;/span&gt;
          &lt;span class='vi'&gt;@user&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;reload&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;should&lt;/span&gt; &lt;span class='n'&gt;have&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='mi'&gt;1&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;authentication&lt;/span&gt;
        &lt;span class='k'&gt;end&lt;/span&gt;

        &lt;span class='n'&gt;it&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;should redirect to user&amp;#39;s profile&amp;quot;&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt;
          &lt;span class='n'&gt;post&lt;/span&gt; &lt;span class='ss'&gt;:create&lt;/span&gt;
          &lt;span class='n'&gt;response&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;should&lt;/span&gt; &lt;span class='n'&gt;redirect_to&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;edit_user_registration_path&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='vi'&gt;@user&lt;/span&gt;&lt;span class='p'&gt;))&lt;/span&gt;
        &lt;span class='k'&gt;end&lt;/span&gt;
      &lt;span class='k'&gt;end&lt;/span&gt;

      &lt;span class='n'&gt;context&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;having facebook authentication&amp;quot;&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt;
        &lt;span class='n'&gt;before&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt; &lt;span class='vi'&gt;@user&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;authentications&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;create!&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='ss'&gt;:provider&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;facebook&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='ss'&gt;:uid&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;12345&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;)}&lt;/span&gt;
        &lt;span class='n'&gt;it&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;should not create authentication  &amp;quot;&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt;
          &lt;span class='n'&gt;post&lt;/span&gt; &lt;span class='ss'&gt;:create&lt;/span&gt;
          &lt;span class='vi'&gt;@user&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;reload&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;should&lt;/span&gt; &lt;span class='n'&gt;have&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='mi'&gt;1&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;authentication&lt;/span&gt;
        &lt;span class='k'&gt;end&lt;/span&gt;

        &lt;span class='n'&gt;it&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;should redirect to user&amp;#39;s profile&amp;quot;&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt;
          &lt;span class='n'&gt;post&lt;/span&gt; &lt;span class='ss'&gt;:create&lt;/span&gt;
          &lt;span class='n'&gt;response&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;should&lt;/span&gt; &lt;span class='n'&gt;redirect_to&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;edit_user_registration_path&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='vi'&gt;@user&lt;/span&gt;&lt;span class='p'&gt;))&lt;/span&gt;
        &lt;span class='k'&gt;end&lt;/span&gt;
      &lt;span class='k'&gt;end&lt;/span&gt;

      &lt;span class='n'&gt;context&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;facebook authentication connected to another account&amp;quot;&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt;
        &lt;span class='n'&gt;before&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt;
          &lt;span class='vi'&gt;@another_user&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='no'&gt;Factory&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='ss'&gt;:user&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
          &lt;span class='vi'&gt;@another_user&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;authentications&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;create!&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='ss'&gt;:provider&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;facebook&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='ss'&gt;:uid&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;12345&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
        &lt;span class='k'&gt;end&lt;/span&gt;

        &lt;span class='n'&gt;it&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;should disallow to connect accounts&amp;quot;&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt;
          &lt;span class='n'&gt;post&lt;/span&gt; &lt;span class='ss'&gt;:create&lt;/span&gt;
          &lt;span class='vi'&gt;@user&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;reload&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;should&lt;/span&gt; &lt;span class='n'&gt;have&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='mi'&gt;0&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;authentications&lt;/span&gt;
          &lt;span class='n'&gt;flash&lt;/span&gt;&lt;span class='o'&gt;[&lt;/span&gt;&lt;span class='ss'&gt;:error&lt;/span&gt;&lt;span class='o'&gt;].&lt;/span&gt;&lt;span class='n'&gt;should&lt;/span&gt; &lt;span class='o'&gt;==&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;This facebook account is already connected to another account in our service&amp;quot;&lt;/span&gt;
          &lt;span class='n'&gt;response&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;should&lt;/span&gt; &lt;span class='n'&gt;redirect_to&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;edit_user_registration_path&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='vi'&gt;@user&lt;/span&gt;&lt;span class='p'&gt;))&lt;/span&gt;
        &lt;span class='k'&gt;end&lt;/span&gt;
      &lt;span class='k'&gt;end&lt;/span&gt;
    &lt;span class='k'&gt;end&lt;/span&gt;

    &lt;span class='n'&gt;context&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;user logged out&amp;quot;&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt;
      &lt;span class='n'&gt;context&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;user has attached authentication&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;and logging in&amp;quot;&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt;
        &lt;span class='n'&gt;before&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt; &lt;span class='vi'&gt;@user&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;authentications&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;create!&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='ss'&gt;:provider&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;facebook&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='ss'&gt;:uid&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;12345&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='p'&gt;}&lt;/span&gt;
        &lt;span class='n'&gt;it&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;should sign in user&amp;quot;&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt;
          &lt;span class='n'&gt;post&lt;/span&gt; &lt;span class='ss'&gt;:create&lt;/span&gt;
          &lt;span class='n'&gt;controller&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;send&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='ss'&gt;:current_user&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;should&lt;/span&gt; &lt;span class='o'&gt;==&lt;/span&gt; &lt;span class='vi'&gt;@user&lt;/span&gt;
        &lt;span class='k'&gt;end&lt;/span&gt;

        &lt;span class='n'&gt;it&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;should redirect&amp;quot;&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt;
          &lt;span class='n'&gt;post&lt;/span&gt; &lt;span class='ss'&gt;:create&lt;/span&gt;
          &lt;span class='n'&gt;response&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;should&lt;/span&gt; &lt;span class='n'&gt;be_redirect&lt;/span&gt;
        &lt;span class='k'&gt;end&lt;/span&gt;
      &lt;span class='k'&gt;end&lt;/span&gt;
    &lt;span class='k'&gt;end&lt;/span&gt;

    &lt;span class='n'&gt;context&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;no matching user&amp;quot;&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt;
      &lt;span class='n'&gt;context&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;no extra credentials given&amp;quot;&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt;
        &lt;span class='n'&gt;before&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt;
          &lt;span class='vi'&gt;@user&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='no'&gt;User&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;new&lt;/span&gt;
          &lt;span class='vi'&gt;@user&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;stub!&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='ss'&gt;:save&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='kp'&gt;false&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
          &lt;span class='no'&gt;User&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;stub!&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='ss'&gt;:new&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='vi'&gt;@user&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
        &lt;span class='k'&gt;end&lt;/span&gt;

        &lt;span class='n'&gt;it&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;should apply authentication&amp;quot;&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt;
          &lt;span class='vi'&gt;@user&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;should_receive&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='ss'&gt;:apply_authentication&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;with&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;request&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;env&lt;/span&gt;&lt;span class='o'&gt;[&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;omniauth.auth&amp;quot;&lt;/span&gt;&lt;span class='o'&gt;]&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
          &lt;span class='n'&gt;post&lt;/span&gt; &lt;span class='ss'&gt;:create&lt;/span&gt;
        &lt;span class='k'&gt;end&lt;/span&gt;

        &lt;span class='n'&gt;it&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;should save authentication to session&amp;quot;&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt;
          &lt;span class='n'&gt;post&lt;/span&gt; &lt;span class='ss'&gt;:create&lt;/span&gt;
          &lt;span class='n'&gt;session&lt;/span&gt;&lt;span class='o'&gt;[&lt;/span&gt;&lt;span class='ss'&gt;:omniauth&lt;/span&gt;&lt;span class='o'&gt;].&lt;/span&gt;&lt;span class='n'&gt;should&lt;/span&gt; &lt;span class='o'&gt;==&lt;/span&gt; &lt;span class='vi'&gt;@omniauth&lt;/span&gt;
        &lt;span class='k'&gt;end&lt;/span&gt;

        &lt;span class='n'&gt;it&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;should redirect to new registration path&amp;quot;&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt;
          &lt;span class='n'&gt;post&lt;/span&gt; &lt;span class='ss'&gt;:create&lt;/span&gt;
          &lt;span class='n'&gt;response&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;should&lt;/span&gt; &lt;span class='n'&gt;redirect_to&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;new_user_registration_path&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
        &lt;span class='k'&gt;end&lt;/span&gt;
      &lt;span class='k'&gt;end&lt;/span&gt;

      &lt;span class='n'&gt;context&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;facebook credentials given&amp;quot;&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt;
        &lt;span class='n'&gt;before&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt; &lt;span class='n'&gt;request&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;env&lt;/span&gt;&lt;span class='o'&gt;[&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;omniauth.auth&amp;quot;&lt;/span&gt;&lt;span class='o'&gt;][&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;user_info&amp;quot;&lt;/span&gt;&lt;span class='o'&gt;]&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;email&amp;quot;&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;example@example.com&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;}&lt;/span&gt; &lt;span class='p'&gt;}&lt;/span&gt;

        &lt;span class='n'&gt;it&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;should create user&amp;quot;&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt;
          &lt;span class='o'&gt;-&amp;gt;&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt; &lt;span class='n'&gt;post&lt;/span&gt; &lt;span class='ss'&gt;:create&lt;/span&gt; &lt;span class='p'&gt;}&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;should&lt;/span&gt; &lt;span class='n'&gt;change&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='no'&gt;User&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='ss'&gt;:count&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;by&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='mi'&gt;1&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
        &lt;span class='k'&gt;end&lt;/span&gt;

        &lt;span class='n'&gt;it&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;should sign in created user&amp;quot;&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt;
          &lt;span class='n'&gt;post&lt;/span&gt; &lt;span class='ss'&gt;:create&lt;/span&gt;
          &lt;span class='n'&gt;controller&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;send&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='ss'&gt;:current_user&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;should_not&lt;/span&gt; &lt;span class='n'&gt;be_nil&lt;/span&gt;
        &lt;span class='k'&gt;end&lt;/span&gt;

        &lt;span class='n'&gt;it&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;should redirect&amp;quot;&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt;
          &lt;span class='n'&gt;post&lt;/span&gt; &lt;span class='ss'&gt;:create&lt;/span&gt;
          &lt;span class='n'&gt;response&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;should&lt;/span&gt; &lt;span class='n'&gt;be_redirect&lt;/span&gt;
        &lt;span class='k'&gt;end&lt;/span&gt;
      &lt;span class='k'&gt;end&lt;/span&gt;
    &lt;span class='k'&gt;end&lt;/span&gt;
  &lt;span class='k'&gt;end&lt;/span&gt;
&lt;span class='k'&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;spec/models/authentication_spec.rb&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='nb'&gt;require&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;spec_helper&amp;#39;&lt;/span&gt;

&lt;span class='n'&gt;describe&lt;/span&gt; &lt;span class='no'&gt;Authentication&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt;
  &lt;span class='n'&gt;describe&lt;/span&gt; &lt;span class='ss'&gt;:email&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt;
    &lt;span class='n'&gt;context&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;for facebook&amp;quot;&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt;
      &lt;span class='n'&gt;before&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt; &lt;span class='vi'&gt;@auth&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='no'&gt;Authentication&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;new&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='ss'&gt;:provider&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;facebook&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='p'&gt;}&lt;/span&gt;
      &lt;span class='n'&gt;it&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;from raw&amp;quot;&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt;
        &lt;span class='vi'&gt;@auth&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;raw&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;user_info&amp;#39;&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;email&amp;#39;&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;artur.roszczyk@gmail.com&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;}}&lt;/span&gt;
        &lt;span class='vi'&gt;@auth&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;email&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;should&lt;/span&gt; &lt;span class='o'&gt;==&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;artur.roszczyk@gmail.com&amp;#39;&lt;/span&gt;
      &lt;span class='k'&gt;end&lt;/span&gt;
    &lt;span class='k'&gt;end&lt;/span&gt;
  &lt;span class='k'&gt;end&lt;/span&gt;
&lt;span class='k'&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href='https://gist.github.com/821291'&gt;Github Gist is available here&lt;/a&gt;&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>iWork '09 Retail after trial</title>
   <link href="http://sevos.github.com/2010/10/26/iwork-09-retail-after-trial.html"/>
   <updated>2010-10-26T00:00:00-07:00</updated>
   <id>http://sevos.github.com/2010/10/26/iwork-09-retail-after-trial</id>
   <content type="html">&lt;h1 id='iwork_09_retail_after_trial'&gt;iWork &amp;#8216;09 Retail after trial&lt;/h1&gt;

&lt;p&gt;Perhaps you installed iWork &amp;#8216;09 trial in order to give it a chance. Perhaps you was amazed by this great suite and wanted to use it also after 30 days period. If you live, like me, in country where you cannot buy an online CD-Key, you have to go to retail store or Apple reseller and buy a retail version of iWork &amp;#8216;09. And that&amp;#8217;s what I did.&lt;/p&gt;

&lt;p&gt;Unfortunately when I came back to home, opened the box and installed suit from DVD, it was not been working. After launching Pages I got request for CD-Key. WTF? I asked uncle Google and got to know that Apple didn&amp;#8217;t require any serials for retail disc installations.&lt;/p&gt;

&lt;p&gt;Solution:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Go to your Applications directory&lt;/li&gt;

&lt;li&gt;Drag iWork &amp;#8216;09 directory to the bin&lt;/li&gt;

&lt;li&gt;Open you Macintosh HD directory (just root directory) and go to Library&lt;/li&gt;

&lt;li&gt;Open Application support folder&lt;/li&gt;

&lt;li&gt;Drag iWork &amp;#8216;09 folder to the trash bin&lt;/li&gt;

&lt;li&gt;Empty your trash bin&lt;/li&gt;

&lt;li&gt;Proceed with standard installation from retail disc&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I hope that it will help you. I wasted 15 minutes for finding this solution.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>The Passionate Programmer</title>
   <link href="http://sevos.github.com/2010/08/19/the-passionate-programmer.html"/>
   <updated>2010-08-19T00:00:00-07:00</updated>
   <id>http://sevos.github.com/2010/08/19/the-passionate-programmer</id>
   <content type="html">&lt;h1 id='the_passionate_programmer'&gt;The Passionate Programmer&lt;/h1&gt;

&lt;p&gt;&lt;img alt='The Passionate Programmer book' src='/img/2010/08/19/the-passionate-programmer/book.jpg' /&gt;&lt;/p&gt;

&lt;p&gt;A couple of months ago I have bought an e-book written by Chad Fowler. It tells mostly about responsible, aware career planning from developer&amp;#8217;s point of view. At least it seems to tell about that. In fact, if we cut off the domain-specific examples, it becomes a vast hanbook explaining how to cultivate our happines, life pleasure.&lt;/p&gt;

&lt;p&gt;The author stands that your live, in general, is filled with your work. Therefore you need to draw satisfaction from your job and enjoy it. He uses his story as an example to show how flexible, foreseeing and enthusiastic about your job you should be in order to achieve succes. Huge impact is put on business point of view, so much misunderstood in IT industry. In the book you are treated as a product, which you are going to sell to your present/future employers or clients.&lt;/p&gt;

&lt;p&gt;The book is divided into five parts:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Choosing Your Market&lt;/li&gt;

&lt;li&gt;Investing in Your Product&lt;/li&gt;

&lt;li&gt;Executing&lt;/li&gt;

&lt;li&gt;Marketing…Not Just for Suits&lt;/li&gt;

&lt;li&gt;Maintaining Your Edge&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can read more about this book on Pragmatic Bookshelf site &lt;a href='http://pragprog.com/titles/cfcar2/the-passionate-programmer'&gt;here&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I am going to write about my experience in applying these hints in my life.&lt;/p&gt;</content>
 </entry>
 

</feed>