<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
xmlns:content="http://purl.org/rss/1.0/modules/content/"
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/">
	<channel>
		<title>Author at Infinum</title>
		<atom:link href="https://infinum.com/blog/author/vladimir-rosancic/feed/" rel="self" type="application/rss+xml" />
		<link></link>
		<description>Building digital products</description>
		<lastBuildDate>Fri, 03 Apr 2026 12:58:20 +0000</lastBuildDate>
		<sy:updatePeriod>hourly</sy:updatePeriod>
		<sy:updateFrequency>1</sy:updateFrequency>

					<item>
				<image>
					<url>8011https://infinum.com/uploads/2018/01/things-i-wish-active-record-had-after-using-ecto-0.webp</url>
				</image>
				<title>Things I Wish ActiveRecord Had After Using Ecto</title>
				<link>https://infinum.com/blog/things-i-wish-active-record-had-after-using-ecto/</link>
				<pubDate>Tue, 16 Jan 2018 10:10:00 +0000</pubDate>
				<dc:creator>Vladimir Rosancic</dc:creator>
				<guid isPermaLink="false">https://infinum.com/the-capsized-eight/things-i-wish-active-record-had-after-using-ecto/</guid>
				<description>
					<![CDATA[<p>Moving from one programming language to another is not hard as long as you have good knowledge of the concepts they share. </p>
<p>The post <a href="https://infinum.com/blog/things-i-wish-active-record-had-after-using-ecto/">Things I Wish ActiveRecord Had After Using Ecto</a> appeared first on <a href="https://infinum.com">Infinum</a>.</p>
]]>
				</description>
				<content:encoded>
					<![CDATA[<div
	class="wrapper"
	data-id="es-222"
	 data-animation-target='inner-items'>
		
			<div class="wrapper__inner">
			<div class="block-blog-content js-block-blog-content">
	
<div class="block-blog-content-sidebar" data-id="es-92">
	</div>

<div class="block-blog-content-main">
	
<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-95"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-93">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-94'
	>
	A few years ago, I wrote an article about <a href="https://infinum.com/blog/i-moved-from-django-to-rails-and-nothing-terrible-happened/">moving from Django to Rails</a>. As I said there, I don’t find it too hard moving from one programming language to another, as long as you have good knowledge on concepts they all share. Each language, of course, brings something on its own.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-98"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-96">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-97'
	>
	Last year, I decided to try something new. As a Ruby developer, Elixir proved to be a logical choice, and I have to admit, I am not disappointed. I fell in love with it at first sight, and I enjoy working with Elixir/Phoenix now.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-101"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-media">
	<div	class="media block-media__media media__border--none media__align--center-center"
	data-id="es-99"
	 data-media-type='image'>

	<figure class="image block-media__image-figure image--size-stretch" data-id="es-100">
	<picture class="image__picture block-media__image-picture">
								
			<source
				srcset=https://infinum.com/uploads/2018/01/things-i-wish-active-record-had-after-using-ecto-1-1400x840.webp				media='(max-width: 699px)'
				type=image/webp								height="840"
												width="1400"
				 />
												<img
					src="https://infinum.com/uploads/2018/01/things-i-wish-active-record-had-after-using-ecto-1.webp"
					class="image__img block-media__image-img"
					alt=""
										height="846"
															width="1410"
										loading="lazy"
					 />
					</picture>

	</figure></div></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-104"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-102">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-103'
	>
	One thing that I especially like is Ecto, a database wrapper, and a domain-specific language for writing queries in Elixir. Although it’s not entirely the same thing as Rails’ Active Record (Ecto is not ORM), they serve the same purpose.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-107"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-105">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-106'
	>
	In this article, I’ll write about few things I like about Ecto that aren’t available in Active Record. It’s not meant to be a “Phoenix is better than Rails” rant as both frameworks provide really great things and we can all learn from each of them.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-110"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-108">
	<h2	class='typography typography--size-52-default js-typography block-heading__heading'
	data-id='es-109'
	>
	Changesets</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-113"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-111">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-112'
	>
	When you want to insert or update the data in your database with Ecto, you should use changesets. As the official documentation says, they allow you to filter, cast and validate changes before you apply them to the data. When I first saw the concept of changesets, I thought of a form object pattern that I often use in Rails. Changesets, like form objects, allow you to have different ‘forms’ for various use cases. Think of a registration form vs. update profile form. Both operate on the same model (<code>User</code>), but they have different validations.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-115"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-elixir github-light" data-language="elixir" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token" style="color: #d73a49;">def</span><span class="token"> </span><span class="token" style="color: #6f42c1;">registration_changeset</span><span class="token">(</span><span class="token">struct</span><span class="token">,</span><span class="token"> params</span><span class="token">)</span><span class="token"> </span><span class="token" style="color: #d73a49;">do</span><span class="token">
</span></span><span class="line"><span class="token">  struct
</span></span><span class="line"><span class="token">  </span><span class="token" style="color: #d73a49;">|&gt;</span><span class="token"> </span><span class="token" style="color: #6f42c1;">cast</span><span class="token">(</span><span class="token">params</span><span class="token">,</span><span class="token"> </span><span class="token">[</span><span class="token" style="color: #005cc5;">:</span><span class="token" style="color: #005cc5;">email</span><span class="token">,</span><span class="token"> </span><span class="token" style="color: #005cc5;">:</span><span class="token" style="color: #005cc5;">password</span><span class="token">]</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">  </span><span class="token" style="color: #d73a49;">|&gt;</span><span class="token"> </span><span class="token" style="color: #6f42c1;">validate_required</span><span class="token">(</span><span class="token">[</span><span class="token" style="color: #005cc5;">:</span><span class="token" style="color: #005cc5;">email</span><span class="token">,</span><span class="token"> </span><span class="token" style="color: #005cc5;">:</span><span class="token" style="color: #005cc5;">password</span><span class="token">]</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">  </span><span class="token" style="color: #d73a49;">|&gt;</span><span class="token"> </span><span class="token" style="color: #6f42c1;">unique_constraint</span><span class="token">(</span><span class="token" style="color: #005cc5;">:</span><span class="token" style="color: #005cc5;">email</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">  </span><span class="token" style="color: #d73a49;">|&gt;</span><span class="token"> </span><span class="token" style="color: #6f42c1;">put_password_hash</span><span class="token">(</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token" style="color: #d73a49;">end</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token" style="color: #d73a49;">def</span><span class="token"> </span><span class="token" style="color: #6f42c1;">update_profile_changeset</span><span class="token">(</span><span class="token">struct</span><span class="token">,</span><span class="token"> params</span><span class="token">)</span><span class="token"> </span><span class="token" style="color: #d73a49;">do</span><span class="token">
</span></span><span class="line"><span class="token">  struct
</span></span><span class="line"><span class="token">  </span><span class="token" style="color: #d73a49;">|&gt;</span><span class="token"> </span><span class="token" style="color: #6f42c1;">cast</span><span class="token">(</span><span class="token">params</span><span class="token">,</span><span class="token"> </span><span class="token">[</span><span class="token" style="color: #005cc5;">:</span><span class="token" style="color: #005cc5;">first_name</span><span class="token">,</span><span class="token"> </span><span class="token" style="color: #005cc5;">:</span><span class="token" style="color: #005cc5;">last_name</span><span class="token">,</span><span class="token"> </span><span class="token" style="color: #005cc5;">:</span><span class="token" style="color: #005cc5;">age</span><span class="token">]</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">  </span><span class="token" style="color: #d73a49;">|&gt;</span><span class="token"> </span><span class="token" style="color: #6f42c1;">validate_required</span><span class="token">(</span><span class="token">[</span><span class="token" style="color: #005cc5;">:</span><span class="token" style="color: #005cc5;">first_name</span><span class="token">,</span><span class="token"> </span><span class="token" style="color: #005cc5;">:</span><span class="token" style="color: #005cc5;">last_name</span><span class="token">]</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token" style="color: #d73a49;">end</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-118"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-116">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-117'
	>
	To accomplish this in Active Record, you have to use conditional validations (if/unless) which is ugly and <strong>hard to reuse</strong>, or you would have to use external gems like <a href="https://github.com/makandra/active_type">Active Type</a> or <a href="https://github.com/trailblazer/reform">Reform</a>.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-121"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-119">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-120'
	>
	Ecto provides it out-of-the-box. The whole data manipulation philosophy in Ecto relies on the concept of small, <strong>reusable and modular</strong> changesets making it a powerful tool.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-124"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-122">
	<h2	class='typography typography--size-52-default js-typography block-heading__heading'
	data-id='es-123'
	>
	Validations use database constraints</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-127"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-125">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-126'
	>
	Ecto can transform database constraints, like unique indexes or foreign key checks, into errors. This allows for a consistent database while giving users proper feedback and friendly error messages.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-130"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-128">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-129'
	>
	Let’s say we have a unique index on <code>email</code> field in <code>users</code> table.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-132"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-elixir github-light" data-language="elixir" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token">create </span><span class="token" style="color: #6f42c1;">unique_index</span><span class="token">(</span><span class="token" style="color: #005cc5;">:</span><span class="token" style="color: #005cc5;">users</span><span class="token">,</span><span class="token"> </span><span class="token">[</span><span class="token" style="color: #005cc5;">:</span><span class="token" style="color: #005cc5;">email</span><span class="token">]</span><span class="token">)</span><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-135"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-133">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-134'
	>
	If we try to insert a user with an email that already exists, an exception will be raised with a message like this:</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-137"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-php github-light" data-language="php" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token">
</span></span><span class="line"><span class="token" style="color: #d73a49;">**</span><span class="token"> </span><span class="token">(</span><span class="token" style="color: #005cc5;">Ecto</span><span class="token" style="color: #d73a49;">.</span><span class="token" style="color: #005cc5;">ConstraintError</span><span class="token">)</span><span class="token"> </span><span class="token" style="color: #005cc5;">constraint</span><span class="token"> </span><span class="token" style="color: #005cc5;">error</span><span class="token"> </span><span class="token" style="color: #005cc5;">when</span><span class="token"> </span><span class="token" style="color: #005cc5;">attempting</span><span class="token"> </span><span class="token" style="color: #005cc5;">to</span><span class="token"> 
</span></span><span class="line"><span class="token" style="color: #005cc5;">insert</span><span class="token"> </span><span class="token" style="color: #005cc5;">struct</span><span class="token">:</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token" style="color: #d73a49;">*</span><span class="token"> </span><span class="token" style="color: #005cc5;">unique</span><span class="token">:</span><span class="token"> </span><span class="token" style="color: #005cc5;">users_email_index</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token" style="color: #005cc5;">If</span><span class="token"> </span><span class="token" style="color: #005cc5;">you</span><span class="token"> </span><span class="token" style="color: #005cc5;">would</span><span class="token"> </span><span class="token" style="color: #005cc5;">like</span><span class="token"> </span><span class="token" style="color: #005cc5;">to</span><span class="token"> </span><span class="token" style="color: #005cc5;">convert</span><span class="token"> </span><span class="token" style="color: #005cc5;">this</span><span class="token"> </span><span class="token" style="color: #005cc5;">constraint</span><span class="token"> </span><span class="token" style="color: #005cc5;">into</span><span class="token"> </span><span class="token" style="color: #005cc5;">an</span><span class="token"> </span><span class="token" style="color: #005cc5;">error</span><span class="token">,</span><span class="token"> </span><span class="token" style="color: #005cc5;">please</span><span class="token">
</span></span><span class="line"><span class="token" style="color: #005cc5;">call</span><span class="token"> </span><span class="token" style="color: #005cc5;">unique_constraint</span><span class="token" style="color: #d73a49;">/</span><span class="token" style="color: #005cc5;">3</span><span class="token"> </span><span class="token" style="color: #005cc5;">in</span><span class="token"> </span><span class="token" style="color: #005cc5;">your</span><span class="token"> </span><span class="token" style="color: #005cc5;">changeset</span><span class="token"> </span><span class="token" style="color: #d73a49;">and</span><span class="token"> </span><span class="token" style="color: #005cc5;">define</span><span class="token"> </span><span class="token" style="color: #005cc5;">the</span><span class="token"> </span><span class="token" style="color: #005cc5;">proper</span><span class="token">
</span></span><span class="line"><span class="token" style="color: #005cc5;">constraint</span><span class="token"> </span><span class="token" style="color: #005cc5;">name</span><span class="token" style="color: #d73a49;">.</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-140"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-138">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-139'
	>
	Let’s call the <code>unique_constraint/3</code> function in our changeset.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-142"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-elixir github-light" data-language="elixir" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token" style="color: #d73a49;">def</span><span class="token"> </span><span class="token" style="color: #6f42c1;">changeset</span><span class="token">(</span><span class="token">struct</span><span class="token">,</span><span class="token"> params</span><span class="token">)</span><span class="token"> </span><span class="token" style="color: #d73a49;">do</span><span class="token">
</span></span><span class="line"><span class="token">  struct
</span></span><span class="line"><span class="token">  </span><span class="token" style="color: #d73a49;">|&gt;</span><span class="token"> </span><span class="token" style="color: #6f42c1;">cast</span><span class="token">(</span><span class="token">params</span><span class="token">,</span><span class="token"> </span><span class="token">[</span><span class="token" style="color: #005cc5;">:</span><span class="token" style="color: #005cc5;">email</span><span class="token">]</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">  </span><span class="token" style="color: #d73a49;">|&gt;</span><span class="token"> </span><span class="token" style="color: #6f42c1;">unique_constraint</span><span class="token">(</span><span class="token" style="color: #005cc5;">:</span><span class="token" style="color: #005cc5;">email</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token" style="color: #d73a49;">end</span><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-145"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-143">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-144'
	>
	Now, if we try to do the same thing as above, Ecto will <strong>catch</strong> the exception and <strong>transform</strong> it into a readable changeset error:</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-147"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-elixir github-light" data-language="elixir" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token">changeset</span><span class="token">.</span><span class="token">errors
</span></span><span class="line"><span class="token">[</span><span class="token" style="color: #005cc5;">email</span><span class="token" style="color: #005cc5;">:</span><span class="token"> </span><span class="token">{</span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">has already been taken</span><span class="token" style="color: #032f62;">&quot;</span><span class="token">,</span><span class="token"> </span><span class="token">[</span><span class="token">]</span><span class="token">}</span><span class="token">]</span><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-150"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-148">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-149'
	>
	On the other hand, Active Record does not catch errors raised by the database, but rather checks the database state right before performing a validation. This could lead to <a href="http://nathanmlong.com/2017/02/guaranteed-consistency-the-case-for-database-constraints/">unwanted situations</a> in case of high traffic and a lot of parallel requests.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-153"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-151">
	<h2	class='typography typography--size-52-default js-typography block-heading__heading'
	data-id='es-152'
	>
	Preloading</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-156"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-154">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-155'
	>
	We all know that N+1 queries are a bad thing. In most cases, you want to lower the number of database queries in a single request. Both Active Record and Ecto provide a way to specify a list of associations that need to be fetched along with the main query.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-159"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-157">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-158'
	>
	The difference is that Ecto will enforce preloading if you want to use the associated resource (it will raise errors in case you don’t), while Active Record will load that resource at the time you use it. As I tend to forget to preload associations and because I don’t want bad things in my apps, I like Ecto’s enforcement.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-161"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-elixir github-light" data-language="elixir" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token">user </span><span class="token" style="color: #d73a49;">=</span><span class="token"> </span><span class="token" style="color: #6f42c1;">MyApp</span><span class="token">.</span><span class="token" style="color: #6f42c1;">Repo</span><span class="token">.</span><span class="token" style="color: #6f42c1;">get</span><span class="token">(</span><span class="token" style="color: #6f42c1;">MyApp</span><span class="token">.</span><span class="token" style="color: #6f42c1;">User</span><span class="token">,</span><span class="token"> </span><span class="token" style="color: #005cc5;">1</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">user</span><span class="token">.</span><span class="token">company
</span></span><span class="line"><span class="token" style="color: #6a737d;">#</span><span class="token" style="color: #6a737d;">Ecto.Association.NotLoaded&lt;association :company is not loaded&gt;</span><span class="token" style="color: #6a737d;">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-164"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-162">
	<h2	class='typography typography--size-52-default js-typography block-heading__heading'
	data-id='es-163'
	>
	Batch inserts</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-167"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-165">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-166'
	>
	To reduce the number of SQL queries, you might need to import data in batches. A use case could be to process data from large <a href="https://infinum.com/blog/superfast-csv-imports-using-postgresqls-copy/">.csv</a> or <a href="https://infinum.com/blog/how-to-efficiently-process-large-excel-files-using-ruby/">.xls</a> tables. For that purpose, we use SQL’s INSERT statement with multiple rows.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-170"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-168">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-169'
	>
	In Rails, we could use a gem like <a href="https://github.com/zdennis/activerecord-import">Active Record Import</a> or similar, but there is no built-in solution. Although Active Record’s <code>create</code> method can accept an array of objects, it does not perform a batch insert, but rather inserts each record one by one.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-173"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-171">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-172'
	>
	Ecto provides a built-in function called <code>insert_all/3</code> that performs batch inserts and it works well.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-175"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-elixir github-light" data-language="elixir" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token" style="color: #6f42c1;">MyApp</span><span class="token">.</span><span class="token" style="color: #6f42c1;">Repo</span><span class="token">.</span><span class="token" style="color: #6f42c1;">insert_all</span><span class="token">(</span><span class="token">
</span></span><span class="line"><span class="token">  </span><span class="token" style="color: #6f42c1;">User</span><span class="token">,</span><span class="token"> 
</span></span><span class="line"><span class="token">  </span><span class="token">[</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token">[</span><span class="token">
</span></span><span class="line"><span class="token">      </span><span class="token" style="color: #005cc5;">first_name</span><span class="token" style="color: #005cc5;">:</span><span class="token"> </span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">John</span><span class="token" style="color: #032f62;">&quot;</span><span class="token">,</span><span class="token"> 
</span></span><span class="line"><span class="token">      </span><span class="token" style="color: #005cc5;">last_name</span><span class="token" style="color: #005cc5;">:</span><span class="token"> </span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">Doe</span><span class="token" style="color: #032f62;">&quot;</span><span class="token">,</span><span class="token"> 
</span></span><span class="line"><span class="token">      </span><span class="token" style="color: #005cc5;">email</span><span class="token" style="color: #005cc5;">:</span><span class="token"> </span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">john.doe@example.com</span><span class="token" style="color: #032f62;">&quot;</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token">]</span><span class="token">,</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token">[</span><span class="token">
</span></span><span class="line"><span class="token">      </span><span class="token" style="color: #005cc5;">first_name</span><span class="token" style="color: #005cc5;">:</span><span class="token"> </span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">Jane</span><span class="token" style="color: #032f62;">&quot;</span><span class="token">,</span><span class="token"> 
</span></span><span class="line"><span class="token">      </span><span class="token" style="color: #005cc5;">last_name</span><span class="token" style="color: #005cc5;">:</span><span class="token"> </span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">Doe</span><span class="token" style="color: #032f62;">&quot;</span><span class="token">,</span><span class="token"> 
</span></span><span class="line"><span class="token">      </span><span class="token" style="color: #005cc5;">email</span><span class="token" style="color: #005cc5;">:</span><span class="token"> </span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">jane.doe@example.com</span><span class="token" style="color: #032f62;">&quot;</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token">]</span><span class="token">
</span></span><span class="line"><span class="token">  </span><span class="token">]</span><span class="token">
</span></span><span class="line"><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-178"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-176">
	<h2	class='typography typography--size-52-default js-typography block-heading__heading'
	data-id='es-177'
	>
	Repo.one</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-181"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-179">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-180'
	>
	Sometimes you expect only one record to be returned by your query. If you get more than one, you know something is wrong. Ecto provides a function called <code>one</code> that will fetch a single result from the query. It raises an exception if more than one entry is returned.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-184"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-182">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-183'
	>
	Imagine we have a unique index on <code>nickname</code> field in <code>users</code> table.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-187"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-185">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-186'
	>
	Somewhere in our code, we have a query to find a user with the specified nickname:</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-189"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-elixir github-light" data-language="elixir" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token">query </span><span class="token" style="color: #d73a49;">=</span><span class="token"> from u </span><span class="token" style="color: #d73a49;">in</span><span class="token"> </span><span class="token" style="color: #6f42c1;">User</span><span class="token">,</span><span class="token"> </span><span class="token" style="color: #005cc5;">where</span><span class="token" style="color: #005cc5;">:</span><span class="token"> u</span><span class="token">.</span><span class="token">nickname </span><span class="token" style="color: #d73a49;">==</span><span class="token"> </span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">mickey</span><span class="token" style="color: #032f62;">&quot;</span><span class="token">
</span></span><span class="line"><span class="token" style="color: #6f42c1;">Repo</span><span class="token">.</span><span class="token" style="color: #6f42c1;">one</span><span class="token">(</span><span class="token">query</span><span class="token">)</span><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-192"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-190">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-191'
	>
	As we know we have a unique index, we are expecting only one result.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-195"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-193">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-194'
	>
	After some time, our business logic changes, and we add another field to our unique index – <code>group_id</code>. Now we can have multiple users with the same nickname, but in different groups.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-198"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-196">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-197'
	>
	Let’s assume that we changed our index, but forgot to change the query in the code; when we query on a nickname that is the same for multiple users, Ecto will raise the following error:</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-200"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-elixir github-light" data-language="elixir" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token" style="color: #d73a49;">*</span><span class="token" style="color: #d73a49;">*</span><span class="token"> </span><span class="token">(</span><span class="token" style="color: #6f42c1;">Ecto</span><span class="token">.</span><span class="token" style="color: #6f42c1;">MultipleResultsError</span><span class="token">)</span><span class="token"> expected at most one result but 
</span></span><span class="line"><span class="token">got </span><span class="token" style="color: #005cc5;">2</span><span class="token"> </span><span class="token" style="color: #d73a49;">in</span><span class="token"> query
</span></span><span class="line"><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-203"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-201">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-202'
	>
	If <code>Repo.one</code> didn’t raise the error on multiple results, we probably wouldn’t easily notice that something is wrong. Our business logic would continue to work with the <strong>first</strong> user returned by the database, not necessarily the <strong>right</strong> one.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-206"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-204">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-205'
	>
	If we compare this with Active Record, methods like <code>find_by</code> would return the first record matching the specified conditions.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-209"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-207">
	<h2	class='typography typography--size-52-default js-typography block-heading__heading'
	data-id='es-208'
	>
	Ecto query language</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-212"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-210">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-211'
	>
	Last, but not least, I like the way queries are written in Ecto. They just feel natural and SQL-ish to me. Let me give you an example of a query written in Ecto:</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-214"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-elixir github-light" data-language="elixir" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token">from user </span><span class="token" style="color: #d73a49;">in</span><span class="token"> </span><span class="token" style="color: #6f42c1;">User</span><span class="token">,</span><span class="token">
</span></span><span class="line"><span class="token" style="color: #005cc5;">left_join</span><span class="token" style="color: #005cc5;">:</span><span class="token"> company </span><span class="token" style="color: #d73a49;">in</span><span class="token"> </span><span class="token" style="color: #6f42c1;">assoc</span><span class="token">(</span><span class="token">user</span><span class="token">,</span><span class="token"> </span><span class="token" style="color: #005cc5;">:</span><span class="token" style="color: #005cc5;">company</span><span class="token">)</span><span class="token">,</span><span class="token">
</span></span><span class="line"><span class="token" style="color: #005cc5;">where</span><span class="token" style="color: #005cc5;">:</span><span class="token"> user</span><span class="token">.</span><span class="token">age </span><span class="token" style="color: #d73a49;">&lt;</span><span class="token"> </span><span class="token" style="color: #005cc5;">25</span><span class="token"> </span><span class="token" style="color: #d73a49;">or</span><span class="token"> user</span><span class="token">.</span><span class="token">age </span><span class="token" style="color: #d73a49;">&gt;</span><span class="token"> </span><span class="token" style="color: #005cc5;">60</span><span class="token">,</span><span class="token">
</span></span><span class="line"><span class="token" style="color: #005cc5;">select</span><span class="token" style="color: #005cc5;">:</span><span class="token"> %</span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">  </span><span class="token" style="color: #005cc5;">first_name</span><span class="token" style="color: #005cc5;">:</span><span class="token"> user</span><span class="token">.</span><span class="token">first_name</span><span class="token">,</span><span class="token"> 
</span></span><span class="line"><span class="token">  </span><span class="token" style="color: #005cc5;">last_name</span><span class="token" style="color: #005cc5;">:</span><span class="token"> user</span><span class="token">.</span><span class="token">last_name</span><span class="token">,</span><span class="token">
</span></span><span class="line"><span class="token">  </span><span class="token" style="color: #005cc5;">age</span><span class="token" style="color: #005cc5;">:</span><span class="token"> user</span><span class="token">.</span><span class="token">age</span><span class="token">,</span><span class="token">
</span></span><span class="line"><span class="token">  </span><span class="token" style="color: #005cc5;">company</span><span class="token" style="color: #005cc5;">:</span><span class="token"> company</span><span class="token">.</span><span class="token">name
</span></span><span class="line"><span class="token">}</span><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-217"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-215">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-216'
	>
	Isn’t that beautiful?</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-220"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-218">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-219'
	>
	While there are some things I didn’t cover in this article, it’s a brief overview of things I love about Ecto. Feel free to comment about things you love about each of these libraries.</p></div>	</div>
</div>
</div>		</div>
	</div><p>The post <a href="https://infinum.com/blog/things-i-wish-active-record-had-after-using-ecto/">Things I Wish ActiveRecord Had After Using Ecto</a> appeared first on <a href="https://infinum.com">Infinum</a>.</p>
]]>
				</content:encoded>
			</item>
					<item>
				<image>
					<url>7870https://infinum.com/uploads/2017/02/how-to-efficiently-process-large-excel-files-using-ruby-0.webp</url>
				</image>
				<title>How to Efficiently Process Large Excel Files Using Ruby</title>
				<link>https://infinum.com/blog/how-to-efficiently-process-large-excel-files-using-ruby/</link>
				<pubDate>Wed, 15 Jun 2016 12:30:00 +0000</pubDate>
				<dc:creator>Vladimir Rosancic</dc:creator>
				<guid isPermaLink="false">https://infinum.com/the-capsized-eight/how-to-efficiently-process-large-excel-files-using-ruby/</guid>
				<description>
					<![CDATA[<p>Last year, I worked on a project in which I needed to parse and handle large .xlsx files. Some of those files had more than 200K rows. </p>
<p>The post <a href="https://infinum.com/blog/how-to-efficiently-process-large-excel-files-using-ruby/">How to Efficiently Process Large Excel Files Using Ruby</a> appeared first on <a href="https://infinum.com">Infinum</a>.</p>
]]>
				</description>
				<content:encoded>
					<![CDATA[<div
	class="wrapper"
	data-id="es-251"
	 data-animation-target='inner-items'>
		
			<div class="wrapper__inner">
			<div class="block-blog-content js-block-blog-content">
	
<div class="block-blog-content-sidebar" data-id="es-223">
	</div>

<div class="block-blog-content-main">
	
<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-226"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-224">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-225'
	>
	Last year, I worked on a project in which I needed to parse and handle large .xlsx files. Some of those files had more than 200K rows. I was looking for a gem that could efficiently do the job.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-229"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-media">
	<div	class="media block-media__media media__border--none media__align--center-center"
	data-id="es-227"
	 data-media-type='image'>

	<figure class="image block-media__image-figure image--size-stretch" data-id="es-228">
	<picture class="image__picture block-media__image-picture">
												<img
					src="https://infinum.com/uploads/2017/02/how-to-efficiently-process-large-excel-files-using-ruby-1.webp"
					class="image__img block-media__image-img"
					alt=""
										height="391"
															width="1000"
										loading="lazy"
					 />
					</picture>

	</figure></div></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-232"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-230">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-231'
	>
	I wanted a simple solution that would just iterate over each row, parse the contents of the row and save data in database tables.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-235"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-233">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-234'
	>
	Popular gems in that time were <a href="https://github.com/roo-rb/roo">Roo</a> and <a href="https://github.com/zdavatz/spreadsheet">Spreadsheet</a>. I also found a simple gem called <a href="https://github.com/woahdae/simple_xlsx_reader">Simple xlsx reader</a> that was easy to use and had everything I needed. Except one thing.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-238"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-236">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-237'
	>
	When I called <em>SimpleXlsxReader.open(file_path)</em>, memory consumption would go to <strong>2GB</strong> and it would stay that way until the garbage collector cleaned it.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-241"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-239">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-240'
	>
	What I needed was a library that would read Excel rows in streams. At that time, none of the mentioned gems had that ability. I found a gem called <a href="https://github.com/pythonicrubyist/creek">Creek</a> that does only that – stream parsing large excel files. It is simple and works well. Memory consumption while parsing these files was now under <strong>200 MB</strong>, which is acceptable. In the meantime, Roo was updated and now it <a href="https://github.com/roo-rb/roo#excel-xlsx-and-xlsm-support">has the same ability</a>.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-244"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-242">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-243'
	>
	Also, to reduce the number of SQL queries, I implemented saving data in batches – 1000 rows in 1 query. So, my method reads a thousand rows, makes an array of ActiveRecord objects and then saves them at once. I used the gem called <a href="https://github.com/zdennis/activerecord-import">ActiveRecord Import</a> for this purpose.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-246"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-ruby github-light" data-language="ruby" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token" style="color: #d73a49;">class</span><span class="token"> </span><span class="token" style="color: #6f42c1;">ExcelDataParser</span><span class="token">
</span></span><span class="line"><span class="token">  </span><span class="token" style="color: #d73a49;">def</span><span class="token"> </span><span class="token" style="color: #6f42c1;">initialize</span><span class="token">(</span><span class="token">file_path</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token" style="color: #24292e;">@</span><span class="token" style="color: #24292e;">file_path</span><span class="token"> </span><span class="token" style="color: #d73a49;">=</span><span class="token"> file_path
</span></span><span class="line"><span class="token">    </span><span class="token" style="color: #24292e;">@</span><span class="token" style="color: #24292e;">records</span><span class="token"> </span><span class="token" style="color: #d73a49;">=</span><span class="token"> </span><span class="token">[</span><span class="token">]</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token" style="color: #24292e;">@</span><span class="token" style="color: #24292e;">counter</span><span class="token"> </span><span class="token" style="color: #d73a49;">=</span><span class="token"> </span><span class="token" style="color: #005cc5;">1</span><span class="token">
</span></span><span class="line"><span class="token">  </span><span class="token" style="color: #d73a49;">end</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">  </span><span class="token" style="color: #005cc5;">BATCH_IMPORT_SIZE</span><span class="token"> </span><span class="token" style="color: #d73a49;">=</span><span class="token"> </span><span class="token" style="color: #005cc5;">1000</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">  </span><span class="token" style="color: #d73a49;">def</span><span class="token"> </span><span class="token" style="color: #6f42c1;">call</span><span class="token">
</span></span><span class="line"><span class="token">    rows</span><span class="token">.</span><span class="token" style="color: #6f42c1;">each</span><span class="token"> </span><span class="token" style="color: #d73a49;">do</span><span class="token"> </span><span class="token" style="color: #d73a49;">|</span><span class="token">row</span><span class="token" style="color: #d73a49;">|</span><span class="token">
</span></span><span class="line"><span class="token">      increment_counter
</span></span><span class="line"><span class="token">      records </span><span class="token" style="color: #d73a49;">&lt;&lt;</span><span class="token"> </span><span class="token" style="color: #6f42c1;">build_new_record</span><span class="token">(</span><span class="token">row</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">      import_records </span><span class="token" style="color: #d73a49;">if</span><span class="token"> reached_batch_import_size? </span><span class="token" style="color: #d73a49;">||</span><span class="token"> reached_end_of_file?
</span></span><span class="line"><span class="token">    </span><span class="token" style="color: #d73a49;">end</span><span class="token">
</span></span><span class="line"><span class="token">  </span><span class="token" style="color: #d73a49;">end</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">  </span><span class="token" style="color: #d73a49;">private</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">  </span><span class="token" style="color: #d73a49;">attr_reader</span><span class="token"> </span><span class="token" style="color: #005cc5;">:</span><span class="token" style="color: #005cc5;">file_path</span><span class="token">,</span><span class="token"> </span><span class="token" style="color: #005cc5;">:</span><span class="token" style="color: #005cc5;">records</span><span class="token">
</span></span><span class="line"><span class="token">  </span><span class="token" style="color: #d73a49;">attr_accessor</span><span class="token"> </span><span class="token" style="color: #005cc5;">:</span><span class="token" style="color: #005cc5;">counter</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">  </span><span class="token" style="color: #d73a49;">def</span><span class="token"> </span><span class="token" style="color: #6f42c1;">book</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token" style="color: #24292e;">@</span><span class="token" style="color: #24292e;">book</span><span class="token"> </span><span class="token" style="color: #d73a49;">||=</span><span class="token"> </span><span class="token" style="color: #005cc5;">Creek</span><span class="token">::</span><span class="token" style="color: #005cc5;">Book</span><span class="token">.</span><span class="token" style="color: #d73a49;">new</span><span class="token">(</span><span class="token">file_path</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">  </span><span class="token" style="color: #d73a49;">end</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">  </span><span class="token" style="color: #6a737d;">#</span><span class="token" style="color: #6a737d;"> in this example, we assume that the</span><span class="token" style="color: #6a737d;">
</span></span><span class="line"><span class="token">  </span><span class="token" style="color: #6a737d;">#</span><span class="token" style="color: #6a737d;"> content is in the first Excel sheet</span><span class="token" style="color: #6a737d;">
</span></span><span class="line"><span class="token">  </span><span class="token" style="color: #d73a49;">def</span><span class="token"> </span><span class="token" style="color: #6f42c1;">rows</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token" style="color: #24292e;">@</span><span class="token" style="color: #24292e;">rows</span><span class="token"> </span><span class="token" style="color: #d73a49;">||=</span><span class="token"> book</span><span class="token">.</span><span class="token" style="color: #6f42c1;">sheets</span><span class="token">.</span><span class="token" style="color: #6f42c1;">first</span><span class="token">.</span><span class="token" style="color: #6f42c1;">rows</span><span class="token">
</span></span><span class="line"><span class="token">  </span><span class="token" style="color: #d73a49;">end</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">  </span><span class="token" style="color: #d73a49;">def</span><span class="token"> </span><span class="token" style="color: #6f42c1;">increment_counter</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token" style="color: #005cc5;">self</span><span class="token">.</span><span class="token" style="color: #6f42c1;">counter</span><span class="token"> </span><span class="token" style="color: #d73a49;">+=</span><span class="token"> </span><span class="token" style="color: #005cc5;">1</span><span class="token">
</span></span><span class="line"><span class="token">  </span><span class="token" style="color: #d73a49;">end</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">  </span><span class="token" style="color: #d73a49;">def</span><span class="token"> </span><span class="token" style="color: #6f42c1;">row_count</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token" style="color: #24292e;">@</span><span class="token" style="color: #24292e;">row_count</span><span class="token"> </span><span class="token" style="color: #d73a49;">||=</span><span class="token"> rows</span><span class="token">.</span><span class="token" style="color: #6f42c1;">count</span><span class="token">
</span></span><span class="line"><span class="token">  </span><span class="token" style="color: #d73a49;">end</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">  </span><span class="token" style="color: #d73a49;">def</span><span class="token"> </span><span class="token" style="color: #6f42c1;">build_new_record</span><span class="token">(</span><span class="token">row</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token" style="color: #6a737d;">#</span><span class="token" style="color: #6a737d;"> only build a new record without saving it</span><span class="token" style="color: #6a737d;">
</span></span><span class="line"><span class="token">    </span><span class="token" style="color: #005cc5;">RecordModel</span><span class="token">.</span><span class="token" style="color: #d73a49;">new</span><span class="token">(</span><span class="token">.</span><span class="token">.</span><span class="token">.</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">  </span><span class="token" style="color: #d73a49;">end</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">  </span><span class="token" style="color: #d73a49;">def</span><span class="token"> </span><span class="token" style="color: #6f42c1;">import_records</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token" style="color: #6a737d;">#</span><span class="token" style="color: #6a737d;"> save multiple records using activerecord-import gem</span><span class="token" style="color: #6a737d;">
</span></span><span class="line"><span class="token">    </span><span class="token" style="color: #005cc5;">RecordModel</span><span class="token">.</span><span class="token" style="color: #6f42c1;">import</span><span class="token">(</span><span class="token">records</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token" style="color: #6a737d;">#</span><span class="token" style="color: #6a737d;"> clear records array</span><span class="token" style="color: #6a737d;">
</span></span><span class="line"><span class="token">    records</span><span class="token">.</span><span class="token" style="color: #6f42c1;">clear</span><span class="token">
</span></span><span class="line"><span class="token">  </span><span class="token" style="color: #d73a49;">end</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">  </span><span class="token" style="color: #d73a49;">def</span><span class="token"> </span><span class="token" style="color: #6f42c1;">reached_batch_import_size?</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token">(</span><span class="token">counter </span><span class="token" style="color: #d73a49;">%</span><span class="token"> </span><span class="token" style="color: #005cc5;">BATCH_IMPORT_SIZE</span><span class="token">)</span><span class="token">.</span><span class="token" style="color: #6f42c1;">zero?</span><span class="token">
</span></span><span class="line"><span class="token">  </span><span class="token" style="color: #d73a49;">end</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">  </span><span class="token" style="color: #d73a49;">def</span><span class="token"> </span><span class="token" style="color: #6f42c1;">reached_end_of_file?</span><span class="token">
</span></span><span class="line"><span class="token">    counter </span><span class="token" style="color: #d73a49;">==</span><span class="token"> row_count
</span></span><span class="line"><span class="token">  </span><span class="token" style="color: #d73a49;">end</span><span class="token">
</span></span><span class="line"><span class="token" style="color: #d73a49;">end</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-249"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-247">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-248'
	>
	Finally, this task is being executed asynchronously in a background job since it’s too heavy to handle in the web process.</p></div>	</div>
</div>
</div>		</div>
	</div><p>The post <a href="https://infinum.com/blog/how-to-efficiently-process-large-excel-files-using-ruby/">How to Efficiently Process Large Excel Files Using Ruby</a> appeared first on <a href="https://infinum.com">Infinum</a>.</p>
]]>
				</content:encoded>
			</item>
					<item>
				<image>
					<url>8034https://infinum.com/uploads/2015/02/i-moved-from-django-to-rails-and-nothing-terrible-happened-0.webp</url>
				</image>
				<title>I Moved from Django to Rails  and Nothing Terrible Happened</title>
				<link>https://infinum.com/blog/i-moved-from-django-to-rails-and-nothing-terrible-happened/</link>
				<pubDate>Tue, 10 Feb 2015 07:14:00 +0000</pubDate>
				<dc:creator>Vladimir Rosancic</dc:creator>
				<guid isPermaLink="false">https://infinum.com/the-capsized-eight/i-moved-from-django-to-rails-and-nothing-terrible-happened/</guid>
				<description>
					<![CDATA[<p>I try to cover my own experience of moving from a Python-based web framework to a Ruby-based one.</p>
<p>The post <a href="https://infinum.com/blog/i-moved-from-django-to-rails-and-nothing-terrible-happened/">I Moved from Django to Rails  and Nothing Terrible Happened</a> appeared first on <a href="https://infinum.com">Infinum</a>.</p>
]]>
				</description>
				<content:encoded>
					<![CDATA[<div
	class="wrapper"
	data-id="es-338"
	 data-animation-target='inner-items'>
		
			<div class="wrapper__inner">
			<div class="block-blog-content js-block-blog-content">
	
<div class="block-blog-content-sidebar" data-id="es-252">
	</div>

<div class="block-blog-content-main">
	
<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-255"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-253">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-254'
	>
	Rails vs. Django, an age-old debate in the web-development community. In this article, I’ll try to cover my own experience of moving from a Python-based web framework to a Ruby-based one.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-258"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-256">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-257'
	>
	The story begins with me graduating from university. My first job was in a media company that runs a number of large web portals, news websites and other online publications. I worked on developing and maintaining those websites as a Django developer. As you can imagine, it was a great and challenging job for a fresh programmer. But just as I settled in and became comfortable working in Django, an opportunity arose to work at Infinum as a Ruby on Rails developer.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-261"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-media">
	<div	class="media block-media__media media__border--none media__align--center-center"
	data-id="es-259"
	 data-media-type='image'>

	<figure class="image block-media__image-figure image--size-stretch" data-id="es-260">
	<picture class="image__picture block-media__image-picture">
												<img
					src="https://infinum.com/uploads/2015/02/i-moved-from-django-to-rails-and-nothing-terrible-happened-1.webp"
					class="image__img block-media__image-img"
					alt=""
										height="400"
															width="700"
										loading="lazy"
					 />
					</picture>

	</figure></div></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-264"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-262">
	<h2	class='typography typography--size-52-default js-typography block-heading__heading'
	data-id='es-263'
	>
	Getting started is weird</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-267"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-265">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-266'
	>
	It was a tough decision for me, but I decided to be brave and accept new challenges. One of the most motivating things for me was the <a href="https://infinum.com/careers/">fantastic work atmosphere and culture here at Infinum</a>. I decided to learn Rails, and now, after 4 months, I have no regrets about making the switch.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-270"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-268">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-269'
	>
	In the beginning, some concepts were a bit strange to me. The Rails “convention over configuration” philosophy caused some confusion in my head because there was too much “magic” going on. When people talk about “magic” in Rails, they usually refer to things that the framework does “on its own”, but which you are required to know about. This is described in this <a href="http://stackoverflow.com/questions/441717/whats-wrong-with-magic">StackOverflow article</a>:</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-273"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-271">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-272'
	>
	Well, consider a couple bits of Rails “magic”: when you write a controller class, its methods have access to certain variables and certain other classes. But these variables and classes were neither defined nor imported by anything in the file of Ruby code you’re looking at; Rails has done a lot of work behind the scenes to ensure they’ll just be there automatically.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-276"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-274">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-275'
	>
	And when you return something from a controller method, Rails makes sure the result is passed along to the appropriate template; you don’t have to write any code to tell it which template to use, where to find it, etc., etc.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-281"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="blockquote block-blockquote__blockquote" data-id="es-277">
	
	<div class="blockquote__content">
		<i
	class="icon blockquote__icon icon--size-16 icon--scale-100"
	 aria-hidden='true' data-name='blockquote-24' data-id='es-278'>
	<svg fill='none' height='24' viewBox='0 0 24 24' width='24' xmlns='http://www.w3.org/2000/svg'><path clip-rule='evenodd' d='m12 24c6.6274 0 12-5.3726 12-12 0-2.79685-.9568-5.37021-2.561-7.41062-.581.22951-1.0832.60583-1.5069 1.12898-.5132.60844-.7698 1.41969-.7698 2.43375v.07605h2.5789v5.59004h-5.6197v-5.01962c0-1.11547.154-2.06616.4619-2.85205.3336-.81125.757-1.48307 1.2702-2.01545.528-.52161 1.1175-.92155 1.7687-1.1998-2.0728-1.70651-4.7279-2.73128-7.6223-2.73128-6.62742 0-12 5.37258-12 12 0 6.6274 5.37258 12 12 12zm-3.53811-18.05347c-.30793.78589-.46189 1.73658-.46189 2.85205v5.01962h5.6197v-5.59004h-2.5789v-.07605c0-1.01406.2566-1.82531.7698-2.43375.5389-.63379 1.1804-1.05209 1.9245-1.2549v-2.28164c-.7441.07605-1.4626.25351-2.1555.53238-.6928.27887-1.3086.68449-1.84752 1.21688-.51321.53238-.9366 1.2042-1.27019 2.01545z' fill='currentColor' fill-rule='evenodd'/></svg></i><p	class='typography typography--size-36-text js-typography blockquote__quote'
	data-id='es-279'
	>
	In other words, it’s as if these things happen by “magic”; you don’t have to lift a finger, they just happen for you.</p>
		<div class="blockquote__caption-wrap">
					</div>
	</div>
</div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-284"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-282">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-283'
	>
	I had to learn to be more careful about naming conventions and the directory structure because Rails relies on those things to work its magic.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-287"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-285">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-286'
	>
	Shortly after that, I started noticing many similarities to the Django framework and very soon I learned how to do things in Rails that I knew how to do in Django. Almost everything that’s possible to do with one framework is doable in the other as well. The time required to start working on real-world projects was <strong>significantly shorter because of my Django experience</strong>.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-290"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-288">
	<h2	class='typography typography--size-52-default js-typography block-heading__heading'
	data-id='es-289'
	>
	Writing more tests</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-293"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-291">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-292'
	>
	What confused me at first later became the thing that I love about Rails. Rails’ magic results in higher productivity and a cleaner code, for example in controllers. Controllers can look really nice, short and sweet. I like the Rails RESTful orientation – routes and controllers are designed in a way that it is best for you to follow the REST architecture.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-295"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-ruby github-light" data-language="ruby" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token" style="color: #6a737d;">#</span><span class="token" style="color: #6a737d;"> in routes.rb</span><span class="token" style="color: #6a737d;">
</span></span><span class="line"><span class="token">resources </span><span class="token" style="color: #005cc5;">:</span><span class="token" style="color: #005cc5;">orders</span><span class="token">,</span><span class="token"> </span><span class="token" style="color: #005cc5;">only</span><span class="token" style="color: #005cc5;">:</span><span class="token"> </span><span class="token">[</span><span class="token" style="color: #005cc5;">:</span><span class="token" style="color: #005cc5;">index</span><span class="token">,</span><span class="token"> </span><span class="token" style="color: #005cc5;">:</span><span class="token" style="color: #005cc5;">show</span><span class="token">,</span><span class="token"> </span><span class="token" style="color: #005cc5;">:</span><span class="token" style="color: #005cc5;">new</span><span class="token">,</span><span class="token"> </span><span class="token" style="color: #005cc5;">:</span><span class="token" style="color: #005cc5;">create</span><span class="token">]</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token" style="color: #6a737d;">#</span><span class="token" style="color: #6a737d;"> orders_controller.rb</span><span class="token" style="color: #6a737d;">
</span></span><span class="line"><span class="token" style="color: #d73a49;">class</span><span class="token"> </span><span class="token" style="color: #6f42c1;">OrdersController</span><span class="token"> </span><span class="token">&lt;</span><span class="token"> </span><span class="token" style="color: #6f42c1;">ApplicationController</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">  </span><span class="token" style="color: #d73a49;">def</span><span class="token"> </span><span class="token" style="color: #6f42c1;">index</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token" style="color: #24292e;">@</span><span class="token" style="color: #24292e;">orders</span><span class="token"> </span><span class="token" style="color: #d73a49;">=</span><span class="token"> </span><span class="token" style="color: #005cc5;">Order</span><span class="token">.</span><span class="token" style="color: #6f42c1;">where</span><span class="token">(</span><span class="token" style="color: #005cc5;">active</span><span class="token" style="color: #005cc5;">:</span><span class="token"> </span><span class="token" style="color: #005cc5;">true</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">  </span><span class="token" style="color: #d73a49;">end</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">  </span><span class="token" style="color: #d73a49;">def</span><span class="token"> </span><span class="token" style="color: #6f42c1;">show</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token" style="color: #24292e;">@</span><span class="token" style="color: #24292e;">order</span><span class="token"> </span><span class="token" style="color: #d73a49;">=</span><span class="token"> </span><span class="token" style="color: #005cc5;">Order</span><span class="token">.</span><span class="token" style="color: #6f42c1;">find</span><span class="token">(</span><span class="token">params</span><span class="token">[</span><span class="token" style="color: #005cc5;">:</span><span class="token" style="color: #005cc5;">id</span><span class="token">]</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">  </span><span class="token" style="color: #d73a49;">end</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">  </span><span class="token" style="color: #d73a49;">def</span><span class="token"> </span><span class="token" style="color: #6f42c1;">new</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token" style="color: #24292e;">@</span><span class="token" style="color: #24292e;">order</span><span class="token"> </span><span class="token" style="color: #d73a49;">=</span><span class="token"> </span><span class="token" style="color: #005cc5;">Order</span><span class="token">.</span><span class="token" style="color: #d73a49;">new</span><span class="token">
</span></span><span class="line"><span class="token">  </span><span class="token" style="color: #d73a49;">end</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">  </span><span class="token" style="color: #d73a49;">def</span><span class="token"> </span><span class="token" style="color: #6f42c1;">create</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token" style="color: #24292e;">@</span><span class="token" style="color: #24292e;">order</span><span class="token"> </span><span class="token" style="color: #d73a49;">=</span><span class="token"> </span><span class="token" style="color: #005cc5;">Order</span><span class="token">.</span><span class="token" style="color: #d73a49;">new</span><span class="token">(</span><span class="token">params</span><span class="token">[</span><span class="token" style="color: #005cc5;">:</span><span class="token" style="color: #005cc5;">order</span><span class="token">]</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token" style="color: #d73a49;">if</span><span class="token"> </span><span class="token" style="color: #24292e;">@</span><span class="token" style="color: #24292e;">order</span><span class="token">.</span><span class="token" style="color: #6f42c1;">save</span><span class="token">
</span></span><span class="line"><span class="token">      redirect_to </span><span class="token" style="color: #24292e;">@</span><span class="token" style="color: #24292e;">order</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token" style="color: #d73a49;">else</span><span class="token">
</span></span><span class="line"><span class="token">      render ’</span><span class="token" style="color: #d73a49;">new</span><span class="token">’
</span></span><span class="line"><span class="token">    </span><span class="token" style="color: #d73a49;">end</span><span class="token">
</span></span><span class="line"><span class="token">  </span><span class="token" style="color: #d73a49;">end</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token" style="color: #d73a49;">end</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-298"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-296">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-297'
	>
	At Infinum, I started to write more tests than before. Rails places extra emphasis on <a href="https://infinum.com/blog/a-ruby-on-rails-continous-integration-process-using-semaphore-github-codeclimate-and-hipchat/">testing</a> and soon I realized how useful tests can be. Many great gems are made in order to make testing simple and clean.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-301"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-299">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-300'
	>
	The Rails asset pipeline is a great solution for managing static files (CSS, JS). I like the fact that I don’t need to worry about concatenating and minifying them. In Django, there is no built-in solution for this problem.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-304"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-302">
	<h2	class='typography typography--size-52-default js-typography block-heading__heading'
	data-id='es-303'
	>
	What I miss from Django</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-307"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-305">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-306'
	>
	There are some things from Django I still miss. For example, I miss Django’s way of database migration. When you want to make a change to some table, all you have to do is directly change the model file and start the migration. When you change the model, the corresponding table in the database also changes. This way, you have your model definition and fields in one place.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-310"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-308">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-309'
	>
	In contrast, in Rails you don’t change the model file, but generate a migration file for every change you want to make. You don’t have a list of model fields in the model definition and you cannot change it directly like you can in Django.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-313"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-311">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-312'
	>
	Here is an example of how you do database migration in Django:</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-315"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-python github-light" data-language="python" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token" style="color: #6a737d;">#</span><span class="token" style="color: #6a737d;"> Author model before migration</span><span class="token">
</span></span><span class="line"><span class="token" style="color: #d73a49;">class</span><span class="token"> </span><span class="token" style="color: #6f42c1;">Author</span><span class="token">(</span><span class="token" style="color: #6f42c1;">models</span><span class="token">.</span><span class="token" style="color: #6f42c1;">Model</span><span class="token">)</span><span class="token">:</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token">name</span><span class="token"> </span><span class="token" style="color: #d73a49;">=</span><span class="token"> </span><span class="token">models</span><span class="token">.</span><span class="token">CharField</span><span class="token">(</span><span class="token" style="color: #e36209;">max_length</span><span class="token" style="color: #d73a49;">=</span><span class="token" style="color: #005cc5;">80</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token">slug</span><span class="token"> </span><span class="token" style="color: #d73a49;">=</span><span class="token"> </span><span class="token">models</span><span class="token">.</span><span class="token">SlugField</span><span class="token">(</span><span class="token" style="color: #e36209;">max_length</span><span class="token" style="color: #d73a49;">=</span><span class="token" style="color: #005cc5;">80</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token">is_active</span><span class="token"> </span><span class="token" style="color: #d73a49;">=</span><span class="token"> </span><span class="token">models</span><span class="token">.</span><span class="token">BooleanField</span><span class="token">(</span><span class="token" style="color: #e36209;">default</span><span class="token" style="color: #d73a49;">=</span><span class="token" style="color: #005cc5;">True</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token" style="color: #6a737d;">#</span><span class="token" style="color: #6a737d;"> We want to add new field called image</span><span class="token">
</span></span><span class="line"><span class="token" style="color: #d73a49;">class</span><span class="token"> </span><span class="token" style="color: #6f42c1;">Author</span><span class="token">(</span><span class="token" style="color: #6f42c1;">models</span><span class="token">.</span><span class="token" style="color: #6f42c1;">Model</span><span class="token">)</span><span class="token">:</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token">name</span><span class="token"> </span><span class="token" style="color: #d73a49;">=</span><span class="token"> </span><span class="token">models</span><span class="token">.</span><span class="token">CharField</span><span class="token">(</span><span class="token" style="color: #e36209;">max_length</span><span class="token" style="color: #d73a49;">=</span><span class="token" style="color: #005cc5;">80</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token">slug</span><span class="token"> </span><span class="token" style="color: #d73a49;">=</span><span class="token"> </span><span class="token">models</span><span class="token">.</span><span class="token">SlugField</span><span class="token">(</span><span class="token" style="color: #e36209;">max_length</span><span class="token" style="color: #d73a49;">=</span><span class="token" style="color: #005cc5;">80</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token" style="color: #6a737d;">#</span><span class="token" style="color: #6a737d;"> we add image field on third place</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token">image</span><span class="token"> </span><span class="token" style="color: #d73a49;">=</span><span class="token"> </span><span class="token">models</span><span class="token">.</span><span class="token">ForeignKey</span><span class="token">(</span><span class="token">Image</span><span class="token">,</span><span class="token"> </span><span class="token" style="color: #e36209;">null</span><span class="token" style="color: #d73a49;">=</span><span class="token" style="color: #005cc5;">True</span><span class="token">,</span><span class="token"> </span><span class="token" style="color: #e36209;">blank</span><span class="token" style="color: #d73a49;">=</span><span class="token" style="color: #005cc5;">True</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token">is_active</span><span class="token"> </span><span class="token" style="color: #d73a49;">=</span><span class="token"> </span><span class="token">models</span><span class="token">.</span><span class="token">BooleanField</span><span class="token">(</span><span class="token" style="color: #e36209;">default</span><span class="token" style="color: #d73a49;">=</span><span class="token" style="color: #005cc5;">True</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token" style="color: #6a737d;">#</span><span class="token" style="color: #6a737d;"> Now we only have to start the migration from the command line</span><span class="token">
</span></span><span class="line"><span class="token" style="color: #b31d28;font-style: italic;">$</span><span class="token"> </span><span class="token">python</span><span class="token"> </span><span class="token">manage</span><span class="token">.</span><span class="token">py</span><span class="token"> </span><span class="token">makemigrations</span><span class="token">
</span></span><span class="line"><span class="token" style="color: #b31d28;font-style: italic;">$</span><span class="token"> </span><span class="token">python</span><span class="token"> </span><span class="token">manage</span><span class="token">.</span><span class="token">py</span><span class="token"> </span><span class="token">migrate</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-318"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-316">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-317'
	>
	Another thing I miss is Django’s great admin interface that you get out of the box when you create a Django project and database tables. It’s of great help when you want to view or change some data.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-321"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-media">
	<div	class="media block-media__media media__border--none media__align--center-center"
	data-id="es-319"
	 data-media-type='image'>

	<figure class="image block-media__image-figure image--size-stretch" data-id="es-320">
	<picture class="image__picture block-media__image-picture">
								
			<source
				srcset=https://infinum.com/uploads/2015/02/i-moved-from-django-to-rails-and-nothing-terrible-happened-2-1400x680.webp				media='(max-width: 699px)'
				type=image/webp								height="680"
												width="1400"
				 />
												<img
					src="https://infinum.com/uploads/2015/02/i-moved-from-django-to-rails-and-nothing-terrible-happened-2.webp"
					class="image__img block-media__image-img"
					alt=""
										height="699"
															width="1439"
										loading="lazy"
					 />
					</picture>

	</figure></div></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-324"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-322">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-323'
	>
	Last but not least, I like Django’s structure based on apps. Every app is responsible for a specific behavior and segment of a larger system. Apps have their own models, views and templates and they can be connected to other apps. This way, you get cleaner structure when you have a big application and a lot of files and directories.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-327"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-325">
	<h2	class='typography typography--size-52-default js-typography block-heading__heading'
	data-id='es-326'
	>
	Conclusion</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-330"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-328">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-329'
	>
	All things considered, both frameworks are really good and both of them are making the process of building modern web applications simpler. If you are willing to put in some time and effort, it’s not hard to switch from one to another.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-333"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-331">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-332'
	>
	Here’s some advice &#8211; try to focus on the upsides of the target framework. I got used to the Rails way of thinking and now I’m really enjoying the platform’s signature behavior &#8211; the ability to write very concise and clean yet very powerful code.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-336"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-334">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-335'
	>
	As I said in the beginning, I moved from one good framework to another, and nothing terrible happened. Try it yourself &#8211; it’s easier than you think.</p></div>	</div>
</div>
</div>		</div>
	</div><p>The post <a href="https://infinum.com/blog/i-moved-from-django-to-rails-and-nothing-terrible-happened/">I Moved from Django to Rails  and Nothing Terrible Happened</a> appeared first on <a href="https://infinum.com">Infinum</a>.</p>
]]>
				</content:encoded>
			</item>
		
	</channel>
</rss>