<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/" xml:lang="en-US">
  <title>BigBinary Blog: Rails 5.2</title>
  <subtitle>Deep technical writing on Ruby on Rails, performance, scaling, monitoring and engineering.</subtitle>
  <link rel="self" type="application/atom+xml" href="https://www.bigbinary.com/blog/categories/rails-5-2/feed.xml"/>
  <link rel="alternate" type="text/html" href="https://www.bigbinary.com/blog/categories/rails-5-2"/>
  <id>https://www.bigbinary.com/blog/categories/rails-5-2</id>
  <updated>2019-08-06T00:00:00.000Z</updated>
  <author>
    <name>BigBinary</name>
    <uri>https://www.bigbinary.com/</uri>
  </author>
  <icon>https://www.bigbinary.com/favicon.ico</icon>
  <logo>https://www.bigbinary.com/images/bigbinary_square_big_logo.png</logo>
  <rights>Copyright 2019 Big Binary LLC</rights>
  <generator uri="https://nextjs.org">Next.js</generator>
  <entry>
      <title type="text"><![CDATA[Recyclable cache keys in Rails]]></title>
      <link rel="alternate" type="text/html" href="https://www.bigbinary.com/blog/rails-adds-support-for-recyclable-cache-keys"/>
      <link rel="enclosure" type="image/png" href="https://www.bigbinary.com/blog/images/social_preview_images/generated/rails-adds-support-for-recyclable-cache-keys.png"/>
      <id>https://www.bigbinary.com/blog/rails-adds-support-for-recyclable-cache-keys</id>
      <published>2019-08-06T00:00:00.000Z</published>
      <updated>2019-08-06T00:00:00.000Z</updated>
      <author>
        <name>Taha Husain</name>
        <uri>https://www.bigbinary.com/blog/authors/taha</uri>
      </author>
      <category term="Rails 5.2"/>
      <category term="Rails 6"/>
      <category term="Rails"/>
      <media:thumbnail url="https://www.bigbinary.com/blog/images/social_preview_images/generated/rails-adds-support-for-recyclable-cache-keys.png" width="1200" height="630"/>
      <summary type="text"><![CDATA[Rails added cache_versioning and collection_cache_versioning to support recyclable cache keys.]]></summary>
      <content type="html" xml:base="https://www.bigbinary.com/blog/rails-adds-support-for-recyclable-cache-keys"><![CDATA[<p><a href="https://github.com/rails/rails/pull/29092">Recyclable cache keys</a> or <em>cache
versioning</em> was introduced in Rails 5.2. Large applications frequently need to
invalidate their cache because cache store has limited memory. We can optimize
cache storage and minimize cache miss using recyclable cache keys.</p>
<p>Recyclable cache keys is supported by all
<a href="https://guides.rubyonrails.org/caching_with_rails.html#cache-stores">cache stores</a>
that ship with Rails.</p>
<p>Before Rails 5.2, <code>cache_key</code>'s format was <em>{model_name}/{id}-{update_at}</em>. Here
<code>model_name</code> and <code>id</code> are always constant for an object and <code>updated_at</code> changes
on every update.</p>
<h4>Rails 5.1</h4>
<pre><code class="language-ruby">&gt;&gt; post = Post.last

&gt;&gt; post.cache_key
=&gt; &quot;posts/1-20190522104553296111&quot;

# Update post
&gt;&gt; post.touch

&gt;&gt; post.cache_key
=&gt; &quot;posts/1-20190525102103422069&quot; # cache_key changed

</code></pre>
<p>In Rails 5.2, <code>#cache_key</code> returns <em>{model_name}/{id}</em> and new method
<code>#cache_version</code> returns <em>{updated_at}</em>.</p>
<h4>Rails 5.2</h4>
<pre><code class="language-ruby">
&gt;&gt; ActiveRecord::Base.cache_versioning = true

&gt;&gt; post = Post.last

&gt;&gt; post.cache_key
=&gt; &quot;posts/1&quot;

&gt;&gt; post.cache_version
=&gt; &quot;20190522070715422750&quot;

&gt;&gt; post.cache_key_with_version
=&gt; &quot;posts/1-20190522070715422750&quot;

</code></pre>
<p>Let's update <code>post</code> instance and check <code>cache_key</code> and <code>cache_version</code>'s
behaviour.</p>
<pre><code class="language-ruby">
&gt;&gt; post.touch

&gt;&gt; post.cache_key
=&gt; &quot;posts/1&quot; # cache_key remains same

&gt;&gt; post.cache_version
=&gt; &quot;20190527062249879829&quot; # cache_version changed

</code></pre>
<p>To use cache versioning feature, we have to enable
<code>ActiveRecord::Base.cache_versioning</code> configuration. By default
<code>cache_versioning</code> config is set to false for backward compatibility.</p>
<p>We can enable cache versioning configuration globally as shown below.</p>
<pre><code class="language-ruby">
ActiveRecord::Base.cache_versioning = true
# or
config.active_record.cache_versioning = true

</code></pre>
<p>Cache versioning config can be applied at model level.</p>
<pre><code class="language-ruby">
class Post &lt; ActiveRecord::Base
  self.cache_versioning = true
end

# Or, when setting `#cache_versioning` outside the model -

Post.cache_versioning = true

</code></pre>
<p>Let's understand the problem step by step with cache keys before Rails 5.2.</p>
<h4>Rails 5.1 (without cache versioning)</h4>
<p><em>1. Write <code>post</code> instance to cache using
<a href="https://apidock.com/rails/ActiveSupport/Cache/Store/fetch"><code>fetch</code></a> api.</em></p>
<pre><code class="language-ruby">
&gt;&gt; before_update_cache_key = post.cache_key
=&gt; &quot;posts/1-20190527062249879829&quot;

&gt;&gt; Rails.cache.fetch(before_update_cache_key) { post }
=&gt; #&lt;Post id: 1, title: &quot;First Post&quot;, created_at: &quot;2019-05-22 17:23:22&quot;, updated_at: &quot;2019-05-27 06:22:49&quot;&gt;

</code></pre>
<p><em>2. Update <code>post</code> instance using
<a href="https://apidock.com/rails/ActiveRecord/Persistence/touch"><code>touch</code></a>.</em></p>
<pre><code class="language-ruby">
&gt;&gt; post.touch
   (0.1ms)  begin transaction
  Post Update (1.6ms)  UPDATE &quot;posts&quot; SET &quot;updated_at&quot; = ? WHERE &quot;posts&quot;.&quot;id&quot; = ?  [[&quot;updated_at&quot;, &quot;2019-05-27 08:01:52.975653&quot;], [&quot;id&quot;, 1]]
   (1.2ms)  commit transaction
=&gt; true

</code></pre>
<p><em>3. Verify stale <code>cache_key</code> in cache store.</em></p>
<pre><code class="language-ruby">
&gt;&gt; Rails.cache.fetch(before_update_cache_key)
=&gt; #&lt;Post id: 1, title: &quot;First Post&quot;, created_at: &quot;2019-05-22 17:23:22&quot;, updated_at: &quot;2019-05-27 06:22:49&quot;&gt;

</code></pre>
<p><em>4. Write updated <code>post</code> instance to cache using new <code>cache_key</code>.</em></p>
<pre><code class="language-ruby">&gt;&gt; after_update_cache_key = post.cache_key
=&gt; &quot;posts/1-20190527080152975653&quot;

&gt;&gt; Rails.cache.fetch(after_update_cache_key) { post }
=&gt; #&lt;Post id: 1, title: &quot;First Post&quot;, created_at: &quot;2019-05-22 17:23:22&quot;, updated_at: &quot;2019-05-27 08:01:52&quot;&gt;

</code></pre>
<p><em>5. Cache store now has two copies of <code>post</code> instance.</em></p>
<pre><code class="language-ruby">
&gt;&gt; Rails.cache.fetch(before_update_cache_key)
=&gt; #&lt;Post id: 1, title: &quot;First Post&quot;, created_at: &quot;2019-05-22 17:23:22&quot;, updated_at: &quot;2019-05-27 06:22:49&quot;&gt;

&gt;&gt; Rails.cache.fetch(after_update_cache_key)
=&gt; #&lt;Post id: 1, title: &quot;First Post&quot;, created_at: &quot;2019-05-22 17:23:22&quot;, updated_at: &quot;2019-05-27 08:01:52&quot;&gt;

</code></pre>
<p><em>cache_key</em> and its associated instance becomes irrelevant as soon as an
instance is updated. But it stays in cache store until it is manually
invalidated.</p>
<p>This sometimes result in overflowing cache store with stale keys and data. In
applications that extensively use cache store, a huge chunk of cache store gets
filled with stale data frequently.</p>
<p>Now let's take a look at the same example. This time with <em>cache versioning</em> to
understand how recyclable cache keys help optimize cache storage.</p>
<h4>Rails 5.2 (cache versioning)</h4>
<p><em>1. Write <code>post</code> instance to cache store with <code>version</code> option.</em></p>
<pre><code class="language-ruby">
&gt;&gt; ActiveRecord::Base.cache_versioning = true

&gt;&gt; post = Post.last

&gt;&gt; cache_key = post.cache_key
=&gt; &quot;posts/1&quot;

&gt;&gt; before_update_cache_version = post.cache_version
=&gt; &quot;20190527080152975653&quot;

&gt;&gt; Rails.cache.fetch(cache_key, version: before_update_cache_version) { post }
=&gt; #&lt;Post id: 1, title: &quot;First Post&quot;, created_at: &quot;2019-05-22 17:23:22&quot;, updated_at: &quot;2019-05-27 08:01:52&quot;&gt;

</code></pre>
<p><em>2. Update <code>post</code> instance.</em></p>
<pre><code class="language-ruby">
&gt;&gt; post.touch
   (0.1ms)  begin transaction
  Post Update (0.4ms)  UPDATE &quot;posts&quot; SET &quot;updated_at&quot; = ? WHERE &quot;posts&quot;.&quot;id&quot; = ?  [[&quot;updated_at&quot;, &quot;2019-05-27 09:09:15.651029&quot;], [&quot;id&quot;, 1]]
   (0.7ms)  commit transaction
=&gt; true

</code></pre>
<p><em>3. Verify stale <code>cache_version</code> in cache store.</em></p>
<pre><code class="language-ruby">
&gt;&gt; Rails.cache.fetch(cache_key, version: before_update_cache_version)
=&gt; #&lt;Post id: 1, title: &quot;First Post&quot;, created_at: &quot;2019-05-22 17:23:22&quot;, updated_at: &quot;2019-05-27 08:01:52&quot;&gt;

</code></pre>
<p><em>4. Write updated <code>post</code> instance to cache.</em></p>
<pre><code class="language-ruby">
&gt;&gt; after_update_cache_version = post.cache_version
=&gt; &quot;20190527090915651029&quot;

&gt;&gt; Rails.cache.fetch(cache_key, version: after_update_cache_version) { post }
=&gt; #&lt;Post id: 1, title: &quot;First Post&quot;, created_at: &quot;2019-05-22 17:23:22&quot;, updated_at: &quot;2019-05-27 09:09:15&quot;&gt;

</code></pre>
<p><em>5. Cache store has replaced old copy of <code>post</code> with new version automatically.</em></p>
<pre><code class="language-ruby">
&gt;&gt; Rails.cache.fetch(cache_key, version: before_update_cache_version)
=&gt; nil

&gt;&gt; Rails.cache.fetch(cache_key, version: after_update_cache_version)
=&gt; #&lt;Post id: 1, title: &quot;First Post&quot;, created_at: &quot;2019-05-22 17:23:22&quot;, updated_at: &quot;2019-05-27 09:09:15&quot;&gt;

</code></pre>
<p>Above example shows how recyclable cache keys maintains single, latest copy of
an instance. Stale versions are removed automatically when new version is added
to cache store.</p>
<p><em>Rails 6</em> added <code>#cache_versioning</code> for <code>ActiveRecord::Relation</code>.</p>
<p><code>ActiveRecord::Base.collection_cache_versioning</code> configuration should be enabled
to use cache versioning feature on collections. It is set to false by default.</p>
<p>We can enable this configuration as shown below.</p>
<pre><code class="language-ruby">
ActiveRecord::Base.collection_cache_versioning = true
# or
config.active_record.collection_cache_versioning = true

</code></pre>
<p>Before Rails 6, <code>ActiveRecord::Relation</code> had <code>cache_key</code> in format
<code>{table_name}/query-{query-hash}-{count}-{max(updated_at)}</code>.</p>
<p>In Rails 6, cache_key is split in stable part <code>cache_key</code> -
<code>{table_name}/query-{query-hash}</code> and volatile part <code>cache_version</code> -
<code>{count}-{max(updated_at)}</code>.</p>
<p>For more information, check out
<a href="https://blog.bigbinary.com/2016/02/02/activerecord-relation-cache-key.html">blog on ActiveRecord::Relation#cache_key in Rails 5</a>.</p>
<h4>Rails 5.2</h4>
<pre><code class="language-ruby">
&gt;&gt; posts = Post.all

&gt;&gt; posts.cache_key
=&gt; &quot;posts/query-00644b6a00f2ed4b925407d06501c8fb-3-20190522172326885804&quot;

</code></pre>
<h4>Rails 6</h4>
<pre><code class="language-ruby">
&gt;&gt; ActiveRecord::Base.collection_cache_versioning = true

&gt;&gt; posts = Post.all

&gt;&gt; posts.cache_key
=&gt; &quot;posts/query-00644b6a00f2ed4b925407d06501c8fb&quot;

&gt;&gt; posts.cache_version
=&gt; &quot;3-20190522172326885804&quot;

</code></pre>
<p>Cache versioning works similarly for <code>ActiveRecord::Relation</code> as
<code>ActiveRecord::Base</code>.</p>
<p>In case of <code>ActiveRecord::Relation</code>, if number of records change and/or
record(s) are updated, then same <code>cache_key</code> is written to cache store with new
<code>cache_version</code> and updated records.</p>
<h2>Conclusion</h2>
<p>Previously, cache invalidation had to be done manually either by deleting cache
or setting cache expire duration. Cache versioning invalidates stale data
automatically and keeps latest copy of data, saving on storage and performance
drastically.</p>
<p>Check out the <a href="https://github.com/rails/rails/pull/29092">pull request</a> and
<a href="https://github.com/rails/rails/commit/4f2ac80d4cdb01c4d3c1765637bed76cc91c1e35">commit</a>
for more details.</p>
]]></content>
    </entry>
  <entry>
      <title type="text"><![CDATA[Rails 5.2 DSL for configuring Content Security Policy]]></title>
      <link rel="alternate" type="text/html" href="https://www.bigbinary.com/blog/rails-5-2-adds-dsl-for-configuring-content-security-policy-header"/>
      <link rel="enclosure" type="image/png" href="https://www.bigbinary.com/blog/images/social_preview_images/generated/rails-5-2-adds-dsl-for-configuring-content-security-policy-header.png"/>
      <id>https://www.bigbinary.com/blog/rails-5-2-adds-dsl-for-configuring-content-security-policy-header</id>
      <published>2018-10-23T00:00:00.000Z</published>
      <updated>2018-10-23T00:00:00.000Z</updated>
      <author>
        <name>Sushant Mittal</name>
        <uri>https://www.bigbinary.com/blog/authors/sushantmittal</uri>
      </author>
      <category term="Rails 5.2"/>
      <category term="Rails"/>
      <media:thumbnail url="https://www.bigbinary.com/blog/images/social_preview_images/generated/rails-5-2-adds-dsl-for-configuring-content-security-policy-header.png" width="1200" height="630"/>
      <summary type="text"><![CDATA[Rails 5.2 adds DSL for configuring Content Security Policy header]]></summary>
      <content type="html" xml:base="https://www.bigbinary.com/blog/rails-5-2-adds-dsl-for-configuring-content-security-policy-header"><![CDATA[<p>Content Security Policy (CSP) is an added layer of security that helps to detect
and mitigate various types of attacks on our web applications, including Cross
Site Scripting (XSS) and data injection attacks.</p>
<h2>What is XSS ?</h2>
<p>In this attack, victim's browser may execute malicious scripts because browser
trusts the source of the content even when it's not coming from the correct
source.</p>
<p><a href="https://blog.bigbinary.com/2012/05/10/xss-and-rails.html">Here is</a> our blog on
XSS written sometime back.</p>
<h2>How CSP can be used to mitigate and report this attack ?</h2>
<p>By using CSP, we can specify domains that are valid sources of executable
scripts. Then a browser with CSP compatibility will only execute those scripts
that are loaded from these whitelisted domains.</p>
<p>Please note that CSP makes XSS attack a lot harder but CSP does not make XSS
attack impossible. CSP does not stop DOM-based XSS (also known as client-side
XSS). To prevent DOM-based XSS, Javascript code should be carefully written to
avoid introducing such vulnerabilities.</p>
<p>In Rails 5.2, <a href="https://github.com/rails/rails/pull/31162">a DSL was added</a> for
configuring Content Security Policy header.</p>
<h2>Let's check the configuration.</h2>
<p>We can define global policy for the project in an initializer.</p>
<pre><code class="language-ruby">
# config/initializers/content_security_policy.rb

Rails.application.config.content_security_policy do |policy|
policy.default_src :self, :https
policy.font_src :self, :https, :data
policy.img_src :self, :https, :data
policy.object_src :none
policy.script_src :self, :https
policy.style_src :self, :https, :unsafe_inline
policy.report_uri &quot;/csp-violation-report-endpoint&quot;
end
</code></pre>
<p>We can override global policy within a controller as well.</p>
<pre><code class="language-ruby">
# Override policy inline

class PostsController &lt; ApplicationController
content_security_policy do |policy|
policy.upgrade_insecure_requests true
end
end
</code></pre>
<pre><code class="language-ruby">
# Using mixed static and dynamic values

class PostsController &lt; ApplicationController
content_security_policy do |policy|
policy.base_uri :self, -&gt; { &quot;https://#{current_user.domain}.example.com&quot; }
end
end
</code></pre>
<h2>Content Security Policy can be deployed in report-only mode as well.</h2>
<p>Here is global setting in an initializer.</p>
<pre><code class="language-ruby">
# config/initializers/content_security_policy.rb

Rails.application.config.content_security_policy_report_only = true
</code></pre>
<p>Here we are putting an override at controller level.</p>
<pre><code class="language-ruby">class PostsController &lt; ApplicationController
content_security_policy_report_only only: :index
end
</code></pre>
<p>Policy specified in <code>content_security_policy_report_only</code> header will not be
enforced, but any violations will be reported to a provided URI. We can provide
this violation report URI in <code>report_uri</code> option.</p>
<pre><code class="language-ruby">
# config/initializers/content_security_policy.rb

Rails.application.config.content_security_policy do |policy|
policy.report_uri &quot;/csp-violation-report-endpoint&quot;
end
</code></pre>
<p>If both <code>content_security_policy_report_only</code> and <code>content_security_policy</code>
headers are present in the same response then policy specified in
<code>content_security_policy</code> header will be enforced while
<code>content_security_policy_report_only</code> policy will generate reports but will not
be enforced.</p>
]]></content>
    </entry>
  <entry>
      <title type="text"><![CDATA[Rails 5.2 stops some raw SQL, prevents SQL injections]]></title>
      <link rel="alternate" type="text/html" href="https://www.bigbinary.com/blog/rails-5-2-disallows-raw-sql-in-active-record"/>
      <link rel="enclosure" type="image/png" href="https://www.bigbinary.com/blog/images/social_preview_images/generated/rails-5-2-disallows-raw-sql-in-active-record.png"/>
      <id>https://www.bigbinary.com/blog/rails-5-2-disallows-raw-sql-in-active-record</id>
      <published>2018-10-16T00:00:00.000Z</published>
      <updated>2018-10-16T00:00:00.000Z</updated>
      <author>
        <name>Piyush Tiwari</name>
        <uri>https://www.bigbinary.com/blog/authors/piyush</uri>
      </author>
      <category term="Rails 5.2"/>
      <category term="Rails"/>
      <media:thumbnail url="https://www.bigbinary.com/blog/images/social_preview_images/generated/rails-5-2-disallows-raw-sql-in-active-record.png" width="1200" height="630"/>
      <summary type="text"><![CDATA[Rails 5.2 disallows raw SQL in dangerous Active Record methods preventing SQL injections]]></summary>
      <content type="html" xml:base="https://www.bigbinary.com/blog/rails-5-2-disallows-raw-sql-in-active-record"><![CDATA[<p>We sometimes use raw SQL in Active Record methods. This can lead to
<a href="https://en.wikipedia.org/wiki/SQL_injection">SQL injection</a> vulnerabilities
when we unknowingly pass unsanitized user input to the Active Record method.</p>
<pre><code class="language-ruby">class UsersController &lt; ApplicationController
  def index
    User.order(&quot;#{params[:order]} ASC&quot;)
  end
end
</code></pre>
<p>Although this code is looking fine on the surface, we can see the issues looking
at the example from <a href="http://rails-sqli.org/">rails-sqli</a>.</p>
<pre><code class="language-ruby">pry(main)&gt; params[:order] = &quot;(CASE SUBSTR(authentication_token, 1, 1) WHEN 'k' THEN 0 else 1 END)&quot;

pry(main)&gt; User.order(&quot;#{params[:order]} ASC&quot;)
User Load (1.0ms)  SELECT &quot;users&quot;.* FROM &quot;users&quot; ORDER BY (CASE SUBSTR(authentication_token, 1, 1) WHEN 'k' THEN 0 else 1 END) ASC
=&gt; [#&lt;User:0x00007fdb7968b508
  id: 1,
  email: &quot;piyush@example.com&quot;,
  authentication_token: &quot;Vkn5jpV_zxhqkNesyKSG&quot;&gt;]
</code></pre>
<p>There are many Active Record methods which are vulnerable to SQL injection and
some of these can be found <a href="http://rails-sqli.org/"><code>here</code></a>.</p>
<p>However, in Rails 5.2 these APIs are changed and they allow only attribute
arguments and Rails does not allow raw SQL. With Rails 5.2 it is not mandatory
but the developer would see a deprecation warning to remind about this.</p>
<pre><code class="language-ruby">irb(main):004:0&gt; params[:order] = &quot;email&quot;
=&gt; &quot;email&quot;
irb(main):005:0&gt; User.order(params[:order])
  User Load (1.0ms)  SELECT  &quot;users&quot;.* FROM &quot;users&quot; ORDER BY email LIMIT $1  [[&quot;LIMIT&quot;, 11]]
=&gt; #&lt;ActiveRecord::Relation [#&lt;User id: 1, email: &quot;piyush@example.com&quot;, authentication_token: &quot;Vkn5jpV_zxhqkNesyKSG&quot;&gt;]&gt;

irb(main):008:0&gt; params[:order] = &quot;(CASE SUBSTR(authentication_token, 1, 1) WHEN 'k' THEN 0 else 1 END)&quot;
irb(main):008:0&gt; User.order(&quot;#{params[:order]} ASC&quot;)
DEPRECATION WARNING: Dangerous query method (method whose arguments are used as raw SQL) called with non-attribute argument(s): &quot;(CASE SUBSTR(authentication_token, 1, 1) WHEN 'k' THEN 0 else 1 END)&quot;. Non-attribute arguments will be disallowed in Rails 6.0. This method should not be called with user-provided values, such as request parameters or model attributes. Known-safe values can be passed by wrapping them in Arel.sql(). (called from irb_binding at (irb):8)
  User Load (1.2ms)  SELECT  &quot;users&quot;.* FROM &quot;users&quot; ORDER BY (CASE SUBSTR(authentication_token, 1, 1) WHEN 'k' THEN 0 else 1 END) ASC
=&gt; #&lt;ActiveRecord::Relation [#&lt;User id: 1, email: &quot;piyush@example.com&quot;, authentication_token: &quot;Vkn5jpV_zxhqkNesyKSG&quot;&gt;]&gt;
</code></pre>
<p>In Rails 6, this will result into an error.</p>
<p>In Rails 5.2, if we want to run raw SQL without getting the above warning, we
have to change raw SQL string literals to an <code>Arel::Nodes::SqlLiteral</code> object.</p>
<pre><code class="language-ruby">irb(main):003:0&gt; Arel.sql('title')
=&gt; &quot;title&quot;
irb(main):004:0&gt; Arel.sql('title').class
=&gt; Arel::Nodes::SqlLiteral

irb(main):006:0&gt; User.order(Arel.sql(&quot;#{params[:order]} ASC&quot;))
  User Load (1.2ms)  SELECT  &quot;users&quot;.* FROM &quot;users&quot; ORDER BY (CASE SUBSTR(authentication_token, 1, 1) WHEN 'k' THEN 0 else 1 END) ASC
=&gt; #&lt;ActiveRecord::Relation [#&lt;User id: 1, email: &quot;piyush@example.com&quot;, authentication_token: &quot;Vkn5jpV_zxhqkNesyKSG&quot;&gt;]&gt;
</code></pre>
<p>This should be done with care and should not be done with user input.</p>
<p>Here is relevant <a href="https://github.com/rails/rails/pull/27947/files">commit</a> and
<a href="https://github.com/rails/rails/pull/27947">discussion</a>.</p>
]]></content>
    </entry>
  <entry>
      <title type="text"><![CDATA[Rails 5.2 added method write_multi to cache store]]></title>
      <link rel="alternate" type="text/html" href="https://www.bigbinary.com/blog/rails-5.2-adds-write_multi-for-cache-writes"/>
      <link rel="enclosure" type="image/png" href="https://www.bigbinary.com/blog/images/social_preview_images/generated/rails-5.2-adds-write_multi-for-cache-writes.png"/>
      <id>https://www.bigbinary.com/blog/rails-5.2-adds-write_multi-for-cache-writes</id>
      <published>2018-07-03T00:00:00.000Z</published>
      <updated>2018-07-03T00:00:00.000Z</updated>
      <author>
        <name>Rohan Pujari</name>
        <uri>https://www.bigbinary.com/blog/authors/rohanpujaris</uri>
      </author>
      <category term="Rails 5.2"/>
      <category term="Rails"/>
      <media:thumbnail url="https://www.bigbinary.com/blog/images/social_preview_images/generated/rails-5.2-adds-write_multi-for-cache-writes.png" width="1200" height="630"/>
      <summary type="text"><![CDATA[Before 5.2 it was not possible to write multiple entries to cache store in one shot even though cache stores like Redis has MSET command to set multiple keys in a single atomic operation. However we...]]></summary>
      <content type="html" xml:base="https://www.bigbinary.com/blog/rails-5.2-adds-write_multi-for-cache-writes"><![CDATA[<p>Before 5.2 it was not possible to write multiple entries to cache store in one
shot even though cache stores like Redis has
<a href="https://redis.io/commands/mset"><code>MSET</code></a> command to set multiple keys in a
single atomic operation. However we were not able to use this feature of Redis
because of the way Rails had implemented caching.</p>
<p>Rails has implemented caching using an abstract class
<code>ActiveSupport::Cache::Store</code> which defines the interface that all cache store
classes should implement. Rails also provides few common functionality that all
cache store classes will need.</p>
<p>Prior to Rails 5.2 <code>ActiveSupport::Cache::Store</code> didn't have any method to set
multiple entities at once.</p>
<p>In Rails 5.2, <a href="https://github.com/rails/rails/pull/29366">write_multi was added</a>
. Each cache store can implement this method and provide the functionality to
add multiple entries at once. If cache store does not implement this method,
then the default implementation is to loop over each key value pair and sets it
individually using <code>write_entity</code> method.</p>
<p>Multiple entities can be set as shown here.</p>
<pre><code class="language-ruby">Rails.cache.write_multi name: 'Alan Turning', country: 'England'
</code></pre>
<p><a href="https://github.com/redis-store/redis-rails">redis-rails</a> gem provides redis as
cache store. However it does not implement <code>write_multi</code> method.</p>
<p>However if we are using Rails 5.2, then there is no point in using <code>redis-rails</code>
gem, as Rails 5.2 comes with built in support for redis cache store, which
implements <code>write_multi</code> method. It was added by
<a href="https://github.com/rails/rails/pull/31134">this PR</a>.</p>
<p>We need to make following change.</p>
<pre><code class="language-ruby"># before
config.cache_store = :redis_store

# after
config.cache_store = :redis_cache_store
</code></pre>
<p><code>redis-rails</code> repo has a
<a href="https://github.com/redis-store/redis-rails/pull/81">pull request</a> to notify
users that development of this gem is ceased. So it's better to use redis cache
store that comes with Rails 5.2.</p>
]]></content>
    </entry>
  <entry>
      <title type="text"><![CDATA[Rails 5.2 uses AES-256-GCM authenticated encryption]]></title>
      <link rel="alternate" type="text/html" href="https://www.bigbinary.com/blog/rails-5-2-uses-aes-256-gcm-authenticated-encryption-as-default-cipher-for-encrypting-messages"/>
      <link rel="enclosure" type="image/png" href="https://www.bigbinary.com/blog/images/social_preview_images/generated/rails-5-2-uses-aes-256-gcm-authenticated-encryption-as-default-cipher-for-encrypting-messages.png"/>
      <id>https://www.bigbinary.com/blog/rails-5-2-uses-aes-256-gcm-authenticated-encryption-as-default-cipher-for-encrypting-messages</id>
      <published>2018-06-26T00:00:00.000Z</published>
      <updated>2018-06-26T00:00:00.000Z</updated>
      <author>
        <name>Sushant Mittal</name>
        <uri>https://www.bigbinary.com/blog/authors/sushantmittal</uri>
      </author>
      <category term="Rails 5.2"/>
      <category term="Rails"/>
      <media:thumbnail url="https://www.bigbinary.com/blog/images/social_preview_images/generated/rails-5-2-uses-aes-256-gcm-authenticated-encryption-as-default-cipher-for-encrypting-messages.png" width="1200" height="630"/>
      <summary type="text"><![CDATA[Rails 5.2 uses AES-256-GCM authenticated encryption as default cipher for encrypting messages]]></summary>
      <content type="html" xml:base="https://www.bigbinary.com/blog/rails-5-2-uses-aes-256-gcm-authenticated-encryption-as-default-cipher-for-encrypting-messages"><![CDATA[<p>Before Rails 5.2, <code>AES-256-CBC</code> authenticated encryption was the default cipher
for encrypting messages.</p>
<p>It was proposed to use <code>AES-256-GCM</code> authenticated encryption as the default
cipher for encrypting messages because of following reasons:</p>
<ul>
<li>It produces shorter ciphertexts and performs quick encryption and decryption.</li>
<li>It is less error prone and more secure.</li>
</ul>
<p>So, <code>AES-256-GCM</code> became
<a href="https://github.com/rails/rails/pull/29263">default cipher</a> for encrypting
messages in Rails 5.2 .</p>
<p>If we do not want <code>AES-256-GCM</code> as default cipher for encrypting messages in our
rails application, then we can disable it.</p>
<pre><code class="language-ruby">Rails.application.config.active_support.use_authenticated_message_encryption = false
</code></pre>
<p>Default Encryption for cookies and sessions was also updated to use
<code>AES-256-GCM</code> <a href="https://github.com/rails/rails/pull/28132">in this pull request</a>.</p>
<p>If we do not want <code>AES-256-GCM</code> as default encryption of cookies and sessions,
then we can disable it too.</p>
<pre><code class="language-ruby">Rails.application.config.active_support.use_authenticated_cookie_encryption = false
</code></pre>
]]></content>
    </entry>
  <entry>
      <title type="text"><![CDATA[Rails 5.2 adds allow_other_host to redirect_back method]]></title>
      <link rel="alternate" type="text/html" href="https://www.bigbinary.com/blog/rails-5-2-adds-allow_other_host-option-to-redirect_back-method"/>
      <link rel="enclosure" type="image/png" href="https://www.bigbinary.com/blog/images/social_preview_images/generated/rails-5-2-adds-allow_other_host-option-to-redirect_back-method.png"/>
      <id>https://www.bigbinary.com/blog/rails-5-2-adds-allow_other_host-option-to-redirect_back-method</id>
      <published>2018-05-30T00:00:00.000Z</published>
      <updated>2018-05-30T00:00:00.000Z</updated>
      <author>
        <name>Mohit Natoo</name>
        <uri>https://www.bigbinary.com/blog/authors/mohit</uri>
      </author>
      <category term="Rails 5.2"/>
      <category term="Rails"/>
      <media:thumbnail url="https://www.bigbinary.com/blog/images/social_preview_images/generated/rails-5-2-adds-allow_other_host-option-to-redirect_back-method.png" width="1200" height="630"/>
      <summary type="text"><![CDATA[Rails 5.2 introduces allow_other_host option to redirect_back method to handle redirection for requests received from a different host]]></summary>
      <content type="html" xml:base="https://www.bigbinary.com/blog/rails-5-2-adds-allow_other_host-option-to-redirect_back-method"><![CDATA[<p>Rails 5.0 had introduced
<a href="https://blog.bigbinary.com/2016/02/29/rails-5-improves-redirect_to_back-with-redirect-back.html">redirect_back</a>
method to perform redirection to path present in <code>HTTP_REFERRER</code>. If there is no
<code>HTTP_REFERRER</code> present, then site is redirected to <code>fallback_location</code>.</p>
<p>Now consider the following scenario.</p>
<p>In one of the searches on <code>google.com</code>, we see a link to <code>bigbinary.com</code>. On
clicking the link, we are navigated to <code>bigbinary.com</code>.</p>
<p>When somebody gets redirected to <code>bigbinary.com</code> from <code>google.com</code>, the HTTP
REFERRER is set to <code>google.com</code></p>
<p>If <code>bigbinary.com</code> uses <code>redirect_back</code> in its code then the user will get
redirected to <code>google.com</code> which might be undesired behavior for some
applications.</p>
<p>To avoid such cases, Rails 5.2 has added a flag
<a href="https://github.com/rails/rails/pull/30850/commits/0db6a14ae16b143e078375ff7f3c940cf707290b">allow_other_host</a>
to not allow redirecting to a different host other than the current site.</p>
<p>By default, <code>allow_other_host</code> option is set to <code>true</code>. So if you do not want
users to go back to <code>google.com</code> then you need to explicitly set
<code>allow_other_host: false</code>.</p>
<pre><code class="language-ruby">
&gt; request.host
#=&gt; &quot;http://www.bigbinary.com&quot;

&gt; request.headers[&quot;Referrer&quot;]
#=&gt; &quot;http://www.google.com&quot;

# This will redirect back to google.com
redirect_back(fallback_path: &quot;/&quot;)

# This will not redirect back to google.com
redirect_back(fallback_path: &quot;/&quot;, allow_other_host: false)

</code></pre>
]]></content>
    </entry>
  <entry>
      <title type="text"><![CDATA[Rails 5.2 fixes query caching in MySQL & PostgreSQL adapters]]></title>
      <link rel="alternate" type="text/html" href="https://www.bigbinary.com/blog/rails-5-2-fixes-query-caching-in-mysql-and-postgresql-adapters"/>
      <link rel="enclosure" type="image/png" href="https://www.bigbinary.com/blog/images/social_preview_images/generated/rails-5-2-fixes-query-caching-in-mysql-and-postgresql-adapters.png"/>
      <id>https://www.bigbinary.com/blog/rails-5-2-fixes-query-caching-in-mysql-and-postgresql-adapters</id>
      <published>2018-05-16T00:00:00.000Z</published>
      <updated>2018-05-16T00:00:00.000Z</updated>
      <author>
        <name>Sushant Mittal</name>
        <uri>https://www.bigbinary.com/blog/authors/sushantmittal</uri>
      </author>
      <category term="Rails 5.2"/>
      <category term="Rails"/>
      <media:thumbnail url="https://www.bigbinary.com/blog/images/social_preview_images/generated/rails-5-2-fixes-query-caching-in-mysql-and-postgresql-adapters.png" width="1200" height="630"/>
      <summary type="text"><![CDATA[Rails 5.2 fixes query caching in MySQL and PostgreSQL adapters]]></summary>
      <content type="html" xml:base="https://www.bigbinary.com/blog/rails-5-2-fixes-query-caching-in-mysql-and-postgresql-adapters"><![CDATA[<p>Prior to Rails 5.2, MySQL and PostgreSQL adapters had <code>select_value</code>,
<code>select_values</code> &amp; <code>select_rows</code> <code>select_{value,values,rows}</code> methods. They
improve the performance by not instantiating <code>ActiveRecord::Result</code>.</p>
<p>However these methods broke query caching of
<code>ActiveRecord::FinderMethods#exists?</code> method. Let's check the issue.</p>
<pre><code class="language-ruby">&gt;&gt; User.cache do
&gt;&gt;   2.times { User.exists?(1) }
&gt;&gt; end

User Exists (2.1ms)  SELECT  1 AS one FROM &quot;users&quot; WHERE &quot;users&quot;.&quot;id&quot; = $1 LIMIT $2  [[&quot;id&quot;, 1], [&quot;LIMIT&quot;, 1]]

User Exists (2ms)  SELECT  1 AS one FROM &quot;users&quot; WHERE &quot;users&quot;.&quot;id&quot; = $1 LIMIT $2  [[&quot;id&quot;, 1], [&quot;LIMIT&quot;, 1]]

</code></pre>
<p>As we can see, query was not cached and sql was executed second time.</p>
<p>From Rails 5.2, MySQL and PostgreSQL adapters are
<a href="https://github.com/rails/rails/pull/29454">no longer override select_{value,values,rows} methods</a>
which fix this query caching issue.</p>
<p>Also, the performance improvement provided by these methods was marginal and not
a hotspot in Active Record, so this change was accepted.</p>
<p>Let's check query caching of <code>ActiveRecord::FinderMethods#exists?</code> after the
change.</p>
<pre><code class="language-ruby">&gt;&gt; User.cache do
&gt;&gt;   2.times { User.exists?(1) }
&gt;&gt; end

User Exists (2.1ms)  SELECT  1 AS one FROM &quot;users&quot; WHERE &quot;users&quot;.&quot;id&quot; = $1 LIMIT $2  [[&quot;id&quot;, 1], [&quot;LIMIT&quot;, 1]]

CACHE User Exists (0.0ms)  SELECT  1 AS one FROM &quot;users&quot; WHERE &quot;users&quot;.&quot;id&quot; = $1 LIMIT $2  [[&quot;id&quot;, 1], [&quot;LIMIT&quot;, 1]]
</code></pre>
<p>Now, query has been cached as expected.</p>
<p>This change has been backported in rails 5.1 from version 5.1.2 as well.</p>
]]></content>
    </entry>
  <entry>
      <title type="text"><![CDATA[Rails 5.2 sets version in Gemfile & adds .ruby-version]]></title>
      <link rel="alternate" type="text/html" href="https://www.bigbinary.com/blog/rails-5_2-adds-ruby-version-file-and-ruby-version-to-gemfile-by-default"/>
      <link rel="enclosure" type="image/png" href="https://www.bigbinary.com/blog/images/social_preview_images/generated/rails-5_2-adds-ruby-version-file-and-ruby-version-to-gemfile-by-default.png"/>
      <id>https://www.bigbinary.com/blog/rails-5_2-adds-ruby-version-file-and-ruby-version-to-gemfile-by-default</id>
      <published>2018-05-07T00:00:00.000Z</published>
      <updated>2018-05-07T00:00:00.000Z</updated>
      <author>
        <name>Mohit Natoo</name>
        <uri>https://www.bigbinary.com/blog/authors/mohit</uri>
      </author>
      <category term="Rails 5.2"/>
      <category term="Rails"/>
      <media:thumbnail url="https://www.bigbinary.com/blog/images/social_preview_images/generated/rails-5_2-adds-ruby-version-file-and-ruby-version-to-gemfile-by-default.png" width="1200" height="630"/>
      <summary type="text"><![CDATA[Rails 5.2 sets Ruby version in Gemfile and adds .ruby-version file by default.]]></summary>
      <content type="html" xml:base="https://www.bigbinary.com/blog/rails-5_2-adds-ruby-version-file-and-ruby-version-to-gemfile-by-default"><![CDATA[<p>For Ruby developers, it's common to switch between multiple Ruby versions for
multiple projects as per the needs of the project. Sometimes, the process of
going back and forth with multiple Ruby versions could be frustrating for the
developer. To avoid this we add
<a href="https://rvm.io/workflow/projects#project-file-ruby-version">.ruby-version files</a>
to our projects so that version manager tools such as <code>rvm</code>, <code>rbenv</code> etc. can
easily determine which Ruby version should be used for that particular project.</p>
<p>One other case that Rails developers have to take care of is ensuring that the
Ruby version used to run Rails by the deployment tools is the one that is
desired. In order to ensure that we
<a href="https://devcenter.heroku.com/articles/ruby-versions">add ruby version to Gemfile</a>.
This will help bundler install dependencies scoped to the specified Ruby
version.</p>
<h3>Good News! Rails 5.2 makes our work easy.</h3>
<p>In Rails 5.2,
<a href="https://github.com/rails/rails/pull/30016">changes have been made</a> to introduce
<code>.ruby-version</code> file and also add the Ruby version to Gemfile by default after
creating an app.</p>
<p>Let's create a new project with Ruby 2.5 .</p>
<pre><code class="language-ruby">$ rvm list default

  Default Ruby (for new shells)

     ruby-2.5 [ x86_64 ]


$ rails new my_new_app
</code></pre>
<p>In our new project, we should be able to see <code>.ruby-version</code> in its root
directory and it will contain value <code>2.5</code>. Also, we should see following line in
the Gemfile.</p>
<pre><code class="language-ruby">ruby &quot;2.5&quot;
</code></pre>
]]></content>
    </entry>
  <entry>
      <title type="text"><![CDATA[Rails 5.2 Date#prev_occurring & Date#next_occurring]]></title>
      <link rel="alternate" type="text/html" href="https://www.bigbinary.com/blog/rails-5-2-adds-date-methods-to-return-specified-next-or-previous-occurring-day-of-week"/>
      <link rel="enclosure" type="image/png" href="https://www.bigbinary.com/blog/images/social_preview_images/generated/rails-5-2-adds-date-methods-to-return-specified-next-or-previous-occurring-day-of-week.png"/>
      <id>https://www.bigbinary.com/blog/rails-5-2-adds-date-methods-to-return-specified-next-or-previous-occurring-day-of-week</id>
      <published>2018-04-17T00:00:00.000Z</published>
      <updated>2018-04-17T00:00:00.000Z</updated>
      <author>
        <name>Sushant Mittal</name>
        <uri>https://www.bigbinary.com/blog/authors/sushantmittal</uri>
      </author>
      <category term="Rails 5.2"/>
      <category term="Rails"/>
      <media:thumbnail url="https://www.bigbinary.com/blog/images/social_preview_images/generated/rails-5-2-adds-date-methods-to-return-specified-next-or-previous-occurring-day-of-week.png" width="1200" height="630"/>
      <summary type="text"><![CDATA[Rails 5.2 added Date#prev_occurring and Date#next_occurring to return specified next/previous occurring day of week.]]></summary>
      <content type="html" xml:base="https://www.bigbinary.com/blog/rails-5-2-adds-date-methods-to-return-specified-next-or-previous-occurring-day-of-week"><![CDATA[<p>Before Rails 5.2, this is how we would write to find next or previous occurring
day of the week.</p>
<p><strong>Assume that current date is Tue, 27 Feb 2018.</strong></p>
<pre><code class="language-ruby"># find previous thursday
&gt;&gt; Date.yesterday.beginning_of_week(:thursday)
=&gt; Thu, 22 Feb 2018

# find next thursday
&gt;&gt; Date.tomorrow.end_of_week(:friday)
=&gt; Thu, 01 Mar 2018

</code></pre>
<p>Rails 5.2 has <a href="https://github.com/rails/rails/pull/26600">introduced methods</a>
<code>Date#prev_occurring</code> and <code>Date#next_occurring</code> to find next &amp; previous
occurring day of the week.</p>
<pre><code class="language-ruby"># find previous thursday
&gt;&gt; Date.prev_occurring(:thursday)
=&gt; Thu, 22 Feb 2018

# find next thursday
&gt;&gt; Date.next_occurring(:thursday)
=&gt; Thu, 01 Mar 2018
</code></pre>
]]></content>
    </entry>
  <entry>
      <title type="text"><![CDATA[Rails 5.2 adds default option to attribute accessors]]></title>
      <link rel="alternate" type="text/html" href="https://www.bigbinary.com/blog/rails-5-2-adds-default-options-to-module-and-class-attribute-accessors"/>
      <link rel="enclosure" type="image/png" href="https://www.bigbinary.com/blog/images/social_preview_images/generated/rails-5-2-adds-default-options-to-module-and-class-attribute-accessors.png"/>
      <id>https://www.bigbinary.com/blog/rails-5-2-adds-default-options-to-module-and-class-attribute-accessors</id>
      <published>2018-02-27T00:00:00.000Z</published>
      <updated>2018-02-27T00:00:00.000Z</updated>
      <author>
        <name>Vishal Telangre</name>
        <uri>https://www.bigbinary.com/blog/authors/vishaltelangre</uri>
      </author>
      <category term="Rails 5.2"/>
      <category term="Rails"/>
      <media:thumbnail url="https://www.bigbinary.com/blog/images/social_preview_images/generated/rails-5-2-adds-default-options-to-module-and-class-attribute-accessors.png" width="1200" height="630"/>
      <summary type="text"><![CDATA[Rails 5.2 now supports specifying a default value using 'default' option for the module and class macros viz. mattr_accessor, mattr_reader, mattr_writer, cattr_accessor, cattr_reader, and cattr_writer respectively.]]></summary>
      <content type="html" xml:base="https://www.bigbinary.com/blog/rails-5-2-adds-default-options-to-module-and-class-attribute-accessors"><![CDATA[<p>When DHH introduced
<a href="https://blog.bigbinary.com/2018/02/21/rails-5-2-supports-specifying-default-value-for-a-class_attribute.html">support for specifying a default value for class_attribute</a>,
Genadi Samokovarov
<a href="https://github.com/rails/rails/pull/29270#issuecomment-304705841">brought to notice</a>
that the module and class attribute accessor macros also support specifying a
default value but using a block and not with a <code>default</code> option.</p>
<p>To have consistent and symmetrical behaviour across all the attribute
extensions, it was decided to support specifying a default value using <code>default</code>
option for all the module and class attribute macros as well.</p>
<p><code>mattr_accessor</code>, <code>mattr_reader</code> and <code>mattr_writer</code> macros generate getter and
setter methods at the module level.</p>
<p>Similarly, <code>cattr_accessor</code>, <code>cattr_reader</code>, and <code>cattr_writer</code> macros generate
getter and setter methods at the class level.</p>
<h2>Before Rails 5.2</h2>
<p>Before Rails 5.2, this is how we would set the default values for the module and
class attribute accessor macros.</p>
<pre><code class="language-ruby">module ActivityLoggerHelper
  mattr_accessor :colorize_logs
  mattr_writer :log_ip { false }

  self.colorize_logs = true
end

class ActivityLogger
  include ActivityLoggerHelper

  cattr_writer :logger { Logger.new(STDOUT) }
  cattr_accessor :level
  cattr_accessor :settings
  cattr_reader :pid { Process.pid }

  @@level = Logger::DEBUG
  self.settings = {}
end
</code></pre>
<h2>After Rails 5.2</h2>
<p>We can still set a default value of a module or class attribute accessor by
providing a block. In this
<a href="https://github.com/rails/rails/pull/29294">pull request</a>, support for
specifying a default value using a new <code>default</code> option has been introduced.</p>
<p>So instead of</p>
<pre><code class="language-ruby">cattr_writer :logger { Logger.new(STDOUT) }
</code></pre>
<p>or</p>
<pre><code class="language-ruby">cattr_writer :logger
self.logger = Logger.new(STDOUT)
</code></pre>
<p>or</p>
<pre><code class="language-ruby">cattr_writer :logger
@@logger = Logger.new(STDOUT)
</code></pre>
<p>we can now easily write</p>
<pre><code class="language-ruby">cattr_writer :logger, default: Logger.new(STDOUT)
</code></pre>
<p>Same applies to the other attribute accessor macros like <code>mattr_accessor</code>,
<code>mattr_reader</code>, <code>mattr_writer</code>, <code>cattr_accessor</code>, and <code>cattr_reader</code>.</p>
<p>Note that, the old way of specifying a default value using the block syntax will
work but will not be documented anywhere.</p>
<p>Also, note that if we try to set the default value by both ways i.e. by
providing a block as well as by specifying a <code>default</code> option; the value
provided by <code>default</code> option will always take the precedence.</p>
<pre><code class="language-ruby">mattr_accessor(:colorize_logs, default: true) { false }
</code></pre>
<p>Here, <code>@@colorize_logs</code> would be set with <code>true</code> as per the above precedence
rule.</p>
<p><a href="https://github.com/rails/rails/blob/b6b0c99ff3e8ace3f42813154dbe4b8ad6a98e6c/activesupport/test/core_ext/module/attribute_accessor_test.rb#L45-L47">Here is a test</a>
which verifies this behavior.</p>
<p>Finally, here is simplified version using the new <code>default</code> option.</p>
<pre><code class="language-ruby">module ActivityLoggerHelper
  mattr_accessor :colorize_logs, default: true
  mattr_writer :log_ip, default: false
end

class ActivityLogger
  include ActivityLoggerHelper

  cattr_writer :logger, default: Logger.new(STDOUT)
  cattr_accessor :level, default: Logger::DEBUG
  cattr_accessor :settings, default: {}
  cattr_reader :pid, default: Process.pid
end
</code></pre>
]]></content>
    </entry>
  <entry>
      <title type="text"><![CDATA[Rails 5.2 specifying default value for class_attribute]]></title>
      <link rel="alternate" type="text/html" href="https://www.bigbinary.com/blog/rails-5-2-supports-specifying-default-value-for-a-class_attribute"/>
      <link rel="enclosure" type="image/png" href="https://www.bigbinary.com/blog/images/social_preview_images/generated/rails-5-2-supports-specifying-default-value-for-a-class_attribute.png"/>
      <id>https://www.bigbinary.com/blog/rails-5-2-supports-specifying-default-value-for-a-class_attribute</id>
      <published>2018-02-21T00:00:00.000Z</published>
      <updated>2018-02-21T00:00:00.000Z</updated>
      <author>
        <name>Vishal Telangre</name>
        <uri>https://www.bigbinary.com/blog/authors/vishaltelangre</uri>
      </author>
      <category term="Rails 5.2"/>
      <category term="Rails"/>
      <media:thumbnail url="https://www.bigbinary.com/blog/images/social_preview_images/generated/rails-5-2-supports-specifying-default-value-for-a-class_attribute.png" width="1200" height="630"/>
      <summary type="text"><![CDATA[Rails 5.2 now supports specifying a default value for the class attributes defined using `class_attribute`.]]></summary>
      <content type="html" xml:base="https://www.bigbinary.com/blog/rails-5-2-supports-specifying-default-value-for-a-class_attribute"><![CDATA[<p>It is very common to set a default value for a <code>class_attribute</code>.</p>
<p>Before Rails 5.2, to specify a default value for a <code>class_attribute</code>, we needed
to write like this.</p>
<pre><code class="language-ruby">class ActivityLogger
class_attribute :logger
class_attribute :settings

self.logger = Logger.new(STDOUT)
self.settings = {}
end
</code></pre>
<p>As we can see above, it requires additional keystrokes to set a default value
for each <code>class_attribute</code>.</p>
<p>Rails 5.2 has added support for specifying a default value for a
<code>class_attribute</code> using <code>default</code> option.</p>
<pre><code class="language-ruby">class ActivityLogger
class_attribute :logger, default: Logger.new(STDOUT)
class_attribute :settings, default: {}
end
</code></pre>
<p>This enhancement was introduced in this
<a href="https://github.com/rails/rails/pull/29270">pull request</a>.</p>
]]></content>
    </entry>
  <entry>
      <title type="text"><![CDATA[Rails 5.2 allows mailers to use custom Active Job class]]></title>
      <link rel="alternate" type="text/html" href="https://www.bigbinary.com/blog/rails-5-2-allows-mailers-to-use-custom-active-job-class"/>
      <link rel="enclosure" type="image/png" href="https://www.bigbinary.com/blog/images/social_preview_images/generated/rails-5-2-allows-mailers-to-use-custom-active-job-class.png"/>
      <id>https://www.bigbinary.com/blog/rails-5-2-allows-mailers-to-use-custom-active-job-class</id>
      <published>2018-01-15T00:00:00.000Z</published>
      <updated>2018-01-15T00:00:00.000Z</updated>
      <author>
        <name>Prathamesh Sonpatki</name>
        <uri>https://www.bigbinary.com/blog/authors/prathamesh</uri>
      </author>
      <category term="Rails 5.2"/>
      <category term="Rails"/>
      <media:thumbnail url="https://www.bigbinary.com/blog/images/social_preview_images/generated/rails-5-2-allows-mailers-to-use-custom-active-job-class.png" width="1200" height="630"/>
      <summary type="text"><![CDATA[Rails now allows to configure a job class for a mailer so that we can use custom Active Job classes per mailer]]></summary>
      <content type="html" xml:base="https://www.bigbinary.com/blog/rails-5-2-allows-mailers-to-use-custom-active-job-class"><![CDATA[<p>Rails allows sending emails asynchronously via Active Job.</p>
<pre><code class="language-ruby">Notifier.welcome(User.first).deliver_later
</code></pre>
<p>It uses <code>ActionMailer::DeliveryJob</code> as the default job class to send emails.
This class is
<a href="https://github.com/rails/rails/blob/7b4132f4a28d1c264a972b95bf86bf6230869a40/actionmailer/lib/action_mailer/delivery_job.rb#L10">defined internally</a>
by Rails.</p>
<p>The <code>DeliveryJob</code> defines <code>handle_exception_with_mailer_class</code> method to handle
exception and to do some housekeeping work.</p>
<pre><code class="language-ruby">def handle_exception_with_mailer_class(exception)
  if klass = mailer_class
    klass.handle_exception exception
  else
    raise exception
  end
end
</code></pre>
<p>One might need more control on the job class to retry the job under certain
conditions or add more logging around exceptions.</p>
<p>Before Rails 5.2, it was not possible to use a custom job class for this
purpose.</p>
<p>Rails 5.2 has added a feature to
<a href="https://github.com/rails/rails/pull/29457">configure the job class per mailer</a>.</p>
<pre><code class="language-ruby">class CustomNotifier &lt; ApplicationMailer
  self.delivery_job = CustomNotifierDeliveryJob
end
</code></pre>
<p>By default, Rails will use the internal <code>DeliveryJob</code> class if the
<code>delivery_job</code> configuration is not present in the mailer class.</p>
<p>Now, Rails will use <code>CustomNotifierDeliveryJob</code> for sending emails for
CustomNotifier mailer.</p>
<pre><code class="language-ruby">CustomNotifier.welcome(User.first).deliver_later
</code></pre>
<p>As mentioned above <code>CustomNotifierDeliveryJob</code> can be further configured for
logging, exception handling and reporting.</p>
<p>By default, <code>deliver_later</code> will pass following arguments to the <code>perform</code>
method of the <code>CustomNotifierDeliveryJob</code>.</p>
<ul>
<li>mailer class name</li>
<li>mailer method name</li>
<li>mail delivery method</li>
<li>original arguments with which the mail is to be sent</li>
</ul>
<pre><code class="language-ruby">class CustomNotifierDeliveryJob &lt; ApplicationJob

  rescue_from StandardError, with: :handle_exception_with_mailer_class

  retry_on CustomNotifierException

  discard_on ActiveJob::DeserializationError

  def perform(mailer, mail_method, delivery_method, *args)
    logger.log &quot;Mail delivery started&quot;
    klass = mailer.constantize
    klass.public_send(mail_method, *args).send(delivery_method)
    logger.log &quot;Mail delivery completed&quot;
  end

  def handle_exception_with_mailer_class(exception)
    if klass = mailer_class
      klass.handle_exception exception
    else
      raise exception
    end
  end
end
</code></pre>
<p>We can also simply inherit from the <code>ActionMailer::DeliveryJob</code> and override the
retry logic.</p>
<pre><code class="language-ruby">class CustomNotifierDeliveryJob &lt; ActionMailer::DeliveryJob
  retry_on CustomNotifierException
end
</code></pre>
]]></content>
    </entry>
  <entry>
      <title type="text"><![CDATA[Rails 5.2 supports descending indexes for MySQL]]></title>
      <link rel="alternate" type="text/html" href="https://www.bigbinary.com/blog/rails-5-2-supports-descending-indexes-for-mysql"/>
      <link rel="enclosure" type="image/png" href="https://www.bigbinary.com/blog/images/social_preview_images/generated/rails-5-2-supports-descending-indexes-for-mysql.png"/>
      <id>https://www.bigbinary.com/blog/rails-5-2-supports-descending-indexes-for-mysql</id>
      <published>2018-01-10T00:00:00.000Z</published>
      <updated>2018-01-10T00:00:00.000Z</updated>
      <author>
        <name>Chirag Shah</name>
        <uri>https://www.bigbinary.com/blog/authors/chiraggshah</uri>
      </author>
      <category term="Rails 5.2"/>
      <category term="Rails"/>
      <media:thumbnail url="https://www.bigbinary.com/blog/images/social_preview_images/generated/rails-5-2-supports-descending-indexes-for-mysql.png" width="1200" height="630"/>
      <summary type="text"><![CDATA[Rails 5.2 now supports descending indexes for MySQL for versions 8.0.1 and higher.]]></summary>
      <content type="html" xml:base="https://www.bigbinary.com/blog/rails-5-2-supports-descending-indexes-for-mysql"><![CDATA[<p>An index is used to speed up the performance of queries on a database.</p>
<p>Rails allows us to create index on a database column by means of a migration. By
default, the sort order for the index is ascending.</p>
<p>But consider the case where we are fetching reports from the database. And while
querying the database, we always want to get the latest report. In this case, it
is efficient to specify the sort order for the index to be descending.</p>
<p>We can specify the sort order by adding an index to the required column by
adding a migration .</p>
<pre><code class="language-ruby">add_index :reports, [:user_id, :name], order: { user_id: :asc, name: :desc }
</code></pre>
<h2>PostgreSQL</h2>
<p>If our Rails application is using postgres database, after running the above
migration we can verify that the sort order was added in schema.rb</p>
<pre><code class="language-ruby">create_table &quot;reports&quot;, force: :cascade do |t|
  t.string &quot;name&quot;
  t.integer &quot;user_id&quot;
  t.datetime &quot;created_at&quot;, null: false
  t.datetime &quot;updated_at&quot;, null: false
  t.index [&quot;user_id&quot;, &quot;name&quot;], name: &quot;index_reports_on_user_id_and_name&quot;, order: { name: :desc }
end
</code></pre>
<p>Here, the index for <code>name</code> has sort order in descending. Since the default is
ascending, the sort order for <code>user_id</code> is not specified in schema.rb.</p>
<h2>MySQL &lt; 8.0.1</h2>
<p>For <strong>MySQL &lt; 8.0.1</strong>, running the above migration, would generate the following
schema.rb</p>
<pre><code class="language-ruby">create_table &quot;reports&quot;, force: :cascade do |t|
  t.string &quot;name&quot;
  t.integer &quot;user_id&quot;
  t.datetime &quot;created_at&quot;, null: false
  t.datetime &quot;updated_at&quot;, null: false
  t.index [&quot;user_id&quot;, &quot;name&quot;], name: &quot;index_reports_on_user_id_and_name&quot;
end
</code></pre>
<p>As we can see, although the migration runs successfully, it ignores the sort
order and the default ascending order is added.</p>
<h2>Rails 5.2 and MySQL &gt; 8.0.1</h2>
<p><strong>MySQL 8.0.1</strong>
<a href="https://dev.mysql.com/doc/relnotes/mysql/8.0/en/news-8-0-1.html#mysqld-8-0-1-optimizer">added support</a>
for descending indices.</p>
<p>Rails community was quick
<a href="https://github.com/rails/rails/pull/28773">to integrate it as well</a>. So now in
Rails 5.2, we can add descending indexes for MySQL databases.</p>
<p>Running the above migration would lead to the same output in schema.rb file as
that of the postgres one.</p>
<pre><code class="language-ruby">create_table &quot;reports&quot;, force: :cascade do |t|
  t.string &quot;name&quot;
  t.integer &quot;user_id&quot;
  t.datetime &quot;created_at&quot;, null: false
  t.datetime &quot;updated_at&quot;, null: false
  t.index [&quot;user_id&quot;, &quot;name&quot;], name: &quot;index_reports_on_user_id_and_name&quot;, order: { name: :desc }
end
</code></pre>
]]></content>
    </entry>
  <entry>
      <title type="text"><![CDATA[Rails 5.2 pass request params to Action Mailer previews]]></title>
      <link rel="alternate" type="text/html" href="https://www.bigbinary.com/blog/rails-5-2-allows-passing-request-params-to-action-mailer-previews"/>
      <link rel="enclosure" type="image/png" href="https://www.bigbinary.com/blog/images/social_preview_images/generated/rails-5-2-allows-passing-request-params-to-action-mailer-previews.png"/>
      <id>https://www.bigbinary.com/blog/rails-5-2-allows-passing-request-params-to-action-mailer-previews</id>
      <published>2018-01-08T00:00:00.000Z</published>
      <updated>2018-01-08T00:00:00.000Z</updated>
      <author>
        <name>Prathamesh Sonpatki</name>
        <uri>https://www.bigbinary.com/blog/authors/prathamesh</uri>
      </author>
      <category term="Rails 5.2"/>
      <category term="Rails"/>
      <media:thumbnail url="https://www.bigbinary.com/blog/images/social_preview_images/generated/rails-5-2-allows-passing-request-params-to-action-mailer-previews.png" width="1200" height="630"/>
      <summary type="text"><![CDATA[A neat way to pass the params to the Action Mailer previews directly for better debugging]]></summary>
      <content type="html" xml:base="https://www.bigbinary.com/blog/rails-5-2-allows-passing-request-params-to-action-mailer-previews"><![CDATA[<p>Rails has inbuilt feature to preview the emails using
<a href="http://guides.rubyonrails.org/action_mailer_basics.html#previewing-emails">Action Mailer previews</a>.</p>
<p>A preview mailer can be setup as shown here.</p>
<pre><code class="language-ruby">class NotificationMailer &lt; ApplicationMailer
def notify(email: email, body: body)
user = User.find_by(email: email)
mail(to: user.email, body: body)
end
end

class NotificationMailerPreview &lt; ActionMailer::Preview
def notify
NotificationMailer.notify(email: User.first.email, body: &quot;Hi there!&quot;)
end
end
</code></pre>
<p>This will work as expected. But our email template is displayed differently
based on user's role. To test this, we need to update the notify method and then
check the updated preview.</p>
<p>What if we could just pass the email in the preview URL.</p>
<pre><code class="language-plaintext">http://localhost:3000/rails/mailers/notification/notify?email=superadmin@example.com
</code></pre>
<p>In Rails 5.2, we can pass the params directly in the URL and
<a href="https://github.com/rails/rails/pull/28244">params will be available to the preview mailers</a>.</p>
<p>Our code can be changed as follows to use the params.</p>
<pre><code class="language-ruby">class NotificationMailerPreview &lt; ActionMailer::Preview
def notify
email = params[:email] || User.first.email
NotificationMailer.notify(email: email, body: &quot;Hi there!&quot;)
end
end
</code></pre>
<p>This allows us to test our mailers with dynamic input as per requirements.</p>
]]></content>
    </entry>
  <entry>
      <title type="text"><![CDATA[Rails 5.2 adds bootsnap to the app to speed up boot time]]></title>
      <link rel="alternate" type="text/html" href="https://www.bigbinary.com/blog/rails-5-2-adds-bootsnap-to-the-app-to-speed-up-boot-time"/>
      <link rel="enclosure" type="image/png" href="https://www.bigbinary.com/blog/images/social_preview_images/generated/rails-5-2-adds-bootsnap-to-the-app-to-speed-up-boot-time.png"/>
      <id>https://www.bigbinary.com/blog/rails-5-2-adds-bootsnap-to-the-app-to-speed-up-boot-time</id>
      <published>2018-01-01T00:00:00.000Z</published>
      <updated>2018-01-01T00:00:00.000Z</updated>
      <author>
        <name>Prathamesh Sonpatki</name>
        <uri>https://www.bigbinary.com/blog/authors/prathamesh</uri>
      </author>
      <category term="Rails 5.2"/>
      <category term="Rails"/>
      <media:thumbnail url="https://www.bigbinary.com/blog/images/social_preview_images/generated/rails-5-2-adds-bootsnap-to-the-app-to-speed-up-boot-time.png" width="1200" height="630"/>
      <summary type="text"><![CDATA[Rails 5.2 adds bootsnap gem to the Gemfile of newly created app so as to speed up boot time]]></summary>
      <content type="html" xml:base="https://www.bigbinary.com/blog/rails-5-2-adds-bootsnap-to-the-app-to-speed-up-boot-time"><![CDATA[<p>Rails 5.2 beta 1 was recently
<a href="http://weblog.rubyonrails.org/2017/11/27/Rails-5-2-Active-Storage-Redis-Cache-Store-HTTP2-Early-Hints-Credentials/">released</a>.</p>
<p>If we generate a new Rails app using Rails 5.2, we will see bootsnap gem in the
Gemfile. <a href="https://github.com/Shopify/bootsnap">bootsnap</a> helps in reducing the
boot time of the app by caching expensive computations.</p>
<p>In a new Rails 5.2 app, <code>boot.rb</code> will contain following content:</p>
<pre><code class="language-ruby">ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../Gemfile', __dir__)

require 'bundler/setup' # Set up gems listed in the Gemfile.
require 'bootsnap/setup' # Speed up boot time by caching expensive operations.

if %w[s server c console].any? { |a| ARGV.include?(a) }
  puts &quot;=&gt; Booting Rails&quot;
end
</code></pre>
<p>This sets up bootsnap to start in all environments. We can toggle it per
environment as required.</p>
<p>This works out of the box and we don't have do to anything for the new app.</p>
<p>If we are upgrading an older app which already has bootsnap, then we need to
make sure that we are using bootsnap &gt;= 1.1.0 because new Rails apps ship with
that version constraint.</p>
<p>If the app doesn't contain the bootsnap gem already then we will need to add it
manually since <code>rails app:update</code> task adds the <code>bootsnap/setup</code> line to
<code>boot.rb</code> regardless of its presence in the Gemfile.</p>
]]></content>
    </entry>
  <entry>
      <title type="text"><![CDATA[Rails 5.2 fetch_values for HashWithIndifferentAccess]]></title>
      <link rel="alternate" type="text/html" href="https://www.bigbinary.com/blog/rails-5-2-implements-fetch_values-for-hashwithindifferentaccess"/>
      <link rel="enclosure" type="image/png" href="https://www.bigbinary.com/blog/images/social_preview_images/generated/rails-5-2-implements-fetch_values-for-hashwithindifferentaccess.png"/>
      <id>https://www.bigbinary.com/blog/rails-5-2-implements-fetch_values-for-hashwithindifferentaccess</id>
      <published>2017-12-06T00:00:00.000Z</published>
      <updated>2017-12-06T00:00:00.000Z</updated>
      <author>
        <name>Mohit Natoo</name>
        <uri>https://www.bigbinary.com/blog/authors/mohit</uri>
      </author>
      <category term="Rails 5.2"/>
      <category term="Rails"/>
      <media:thumbnail url="https://www.bigbinary.com/blog/images/social_preview_images/generated/rails-5-2-implements-fetch_values-for-hashwithindifferentaccess.png" width="1200" height="630"/>
      <summary type="text"><![CDATA[Starting Rails 5.2 we'll be able to make use of fetch_values HashWithIndifferentAccess analogous to its use on Hash.]]></summary>
      <content type="html" xml:base="https://www.bigbinary.com/blog/rails-5-2-implements-fetch_values-for-hashwithindifferentaccess"><![CDATA[<p>Ruby 2.3 added
<a href="https://bugs.ruby-lang.org/issues/10017">fetch_values method to hash</a>.</p>
<p>By using <code>fetch_values</code> we are able to get values for multiple keys in a hash.</p>
<pre><code class="language-ruby">capitals = { usa: &quot;Washington DC&quot;,
             china: &quot;Beijing&quot;,
             india: &quot;New Delhi&quot;,
             australia: &quot;Canberra&quot; }

capitals.fetch_values(:usa, :india)
#=&gt; [&quot;Washington DC&quot;, &quot;New Delhi&quot;]

capitals.fetch_values(:usa, :spain) { |country| &quot;N/A&quot; }
#=&gt; [&quot;Washington DC&quot;, &quot;N/A&quot;]
</code></pre>
<p>Rails 5.2 introduces method <code>fetch_values</code>
<a href="https://github.com/rails/rails/pull/28316">on HashWithIndifferentAccess</a>. We'll
hence be able to fetch values of multiple keys on any instance of
HashWithIndifferentAccess class.</p>
<pre><code class="language-ruby">capitals = HashWithIndifferentAccess.new
capitals[:usa] = &quot;Washington DC&quot;
capitals[:china] = &quot;Beijing&quot;

capitals.fetch_values(&quot;usa&quot;, &quot;china&quot;)
#=&gt; [&quot;Washington DC&quot;, &quot;Beijing&quot;]

capitals.fetch_values(&quot;usa&quot;, &quot;spain&quot;) { |country| &quot;N/A&quot; }
#=&gt; [&quot;Washington DC&quot;, &quot;N/A&quot;]
</code></pre>
]]></content>
    </entry>
  <entry>
      <title type="text"><![CDATA[Rails 5.2 expiry option for signed & encrypted cookies]]></title>
      <link rel="alternate" type="text/html" href="https://www.bigbinary.com/blog/expirty-option-for-signed-and-encrypted-cookies-in-rails-5-2"/>
      <link rel="enclosure" type="image/png" href="https://www.bigbinary.com/blog/images/social_preview_images/generated/expirty-option-for-signed-and-encrypted-cookies-in-Rails-5-2.png"/>
      <id>https://www.bigbinary.com/blog/expirty-option-for-signed-and-encrypted-cookies-in-Rails-5-2</id>
      <published>2017-10-09T00:00:00.000Z</published>
      <updated>2017-10-09T00:00:00.000Z</updated>
      <author>
        <name>Mohit Natoo</name>
        <uri>https://www.bigbinary.com/blog/authors/mohit</uri>
      </author>
      <category term="Rails 5.2"/>
      <category term="Rails"/>
      <media:thumbnail url="https://www.bigbinary.com/blog/images/social_preview_images/generated/expirty-option-for-signed-and-encrypted-cookies-in-Rails-5-2.png" width="1200" height="630"/>
      <summary type="text"><![CDATA[Rails 5.2 adds expiry option for signed and encrypted cookies and adds relative expiry time]]></summary>
      <content type="html" xml:base="https://www.bigbinary.com/blog/expirty-option-for-signed-and-encrypted-cookies-in-rails-5-2"><![CDATA[<p>In Rails 5.1 we have option to set expiry for cookies.</p>
<pre><code class="language-ruby">cookies[:username] = {value: &quot;sam_smith&quot;, expires: Time.now + 4.hours}
</code></pre>
<p>The above code sets cookie which expires in 4 hours.</p>
<p>The <code>expires</code> option, is not supported for
<a href="https://blog.bigbinary.com/2013/03/19/cookies-on-rails.html">signed and encrypted cookies</a>.
In other words we are not able to decide on server side when an encrypted or
signed cookie would expire.</p>
<p>From Rails 5.2, we'll be able to
<a href="https://github.com/rails/rails/pull/30121">set expiry for encrypted and signed cookies</a>
as well.</p>
<pre><code class="language-ruby">cookies.encrypted[:firstname] = { value: &quot;Sam&quot;, expires: Time.now + 1.day }

# sets string `Sam` in an encrypted `firstname` cookie for 1 day.

cookies.signed[:lastname] = {value: &quot;Smith&quot;, expires: Time.now + 1.hour }

# sets string `Smith` in a signed `lastname` cookie for 1 hour.

</code></pre>
<p>Apart from this, in Rails 5.1, we needed to provide an absolute date/time value
for expires option.</p>
<pre><code class="language-ruby">
# setting cookie for 90 minutes from current time.

cookies[:username] = {value: &quot;Sam&quot;, expires: Time.now + 90.minutes}
</code></pre>
<p>Starting Rails 5.2, we'll be able to set the <code>expires</code> option by giving a
relative duration as value.</p>
<pre><code class="language-ruby">
# setting cookie for 90 minutes from current time.

cookies[:username] = { value: &quot;Sam&quot;, expires: 90.minutes }

# After 1 hour

&gt; cookies[:username]
&gt; #=&gt; &quot;Sam&quot;

# After 2 hours

&gt; cookies[:username]
&gt; #=&gt; nil
&gt; ~~~
</code></pre>
]]></content>
    </entry>
</feed>