<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Sebastian Sogamoso</title>
    <description>The latest articles on DEV Community by Sebastian Sogamoso (@sogamoso).</description>
    <link>https://dev.to/sogamoso</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F55210%2Fcd476964-0d2d-46a8-8518-caa53d32e1de.jpg</url>
      <title>DEV Community: Sebastian Sogamoso</title>
      <link>https://dev.to/sogamoso</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/sogamoso"/>
    <language>en</language>
    <item>
      <title>Rails signed IDs for ActiveRecord</title>
      <dc:creator>Sebastian Sogamoso</dc:creator>
      <pubDate>Tue, 19 May 2020 22:56:56 +0000</pubDate>
      <link>https://dev.to/sogamoso/rails-signed-ids-for-active-record-5b7o</link>
      <guid>https://dev.to/sogamoso/rails-signed-ids-for-active-record-5b7o</guid>
      <description>&lt;p&gt;Starting with version 6.1, &lt;code&gt;ActiveRecord&lt;/code&gt; will support looking for records using signed IDs. This feature can be handy when doing things like resetting passwords, sending invitations, or doing email verification.&lt;/p&gt;

&lt;p&gt;Signed IDs have three characteristics:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;They are tamper-proof&lt;/li&gt;
&lt;li&gt;They can be set to expire&lt;/li&gt;
&lt;li&gt;They can be scoped to a particular purpose&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  How is this different from GlobalId?
&lt;/h3&gt;

&lt;p&gt;The above seems oddly similar to &lt;a href="https://github.com/rails/globalid#signed-global-ids"&gt;Signed Global IDs&lt;/a&gt;, so you may be wondering, why was this feature introduced?&lt;/p&gt;

&lt;p&gt;The main difference is that &lt;code&gt;ActiveRecord&lt;/code&gt; signed IDs can only be used when referring to a single concrete class, conversely &lt;code&gt;GlobalId&lt;/code&gt; can be used when the passed ID might respond to any number of classes.&lt;/p&gt;

&lt;h3&gt;
  
  
  How can I use signed IDs?
&lt;/h3&gt;

&lt;p&gt;When Rails 6.1 is released all &lt;code&gt;ActiveRecord&lt;/code&gt; instances will respond to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;signed_id&lt;/code&gt; to generate the token&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;find_signed&lt;/code&gt; to find a record using the token&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;find_signed!&lt;/code&gt; same as the above but instead of returning &lt;code&gt;nil&lt;/code&gt; when the record is not found an error will be raised&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here's a simple example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;signed_user_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;User&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;first&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;signed_id&lt;/span&gt;

&lt;span class="no"&gt;User&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find_signed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;signed_user_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;User&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;first&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you want to set a purpose and expiration to the token you can pass them as arguments to &lt;code&gt;signed_id&lt;/code&gt;, like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;signed_user_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;User&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;first&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;signed_id&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;purpose: :email_confirmation&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;expires_in: &lt;/span&gt;&lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;minutes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;from_now&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="no"&gt;User&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find_signed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;signed_user_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kp"&gt;nil&lt;/span&gt;

&lt;span class="no"&gt;User&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find_signed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;signed_user_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;purpose: :other&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kp"&gt;nil&lt;/span&gt;

&lt;span class="no"&gt;User&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find_signed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;signed_user_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;purpose: &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;email_confirmation&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;User&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;first&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you don't want the query to silently fail, you can use the bang-method alternative:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="no"&gt;User&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find_signed!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"invalid_token"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;ActiveSupport&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;MessageVerifier&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;InvalidSignature&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Rails will automatically generate a &lt;code&gt;signed_id_verifier_secret&lt;/code&gt; to be used when encoding and decoding the tokens. You can also provide your own in an initializer.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# config/initializers/active_record.rb&lt;/span&gt;
&lt;span class="no"&gt;ActiveRecord&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Base&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;signed_id_verifier_secret&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"custom_verfifier_secret"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you are interested in learning how this was implemented, take a look at the &lt;a href="https://github.com/rails/rails/pull/39313/files"&gt;pull request&lt;/a&gt; where this feature was introduced.&lt;/p&gt;

</description>
      <category>rails</category>
      <category>activerecord</category>
    </item>
  </channel>
</rss>
