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

  <title><![CDATA[Michael Bensoussan]]></title>
  <link href="http://mickeyben.com/atom.xml" rel="self"/>
  <link href="http://mickeyben.com/"/>
  <updated>2012-04-05T16:48:50+02:00</updated>
  <id>http://mickeyben.com/</id>
  <author>
    <name><![CDATA[Michael Bensoussan]]></name>
    
  </author>
  <generator uri="http://octopress.org/">Octopress</generator>

  
  <entry>
    <title type="html"><![CDATA[Register to an image loaded event with jQuery]]></title>
    <link href="http://mickeyben.com/blog/2010/07/26/register-to-an-image-loaded-event-with-jquery/"/>
    <updated>2010-07-26T01:29:00+02:00</updated>
    <id>http://mickeyben.com/blog/2010/07/26/register-to-an-image-loaded-event-with-jquery</id>
    <content type="html"><![CDATA[<p>I was recently working on a lightbox where I needed to display a remote image and re-center the lighbox once the image is loaded.
This may seems pretty simple but it took me some time to discover that jQuery does the job via the <strong>load</strong> method.
As soon as the image has been loaded, the handler is called.</p>

<div><script src='https://gist.github.com/2306563.js?file='></script>
<noscript><pre><code>$(&quot;#image_id&quot;).load(function(){
  // stuff to do after the image is loaded
});</code></pre></noscript></div>

]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Creating an activity feed with rails]]></title>
    <link href="http://mickeyben.com/blog/2010/05/23/creating-an-activity-feed-with-rails/"/>
    <updated>2010-05-23T01:12:00+02:00</updated>
    <id>http://mickeyben.com/blog/2010/05/23/creating-an-activity-feed-with-rails</id>
    <content type="html"><![CDATA[<p>I recently had to build an activity feed at <a href="https://letitcast.com">letitcast.com</a>.
It’s a common thing to do, but I thought I might mention how I did it, and see if anyone else has suggestions/improvements.</p>

<p>We wanted to display to our actors new roles corresponding their profile, new feedbacks and views of their auditions, recent comments &#8230;</p>

<p>So, I first created a model <strong>Activity</strong>, here&#8217;s the migration :</p>

<div><script src='https://gist.github.com/2306479.js?file='></script>
<noscript><pre><code>  class CreateActivities &lt; ActiveRecord::Migration
    def self.up
      create_table :activities do |t|
        t.integer :user_id, :null =&gt; false
        t.integer :activity_type, :null =&gt; false
        t.integer :target_id, :null =&gt; false
        t.string  :target_type, :null =&gt; false
        t.timestamps
      end

       add_index :activities, [:target_id, :target_type]
       add_index :activities, :user_id

    end

    def self.down
      drop_table :activities
    end
  end</code></pre></noscript></div>


<p>As you can see it&#8217;s a polymorphic model, so the activity can be related to any active record model.</p>

<p>Here&#8217;s the model :</p>

<div><script src='https://gist.github.com/2306496.js?file='></script>
<noscript><pre><code>  class Activity &lt; ActiveRecord::Base

    belongs_to :user
    belongs_to :target, :polymorphic =&gt; true
  
    default_scope :order =&gt; 'activities.created_at DESC', :limit =&gt; 10
  
    AUDITION_POSTED           = 1 #target --&gt; model audition
    AUDITION_FEEDBACK_UPDATED = 2 #target --&gt; model audition
    AUDITION_VIEWED           = 3 #target --&gt; model video
    NEW_PART                  = 4 #target --&gt; model part
  
    class &lt;&lt; self
      def add(user, activity_type, target)
        return false if user.blank? or activity_type.blank? or target.blank?
        activity = Activity.new(:user =&gt; user, :activity_type =&gt; activity_type, :target =&gt; target)
        activity.save!
      end
    end
  
  end</code></pre></noscript></div>


<p>At the beginning the activity types were mapped in an other database but it was a bit overkill and was reducing the performance a lot so I just added them into the model (AUDITION_POSTED, AUDITION_FEEDBACK_UPDATED, &#8230;)</p>

<p>Activities are created with observers.
In this exemple a new audition triggers an AUDITION_POSTED activity created.</p>

<div><script src='https://gist.github.com/2306518.js?file='></script>
<noscript><pre><code>class AuditionObserver &lt; ActiveRecord::Observer

  # ACTIVITY OBSERVER : new audition posted
  def after_create(audition)
    if audition.actor
      Activity.add(audition.actor.user, Activity::AUDITION_POSTED, audition)
    end
  end

end</code></pre></noscript></div>


<p>Sooooo &#8230; I can add any event via a simple variable in the activity model and an observer.</p>

<p>It was working really well but there were some performance issues with some events that required a lot of inserts in the activity model.
I first decided to execute this observer in a delayed job but after some research I ended up with a fast way to insert a batch of activities, here&#8217;s the method :</p>

<div><script src='https://gist.github.com/2306541.js?file='></script>
<noscript><pre><code>def self.batch_add(users, activity_type, target)
  return false if users.blank? or activity_type.blank? or target.blank?
  inserts = []
  users.each {|user| inserts.push &quot;('#{user.id}', '#{activity_type}', '#{target.id}', '#{target.class}', UTC_TIMESTAMP())&quot; }

  sql = &quot;INSERT INTO activities (`user_id`, `activity_type`, `target_id`, `target_type`, `created_at`) VALUES #{inserts.join(&quot;, &quot;)}&quot;
  ActiveRecord::Base.connection.execute sql
end</code></pre></noscript></div>


<p>To retrieve the activities :</p>

<div><script src='https://gist.github.com/2306543.js?file='></script>
<noscript><pre><code>@user.activities</code></pre></noscript></div>


<p>By default you&#8217;ll get 10 activities order by most recents.
If you want to change this behavior, just change the <strong>default_scope</strong>.</p>

<p>We&#8217;re also in the process of grouping the user activities to display them in a nice view, so there will maybe be a part II :-)</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Optional local in partial that doesn't break]]></title>
    <link href="http://mickeyben.com/blog/2010/05/22/optional-local-in-partial-that-doesnt-break/"/>
    <updated>2010-05-22T00:58:00+02:00</updated>
    <id>http://mickeyben.com/blog/2010/05/22/optional-local-in-partial-that-doesnt-break</id>
    <content type="html"><![CDATA[<p>If you have a partial called with or without local parameters, example :</p>

<div><script src='https://gist.github.com/2306385.js?file=_partial.haml'></script>
<noscript><pre><code>= render partial: 'user/new'
= render partial: 'user/new', locals: { show_ad: true }</code></pre></noscript></div>


<p>And you don’t want the partial to break when the local isn’t assigned, you can access it through the <strong>local_assigns</strong> variable :</p>

<div><script src='https://gist.github.com/2306402.js?file=_partial.haml'></script>
<noscript><pre><code>- if local_assigns[:show_ad]
  = render partial: 'ad'</code></pre></noscript></div>

]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Using Nginx as a load balancer]]></title>
    <link href="http://mickeyben.com/blog/2009/12/30/using-nginx-as-a-load-balancer/"/>
    <updated>2009-12-30T04:13:00+01:00</updated>
    <id>http://mickeyben.com/blog/2009/12/30/using-nginx-as-a-load-balancer</id>
    <content type="html"><![CDATA[<p>Here’s a look at how nginx does basic load balancing :</p>

<div><script src='https://gist.github.com/2306229.js?file=nginx.conf'></script>
<noscript><pre><code>upstream  yoursite  {
   server   yoursite1.yoursite.com;
   server   yoursite2.yoursite.com;
}

server {
   server_name www.yoursite.com;
   location / {
      proxy_pass  http://yoursite;
   }
}</code></pre></noscript></div>


<p>This configuration will send 50% of the requests for www.yoursite.com to yoursite1.yoursite.com and the other 50% to yoursite2.yoursite.com.</p>

<h2>ip_hash</h2>

<p>You can specify the <strong>ip_hash</strong> directive that guarantees the client request will always be transferred to the same server.
If this server is considered inoperative, then the request of this client will be transferred to another server.</p>

<div><script src='https://gist.github.com/2306278.js?file=nginx.conf'></script>
<noscript><pre><code>upstream  yoursite  {
   ip_hash;
   server   yoursite1.yoursite.com;
   server   yoursite2.yoursite.com;
}</code></pre></noscript></div>


<h2>down</h2>

<p>If one of the servers must be removed for some time, you must mark that server as <em>down</em>.</p>

<div><script src='https://gist.github.com/2306287.js?file=nginx.conf'></script>
<noscript><pre><code>upstream  yoursite  {
   ip_hash;
   server   yoursite1.yoursite.com down;
   server   yoursite2.yoursite.com;
}</code></pre></noscript></div>


<h2>weight</h2>

<p>If you add a <em>weight</em> tag onto the end of the <em>server</em> definition you can modify the percentages of the requests send to the servers.
When there&#8217;s no weight set, the weight is equal to one.</p>

<div><script src='https://gist.github.com/2306307.js?file=nginx.conf'></script>
<noscript><pre><code>upstream  yoursite  {
   server   yoursite1.yoursite.com weight=4;
   server   yoursite2.yoursite.com;
}</code></pre></noscript></div>


<p>This configuration will send 80% of the requests to yoursite1.yoursite.com and the other 20% to yoursite2.yoursite.com.</p>

<p><em>note:</em> It&#8217;s not possible to combine ip_hash and weight directives.</p>

<h2>max_fails and fail_timeout</h2>

<p><em>max_fails</em> is a directive defining the number of unsuccessful attempts in the time period defined by <em>fail_timeout</em> before the server is considered inoperative. If not set, the number of attempts is one. A value of 0 turns off this check.
If <em>fail_timeout</em> is not set the time is 10 seconds.</p>

<div><script src='https://gist.github.com/2306328.js?file=nginx.conf'></script>
<noscript><pre><code>upstream  yoursite  {
   server   yoursite1.yoursite.com;
   server   yoursite2.yoursite.com max_fails=3  fail_timeout=30s;
}</code></pre></noscript></div>


<p>In this configuration nginx will consider yoursite2.yoursite.com as inoperative if a request fails 3 times with a 30s timeout.</p>

<h2>backup</h2>

<p>If the non-backup servers are all down or busy, the server(s) with the <em>backup</em> directive will be used.</p>

<div><script src='https://gist.github.com/2306339.js?file=nginx.conf'></script>
<noscript><pre><code>upstream  yoursite  {
   server   yoursite1.yoursite.com max_fails=3;
   server   yoursite2.yoursite.com max_fails=3;
   server   yoursite3.yoursite.com backup;
}</code></pre></noscript></div>


<p>This configuration will send 50% of the requests for www.yoursite.com to yoursite1.yoursite.com and the other 50% to yoursite2.yoursite.com.
If yoursite1.yoursite.com and yoursite2.yoursite.com both fails 3 times the requests will be send to yoursite3.yoursite.com.</p>
]]></content>
  </entry>
  
</feed>

