<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Hungry Machine &#187; activerecord</title>
	<atom:link href="http://blog.hungrymachine.com/tag/activerecord/feed/" rel="self" type="application/rss+xml" />
	<link>http://blog.hungrymachine.com</link>
	<description>The guys behind LivingSocial</description>
	<lastBuildDate>Sun, 25 Oct 2009 15:08:39 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.2</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>ActsAsInsertOrUpdate</title>
		<link>http://blog.hungrymachine.com/2008/04/23/actsasinsertorupdate/</link>
		<comments>http://blog.hungrymachine.com/2008/04/23/actsasinsertorupdate/#comments</comments>
		<pubDate>Wed, 23 Apr 2008 03:40:00 +0000</pubDate>
		<dc:creator>aaron</dc:creator>
				<category><![CDATA[All]]></category>
		<category><![CDATA[activerecord]]></category>
		<category><![CDATA[Rails]]></category>

		<guid isPermaLink="false">blog.hungrymachine.com/2008/11/13/actsasinsertorupdate</guid>
		<description><![CDATA[Problem

With high volume Rails applications, entities with unique constraints are expensive and error prone to create/update. ActsAsInsertOrUpdate helps solve that problem (if you&#8217;re using MySQL), by leveraging the &#8220;INSERT &#8230; ON DUPLICATE KEY UPDATE&#8221; functionality.

Scenario
 Lets say you have a Person, and Entity, and a Rating. Each user can rate each entity only once, and [...]]]></description>
			<content:encoded><![CDATA[<h2>Problem</h2>
<p>
With high volume Rails applications, entities with unique constraints are expensive and error prone to create/update. ActsAsInsertOrUpdate helps solve that problem (if you&#8217;re using MySQL), by leveraging the &#8220;INSERT &#8230; ON DUPLICATE KEY UPDATE&#8221; functionality.
</p>
<h2>Scenario</h2>
<p> Lets say you have a Person, and Entity, and a Rating. Each user can rate each entity only once, and if they re-rate the entity, it should update the value.</p>
<div class="CodeRay">
<div class="code">
<pre><span style="color:#080; font-weight:bold">class</span> <span style="color:#B06; font-weight:bold">Entity</span> &lt; <span style="color:#036; font-weight:bold">ActiveRecord</span>::<span style="color:#036; font-weight:bold">Base</span>
  has_many <span style="color:#A60">:ratings</span>
<span style="color:#080; font-weight:bold">end</span>

<span style="color:#080; font-weight:bold">class</span> <span style="color:#B06; font-weight:bold">Person</span> &lt; <span style="color:#036; font-weight:bold">ActiveRecord</span>::<span style="color:#036; font-weight:bold">Base</span>
 has_many <span style="color:#A60">:ratings</span>
<span style="color:#080; font-weight:bold">end</span>

<span style="color:#080; font-weight:bold">class</span> <span style="color:#B06; font-weight:bold">Rating</span> &lt; <span style="color:#036; font-weight:bold">ActiveRecord</span>::<span style="color:#036; font-weight:bold">Base</span>
 belongs_to <span style="color:#A60"> <img src='http://blog.hungrymachine.com/wp-includes/images/smilies/icon_razz.gif' alt=':P' class='wp-smiley' /> erson</span>
 belongs_to <span style="color:#A60">:Entity</span>
<span style="color:#080; font-weight:bold">end</span>  </pre>
</div>
</div>
<p>Here is the table that back&#8217;s Rating. Notice the Unique Key constraint on (entity_id, person_id).</p>
<div class="CodeRay">
<div class="code">
<pre>CREATE TABLE `ratings` (
  `id` int(11) NOT NULL auto_increment,
  `rating` tinyint(4) default '0',
  `person_id` int(11) default NULL,
  `entity_id` int(11) default NULL,
  `created_at` datetime default NULL,
  `updated_at` datetime default NULL,
  PRIMARY KEY  (`id`),
  UNIQUE KEY `index_ratings_on_entity_id_and_person_id` (`entity_id`,`person_id`),
)</pre>
</div>
</div>
<p>Previously, the logic would be something like:</p>
<ul>
<li>1) Check if a rating exists for the User + Entity</li>
<li>2) If so, update</li>
<li>3) If not, insert</li>
<li>4) rescue the insert in case there is a unqiue constraint error</li>
<li>5) retrieve the record (and/or update with the new rating)</li>
<p>
If the table is MyISAM, Steps 1-5 aren&#8217;t transactionally safe.  If you&#8217;re using InnoDB, and experience heavy volumes of traffic, you&#8217;re prone to Deadlock&#8217;s.  This is even more of a concern is the unique entity is shared across multiple users, as seen with a recent client of ours.
</p>
<h2>Solution:</h2>
<div class="CodeRay">
<div class="code">
<pre><span style="color:#080; font-weight:bold">class</span> <span style="color:#B06; font-weight:bold">Rating</span> &lt; <span style="color:#036; font-weight:bold">ActiveRecord</span>::<span style="color:#036; font-weight:bold">Base</span>
 belongs_to <span style="color:#A60"> <img src='http://blog.hungrymachine.com/wp-includes/images/smilies/icon_razz.gif' alt=':P' class='wp-smiley' /> erson</span>
 belongs_to <span style="color:#A60">:Entity</span>
 acts_as_insert_or_update <span style="color:#A60">:field_to_update</span> =&gt; <span style="background-color:#fff0f0"><span style="color:#710">&quot;</span><span style="color:#D20">rating</span><span style="color:#710">&quot;</span></span>
<span style="color:#080; font-weight:bold">end</span>  </pre>
</div>
</div>
<p>Now Steps 1-5 above become, just one.  Rating.create(..)</p>
<p>In the background, ActsAsInsertOrUpdate overwrites the implementation of ActionRecord:Base#create, to leverage an often unsed feature of MySQL called INSERT &#8230; ON DUPLICATE KEY UPDATE. As configured above, if a duplicate record is found for the unique constraint, the rating field will be updated with the new value. </p>
<h2>Caution</h2>
<p>This is a brute force hack on ActiveRecord::Base#create.  Use at your own risk.</p>
<h2>Code</h2>
<p>Waiting for a rubyforge account.  Will post more info soon.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.hungrymachine.com/2008/04/23/actsasinsertorupdate/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
	</channel>
</rss>
