<?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: Emmanuel Hayford</title>
    <description>The latest articles on DEV Community by Emmanuel Hayford (@siaw23).</description>
    <link>https://dev.to/siaw23</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%2F168215%2Fa600cded-83ab-43d4-958b-e6ed7407d761.JPG</url>
      <title>DEV Community: Emmanuel Hayford</title>
      <link>https://dev.to/siaw23</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/siaw23"/>
    <language>en</language>
    <item>
      <title>Secure Your Ruby App with JSON Web Tokens</title>
      <dc:creator>Emmanuel Hayford</dc:creator>
      <pubDate>Wed, 30 Aug 2023 11:15:47 +0000</pubDate>
      <link>https://dev.to/appsignal/secure-your-ruby-app-with-json-web-tokens-39nb</link>
      <guid>https://dev.to/appsignal/secure-your-ruby-app-with-json-web-tokens-39nb</guid>
      <description>&lt;p&gt;If a web application involves users, as a matter of course, their data should be protected and secured.&lt;/p&gt;

&lt;p&gt;Securing a web application can mean several things. In this post, we'll discuss a subset of web security that involves authentication using JSON Web Tokens (JWTs) and the Ruby on Rails web application framework.&lt;/p&gt;

&lt;p&gt;Let's get started!&lt;/p&gt;

&lt;h2&gt;
  
  
  What is a JSON Web Token?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://datatracker.ietf.org/doc/html/rfc7519"&gt;A JSON Web Token&lt;/a&gt; is an internet standard defined by the Internet Engineering Task Force (IETF) as a: "compact, URL-safe means of representing claims to be transferred between two parties".&lt;/p&gt;

&lt;p&gt;Here, "claims" refers to assorted pieces of information about a subject. A claim is represented as a name/value pair where the name is always a string, and the value can be any JSON value.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Basic Structure of JSON Web Tokens
&lt;/h2&gt;

&lt;p&gt;Delving into the intricacies of JWTs is out of the scope of this post. That said, it's worth knowing the structure of JWTs.&lt;/p&gt;

&lt;p&gt;A JWT consists of three parts, separated by a period: the header, payload, and signature.&lt;/p&gt;

&lt;p&gt;An example JWT could look like the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.
eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.
SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For the sake of readability, each part of the token starts on a new line. In practice, the parts are joined.&lt;/p&gt;

&lt;p&gt;This token is sent from a server to a client. The client sends the token to the server to identify itself and have a request processed.&lt;/p&gt;

&lt;p&gt;The first part, the header, contains information about the algorithm used to generate the token and the type of token. If decoded, we get something like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"alg"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"HS256"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"typ"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"JWT"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The second part, the payload, contains a set of claims about the user. In most cases, this would be the client in a client-server setup, and it could look like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"sub"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"1234567890"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"John Doe"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"iat"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1516239022&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The signature (the last part of a signed JWT) validates the token. It is generated by encoding the header and the payload using &lt;a href="https://datatracker.ietf.org/doc/html/rfc4648"&gt;Base64url Encoding — RFC 4648&lt;/a&gt; and then concatenating them with a period separator.&lt;/p&gt;

&lt;p&gt;Essentially, what happens with the signature bit is this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;HMAC_SHA256(
  secret,
  base64urlEncoding(header) + '.' +
  base64urlEncoding(payload)
)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;HMAC_SHA256&lt;/code&gt; is a type of keyed hash algorithm constructed from the SHA-256 hash function that hashes the signature. The choice of the cryptographic algorithm comes from the &lt;code&gt;"alg": "HS256"&lt;/code&gt; in the header. If the token is unsigned, it'll only have the header and payload without the signature.&lt;/p&gt;

&lt;h2&gt;
  
  
  JWTs Vs. Other Authentication Methods for Your Ruby App
&lt;/h2&gt;

&lt;p&gt;JSON Web Tokens, as the name implies, are token-based. On the other end of the spectrum, we have session-based authentication: a more traditional way of authenticating users. The flow of session-based authentication is quite different from that of token-based authentication.&lt;/p&gt;

&lt;p&gt;The flow of session-based authentication might look like the following:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;A user or client sends a request which contains user credentials.&lt;/li&gt;
&lt;li&gt;The server authenticates the user, stores a session, and returns a session ID stored as a cookie in the browser.&lt;/li&gt;
&lt;li&gt;The client sends the cookies along with its subsequent requests to the server.&lt;/li&gt;
&lt;li&gt;The server inspects the session information presented and, if valid, authenticates the user and returns the requested information to the client.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;While session-based authentication is mostly used for client-server connections, token-based authentication is often used with server-server connections (e.g., between two APIs).&lt;/p&gt;

&lt;p&gt;One important difference to note, however, is that with session-based authentication, the authentication state is handled on the server — while tokens are managed on the client.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Use JWTs for Authentication?
&lt;/h2&gt;

&lt;p&gt;Aside from being relatively simple to implement, there are a few other advantages of using JSON Web Tokens for authentication, such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;They are &lt;strong&gt;stateless&lt;/strong&gt;, meaning that a session store is not necessary. The token itself contains all of the user information, so there is no need to query a database or authentication server for information on each request.&lt;/li&gt;
&lt;li&gt;JWTs are &lt;strong&gt;generally more performant&lt;/strong&gt; than most traditional methods of authentication (as long as the server doesn't do any lookups against a database or store to authenticate a user), making them quite efficient.&lt;/li&gt;
&lt;li&gt;They also offer &lt;strong&gt;solid security guarantees&lt;/strong&gt;, in that signed JWTs provide safeguards so an attacker or client can't modify the tokens to gain access to protected data.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  JWT Best Practices for Ruby Apps
&lt;/h2&gt;

&lt;p&gt;It goes without saying that the secret keys used to sign JWTs should be long, random, and have complex character combinations. This ensures that the keys are adequately safe and it's hard for attackers to brute-force them.&lt;/p&gt;

&lt;p&gt;The secret keys Rails generates are safe for the most part, but safety guarantees are nullified if you accidentally commit keys and reveal them.&lt;/p&gt;

&lt;p&gt;It's also important to use Transport Layer Security (TLS) when transporting tokens between parties on a network. TLS can mitigate a man-in-the-middle attack (both token and session-based authentication methods are prone to such attacks).&lt;/p&gt;

&lt;h2&gt;
  
  
  Implementing JWT authentication in a Rails App
&lt;/h2&gt;

&lt;p&gt;Let's take a look at a token-based authentication flow:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--6C6pQJez--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://blog.appsignal.com/images/blog/2023-08/jwt-auth-flow.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--6C6pQJez--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://blog.appsignal.com/images/blog/2023-08/jwt-auth-flow.png" alt="Token-based Authentication Flow" width="800" height="511"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Unlike session-based authentication, a stateful authentication technique where we use sessions to keep track of an authenticated user, token-based authentication with JWTs is stateless; there's no need to store any information about a user's authentication state on the server. This simplifies application design.&lt;/p&gt;

&lt;p&gt;In this post, we'll assume that our application is split into a frontend and a backend. Authentication occurs on the backend, so we will be building a Rails API backend with authentication.&lt;/p&gt;

&lt;p&gt;The sample code in this post is based on Rails 7.0.5 and Ruby 3.2.2.&lt;/p&gt;

&lt;h3&gt;
  
  
  Using the &lt;code&gt;jwt&lt;/code&gt; and &lt;code&gt;bcrypt&lt;/code&gt; Ruby Gems
&lt;/h3&gt;

&lt;p&gt;We'll need two gems for our application: &lt;code&gt;jwt&lt;/code&gt; and &lt;code&gt;bcrypt&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;jwt&lt;/code&gt; is a &lt;a href="https://github.com/jwt/ruby-jwt"&gt;Ruby implementation&lt;/a&gt; of the RFC 7519 OAuth JSON Web Token standard. &lt;code&gt;bcrypt&lt;/code&gt; is a Ruby binding for the OpenBSD &lt;code&gt;bcrypt()&lt;/code&gt; password hashing algorithm.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/siaw23/jwt_rails_api"&gt;You can follow along with the sample code in this code repo.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; &lt;em&gt;&lt;code&gt;jwt&lt;/code&gt; is not the only solution for working with JWTs; another well-known gem is &lt;code&gt;devise-jwt&lt;/code&gt;, which provides JWT authentication for Devise and Rails. But we'll focus on &lt;code&gt;jwt&lt;/code&gt; in this post.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Let's get started.&lt;/p&gt;

&lt;h3&gt;
  
  
  Building our Rails API
&lt;/h3&gt;

&lt;p&gt;The first thing we need is an API application. We'll create one with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;rails new jwt_rails_api &lt;span class="nt"&gt;--api&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;--api&lt;/code&gt; option here preconfigures a smaller stack of Rails for API applications only.&lt;/p&gt;

&lt;p&gt;Inside the Gemfile, we can add our first dependency, &lt;code&gt;jwt&lt;/code&gt;. Our second gem, &lt;code&gt;bcrypt&lt;/code&gt;, is already in the Gemfile of a newly-generated Rails application — we only need to uncomment it.&lt;/p&gt;

&lt;p&gt;We need &lt;code&gt;bcrypt&lt;/code&gt; to securely hash user passwords in the database. It's important to note that we won't use &lt;code&gt;bcrypt&lt;/code&gt; directly. We'll leverage Active Model's &lt;code&gt;has_secure_password&lt;/code&gt; class method, which depends on &lt;code&gt;bcrypt&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Ignoring the default gems that come with a new Rails application, our Gemfile should look something like:&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;gem&lt;/span&gt; &lt;span class="s1"&gt;'jwt'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'~&amp;gt; 2.7'&lt;/span&gt;
&lt;span class="n"&gt;gem&lt;/span&gt; &lt;span class="s2"&gt;"bcrypt"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"~&amp;gt; 3.1.7"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now is a good time to install our gems with &lt;code&gt;bundle install&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Generate &lt;code&gt;User&lt;/code&gt; and &lt;code&gt;Product&lt;/code&gt; Models
&lt;/h3&gt;

&lt;p&gt;Next, we'll generate two models: &lt;code&gt;User&lt;/code&gt; and &lt;code&gt;Product&lt;/code&gt;. &lt;code&gt;User&lt;/code&gt; will be the model to represent users and we'll authenticate it to allow access to products, represented by the &lt;code&gt;Product&lt;/code&gt; model.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;rails g model User username:string password_digest:string
rails g model Product name:string description:text
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After running our migration with &lt;code&gt;rails db:migrate&lt;/code&gt;, our setup with models is complete, and our schema, found in &lt;code&gt;db/schema.rb&lt;/code&gt;, should now look similar to 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="no"&gt;ActiveRecord&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Schema&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mf"&gt;7.0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;define&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;version: &lt;/span&gt;&lt;span class="mi"&gt;2023_05_28_224534&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;create_table&lt;/span&gt; &lt;span class="s2"&gt;"products"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;force: :cascade&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
    &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt; &lt;span class="s2"&gt;"name"&lt;/span&gt;
    &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;text&lt;/span&gt; &lt;span class="s2"&gt;"description"&lt;/span&gt;
    &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;datetime&lt;/span&gt; &lt;span class="s2"&gt;"created_at"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;null: &lt;/span&gt;&lt;span class="kp"&gt;false&lt;/span&gt;
    &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;datetime&lt;/span&gt; &lt;span class="s2"&gt;"updated_at"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;null: &lt;/span&gt;&lt;span class="kp"&gt;false&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="n"&gt;create_table&lt;/span&gt; &lt;span class="s2"&gt;"users"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;force: :cascade&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
    &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt; &lt;span class="s2"&gt;"username"&lt;/span&gt;
    &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt; &lt;span class="s2"&gt;"password_digest"&lt;/span&gt;
    &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;datetime&lt;/span&gt; &lt;span class="s2"&gt;"created_at"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;null: &lt;/span&gt;&lt;span class="kp"&gt;false&lt;/span&gt;
    &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;datetime&lt;/span&gt; &lt;span class="s2"&gt;"updated_at"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;null: &lt;/span&gt;&lt;span class="kp"&gt;false&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;It's important to point out at this stage that we're deliberately ignoring potential issues such as database constraints, validations, ensuring uniqueness, etc. For the sake of this post, we'll disregard handling errors, among others. Our purpose here is to demonstrate JWTs in action as a form of stateless authentication to secure our Ruby application. In a production application, you'd want to make sure all of these are covered.&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Build a &lt;code&gt;jwt&lt;/code&gt; Gem Wrapper
&lt;/h3&gt;

&lt;p&gt;The next step is to build a wrapper around the &lt;code&gt;jwt&lt;/code&gt; gem we installed earlier. We'll use this wrapper to encode and decode claims from the server to the client. For this, we'll create an &lt;code&gt;app/lib&lt;/code&gt; folder.&lt;/p&gt;

&lt;p&gt;The reason we're not using the &lt;code&gt;lib&lt;/code&gt; folder that comes with Rails is that it's not autoloaded. Everything under &lt;code&gt;app&lt;/code&gt; is autoloaded and eager-loaded by default, making for a simpler setup in our case.&lt;/p&gt;

&lt;p&gt;Our wrapper class is found in &lt;code&gt;app/lib/json_web_token.rb&lt;/code&gt; and looks 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="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;JsonWebToken&lt;/span&gt;
  &lt;span class="no"&gt;JWT_SECRET&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Rails&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;application&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;secrets&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;secret_key_base&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nc"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;exp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;hours&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="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:exp&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;exp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;to_i&lt;/span&gt;

    &lt;span class="no"&gt;JWT&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;JWT_SECRET&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nc"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;body&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;JWT&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;JWT_SECRET&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

    &lt;span class="no"&gt;HashWithIndifferentAccess&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The main methods here are &lt;code&gt;encode&lt;/code&gt; — to encode user information — and &lt;code&gt;decode&lt;/code&gt; — to later decode user information in the server. Note how we're delegating the encoding and decoding tasks to the &lt;code&gt;jwt&lt;/code&gt; gem through &lt;code&gt;JWT.encode&lt;/code&gt; and &lt;code&gt;JWT.decode&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;At this point, you can already test this class in your Rails console:&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;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;"name"&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="s2"&gt;"AppSignal"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="no"&gt;JsonWebToken&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;# =&amp;gt; "eyJhbGciOiJIUzI1NiJ9.eyJuYW1lIjoiQXBwU2lnbmFsIiwiZXhwIjoxNjg1NDI0MjI5fQ.zWJyFHH8Pa6phBOU99XgtRntyfZQSOTX4TdwOxFY9gY"&lt;/span&gt;

&lt;span class="no"&gt;JsonWebToken&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;JsonWebToken&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="c1"&gt;# =&amp;gt; {"name"=&amp;gt;"AppSignal", "exp"=&amp;gt;1685424262}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice how the result of &lt;code&gt;JsonWebToken.encode(data)&lt;/code&gt; is split into three parts by a period, producing the header, payload, and signature. We have the signature bit because we signed our payload with a secret key that Rails provides through &lt;code&gt;Rails.application.secrets.secret_key_base&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Back to the &lt;code&gt;User&lt;/code&gt; Model
&lt;/h3&gt;

&lt;p&gt;Now will be a good time to visit our &lt;code&gt;User&lt;/code&gt; model at &lt;code&gt;app/models/user.rb&lt;/code&gt;. All we need to do here is add the &lt;code&gt;has_secure_password&lt;/code&gt; class method:&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="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ApplicationRecord&lt;/span&gt;
  &lt;span class="n"&gt;has_secure_password&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;has_secure_password&lt;/code&gt; &lt;a href="https://guides.rubyonrails.org/active_model_basics.html#securepassword"&gt;securely hashes&lt;/a&gt; our users' passwords in the database.&lt;/p&gt;

&lt;h3&gt;
  
  
  Create a Sample User and Product in Rails
&lt;/h3&gt;

&lt;p&gt;Now we can hop into the Rails console to generate a sample user and product in our database and test the security of our application:&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;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;username: &lt;/span&gt;&lt;span class="s2"&gt;"emi"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;password: &lt;/span&gt;&lt;span class="s2"&gt;"password"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="no"&gt;Product&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;name: &lt;/span&gt;&lt;span class="s2"&gt;"Rad Ruby"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;description: &lt;/span&gt;&lt;span class="s2"&gt;"A book collection of Ruby tips"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can place the same piece of code in your &lt;code&gt;seeds.rb&lt;/code&gt; file to save some typing in case you reset your database.&lt;/p&gt;

&lt;h3&gt;
  
  
  Using JWTs in Rails Controllers
&lt;/h3&gt;

&lt;p&gt;In the next steps, we'll implement security using JWTs inside our controllers. A good place to start is the &lt;code&gt;ApplicationController&lt;/code&gt; at &lt;code&gt;app/controllers/application_controller.rb&lt;/code&gt;:&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="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ApplicationController&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ActionController&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;API&lt;/span&gt;
  &lt;span class="n"&gt;before_action&lt;/span&gt; &lt;span class="ss"&gt;:authenticate&lt;/span&gt;

  &lt;span class="n"&gt;rescue_from&lt;/span&gt; &lt;span class="no"&gt;JWT&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;VerificationError&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;with: :invalid_token&lt;/span&gt;
  &lt;span class="n"&gt;rescue_from&lt;/span&gt; &lt;span class="no"&gt;JWT&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;DecodeError&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;with: :decode_error&lt;/span&gt;

  &lt;span class="kp"&gt;private&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;authenticate&lt;/span&gt;
    &lt;span class="n"&gt;authorization_header&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'Authorization'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;token&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;authorization_header&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;" "&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;last&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;authorization_header&lt;/span&gt;
    &lt;span class="n"&gt;decoded_token&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;JsonWebToken&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;token&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&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;decoded_token&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:user_id&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;invalid_token&lt;/span&gt;
    &lt;span class="n"&gt;render&lt;/span&gt; &lt;span class="ss"&gt;json: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="ss"&gt;invalid_token: &lt;/span&gt;&lt;span class="s1"&gt;'invalid token'&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;decode_error&lt;/span&gt;
    &lt;span class="n"&gt;render&lt;/span&gt; &lt;span class="ss"&gt;json: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="ss"&gt;decode_error: &lt;/span&gt;&lt;span class="s1"&gt;'decode error'&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, we create an &lt;code&gt;authenticate&lt;/code&gt; method to decode JSON Web tokens that users send us. If we can successfully verify the token, we return the &lt;code&gt;User&lt;/code&gt; object that represents the user making the request. We're mostly interested in the happy path here and will bypass a lot of checks.&lt;/p&gt;

&lt;p&gt;Defining the &lt;code&gt;authenticate&lt;/code&gt; method in the &lt;code&gt;ApplicationController&lt;/code&gt; and setting it up as a &lt;code&gt;before_action&lt;/code&gt; secures every controller inheriting from it. A request to any other controller will need a valid JWT to access those controllers (because every other controller will inherit this main controller).&lt;/p&gt;

&lt;p&gt;Next, we need an &lt;code&gt;AuthenticationController&lt;/code&gt; to which users can send requests and get a signed JSON Web Token from our server. This controller should be placed at &lt;code&gt;app/controllers/authentication_controller.rb&lt;/code&gt; and may look 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="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AuthenticationController&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ApplicationController&lt;/span&gt;
  &lt;span class="n"&gt;skip_before_action&lt;/span&gt; &lt;span class="ss"&gt;:authenticate&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;login&lt;/span&gt;
    &lt;span class="n"&gt;user&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;find_by&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;username: &lt;/span&gt;&lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:username&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
    &lt;span class="n"&gt;authenticated_user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;authenticate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:password&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;authenticated_user&lt;/span&gt;
      &lt;span class="n"&gt;token&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;JsonWebToken&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;user_id: &lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="n"&gt;expires_at&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;JsonWebToken&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="ss"&gt;:exp&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

      &lt;span class="n"&gt;render&lt;/span&gt; &lt;span class="ss"&gt;json: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="p"&gt;:,&lt;/span&gt; &lt;span class="ss"&gt;expires_at: &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="ss"&gt;status: :ok&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;
      &lt;span class="n"&gt;render&lt;/span&gt; &lt;span class="ss"&gt;json: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="ss"&gt;error: &lt;/span&gt;&lt;span class="s1"&gt;'unauthorized'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="ss"&gt;status: :unauthorized&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When a request hits this controller, because it's a user asking for a token, we don't want to initially authenticate them. The purpose of this controller is to respond with a token the user can use to access the rest of the resources on our server. Hence the need for &lt;code&gt;skip_before_action :authenticate&lt;/code&gt; on the second line.&lt;/p&gt;

&lt;p&gt;In the &lt;code&gt;login&lt;/code&gt; action (the one that users hit for a token), we grab the &lt;code&gt;username&lt;/code&gt; and &lt;code&gt;password&lt;/code&gt; from the parameters that come with the request to this controller. If we can authenticate the user — that is, verify if their username and password match what we have stored in our database — then we present them with a signed token and information about when that token expires.&lt;/p&gt;

&lt;p&gt;In our case, we won't use the expiry period of the token. But in a production application, that could be used to revoke access to a resource.&lt;/p&gt;

&lt;p&gt;We'll go through all these steps using &lt;code&gt;curl&lt;/code&gt; later on.&lt;/p&gt;

&lt;h2&gt;
  
  
  Testing Our Ruby Application with a Protected Resource
&lt;/h2&gt;

&lt;p&gt;We partly covered the flow in the earlier 'Implementing JWT authentication in a Rails App' section's flow diagram. To completely cover everything and test out all the steps in the flow diagram, we need a resource to protect.&lt;/p&gt;

&lt;p&gt;We have a &lt;code&gt;Product&lt;/code&gt; model already. We now need a controller for the product model and routes to access the product and tokens.&lt;/p&gt;

&lt;p&gt;Let's create a controller with &lt;code&gt;rails g controller Product index&lt;/code&gt; so we have something like:&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="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ProductsController&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ApplicationController&lt;/span&gt;
  &lt;span class="n"&gt;before_action&lt;/span&gt; &lt;span class="ss"&gt;:authenticate&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;index&lt;/span&gt;
    &lt;span class="vi"&gt;@products&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Product&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;all&lt;/span&gt;

    &lt;span class="n"&gt;render&lt;/span&gt; &lt;span class="ss"&gt;json: &lt;/span&gt;&lt;span class="vi"&gt;@products&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Of course, we need a route to access these controllers. Our &lt;code&gt;config/routes.rb&lt;/code&gt; should look something like:&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;Rails&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;application&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;routes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;draw&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;post&lt;/span&gt; &lt;span class="s1"&gt;'login'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;to: &lt;/span&gt;&lt;span class="s2"&gt;"authentication#login"&lt;/span&gt;
  &lt;span class="n"&gt;get&lt;/span&gt; &lt;span class="s1"&gt;'products'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;to: &lt;/span&gt;&lt;span class="s2"&gt;"products#index"&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we'll test with &lt;code&gt;curl&lt;/code&gt; to see if everything works as expected. Note that we already have a user to authenticate and a product resource to access.&lt;/p&gt;

&lt;p&gt;Let's try getting a JWT with a user that doesn't exist:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="nt"&gt;-X&lt;/span&gt; POST &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{"username":"manny","password":"password"}'&lt;/span&gt; http://localhost:3000/login
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We should get the following response:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;"error"&lt;/span&gt;:&lt;span class="s2"&gt;"unauthorized"&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now try the same with a user that we created earlier:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="nt"&gt;-X&lt;/span&gt; POST &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{"username":"emi","password":"password"}'&lt;/span&gt; http://localhost:3000/login
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This should give us a signed JSON web token that could look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;"token"&lt;/span&gt;:&lt;span class="s2"&gt;"eyJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoxLCJleHAiOjE2ODU0NTEyMTR9.1UEYAbmFOSF93yp9pJqNEzkdHr3rVqutPNZWRIPDYkY"&lt;/span&gt;,&lt;span class="s2"&gt;"expires_at"&lt;/span&gt;:1685432077&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's keep this token for a second and try accessing a product resource with a bad token (I changed a random character in the token):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Authorization: Bearer eyJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoxLCJleHAiOjE2ODU0NTEyMTR9.1UEYAbmFOSF93yp9pJqNEzkdHr3rVqutPNZWRIPZYkY"&lt;/span&gt; http://localhost:3000/products
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And we should get:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;"decode_error"&lt;/span&gt;:&lt;span class="s2"&gt;"decode error"&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;However, if we make the same request to access the product resource with the valid token we got from the server previously:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Authorization: Bearer eyJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoxLCJleHAiOjE2ODU0NTEyMTR9.1UEYAbmFOSF93yp9pJqNEzkdHr3rVqutPNZWRIPDYkY"&lt;/span&gt; http://localhost:3000/products
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We're granted access to the product resource:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;[{&lt;/span&gt;&lt;span class="s2"&gt;"id"&lt;/span&gt;:1,&lt;span class="s2"&gt;"name"&lt;/span&gt;:&lt;span class="s2"&gt;"Rad Ruby"&lt;/span&gt;,&lt;span class="s2"&gt;"description"&lt;/span&gt;:&lt;span class="s2"&gt;"A book collection of Ruby tips"&lt;/span&gt;,&lt;span class="s2"&gt;"created_at"&lt;/span&gt;:&lt;span class="s2"&gt;"2023-05-29T19:33:30.826Z"&lt;/span&gt;,&lt;span class="s2"&gt;"updated_at"&lt;/span&gt;:&lt;span class="s2"&gt;"2023-05-29T19:33:30.826Z"&lt;/span&gt;&lt;span class="o"&gt;}]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's it! We've successfully secured our Ruby application with a JSON web token!&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrapping Up
&lt;/h2&gt;

&lt;p&gt;In this post, we discussed JSON Web Tokens and how they work. We first covered the basics of JWTs, including their structure and some best practices. Then we implemented a simple JWT authentication using the &lt;code&gt;jwt&lt;/code&gt; gem.&lt;/p&gt;

&lt;p&gt;I hope you've found this post helpful. Happy coding!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;P.S. If you'd like to read Ruby Magic posts as soon as they get off the press, &lt;a href="https://blog.appsignal.com/ruby-magic"&gt;subscribe to our Ruby Magic newsletter and never miss a single post&lt;/a&gt;!&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>ruby</category>
    </item>
    <item>
      <title>What's New in Rails 7.1</title>
      <dc:creator>Emmanuel Hayford</dc:creator>
      <pubDate>Tue, 28 Feb 2023 15:53:35 +0000</pubDate>
      <link>https://dev.to/appsignal/whats-new-in-rails-71-4alb</link>
      <guid>https://dev.to/appsignal/whats-new-in-rails-71-4alb</guid>
      <description>&lt;p&gt;Rails 7 was a welcome release that brought a lot of significant features and changes. On the backend, Rails 7 introduced asynchronous query loading and Zeitwerk for autoloading. The frontend saw Hotwire becoming the default solution for new Rails apps.&lt;/p&gt;

&lt;p&gt;Rails 7.1 will add to these notable features. In this post, we'll discuss some noteworthy additions that are likely to be shipped.&lt;/p&gt;

&lt;h2&gt;
  
  
  A New API for Async Queries in Rails
&lt;/h2&gt;

&lt;p&gt;Building on an earlier feature from Rails 7, Rails 7.1 will make it possible to run some queries asynchronously. Rails 7 introduced &lt;code&gt;ActiveRecord::Relation#load_async&lt;/code&gt;, which schedules a query in a background thread pool, allowing us to do stuff like &lt;code&gt;Post.where(published: true).load_async&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;In Rails 7.1, we'll be able to run a lot more queries in background threads. Aggregate methods will run concurrently. Assuming you run two or more independent queries on a job or controller, query results may return quicker if your application is set up accordingly.&lt;/p&gt;

&lt;p&gt;For this to work as intended, there are two configuration options worth paying attention to:&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;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;active_record&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;async_query_executor&lt;/span&gt;
&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;active_record&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;global_executor_concurrency&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Among the methods you can run asynchrously in Rails 7.1 are &lt;code&gt;async_sum&lt;/code&gt;, &lt;code&gt;async_pluck&lt;/code&gt;, and &lt;code&gt;async_count_by_sql&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Resetting Singular Associations
&lt;/h2&gt;

&lt;p&gt;Rails 7.1 allows resetting the cache on singular associations. Currently, you can only clear the cache of &lt;code&gt;has_many&lt;/code&gt; associations with a class like:&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="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Teacher&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&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="n"&gt;has_many&lt;/span&gt; &lt;span class="ss"&gt;:students&lt;/span&gt;
  &lt;span class="n"&gt;has_one&lt;/span&gt; &lt;span class="ss"&gt;:classroom&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="n"&gt;teacher&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Teacher&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;We can only do &lt;code&gt;teacher.students.reset&lt;/code&gt; to clear the caches of the results returned by &lt;code&gt;teacher.students&lt;/code&gt;. Subsequent requests need to hit the database again for a fresh results set in case some data goes stale.&lt;/p&gt;

&lt;p&gt;With Rails 7.1, we'll get the &lt;code&gt;reset&lt;/code&gt; method on a &lt;code&gt;has_one&lt;/code&gt; association. Using our example class above, Rails 7.1 will allow us to do &lt;code&gt;teacher.classroom.reset_teacher&lt;/code&gt; to clear the cache for the associations between &lt;code&gt;teacher&lt;/code&gt; and &lt;code&gt;classroom&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Disabling Methods Generated By &lt;code&gt;ActiveRecord#enum&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;ActiveRecord#enum&lt;/code&gt; generates a bunch of methods if you create an enum Rails. Rails 7.1 will provide an option to opt out of these generated methods. 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="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Payment&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&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="n"&gt;enum&lt;/span&gt; &lt;span class="ss"&gt;:status&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sx"&gt;%i[succeeded failed]&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;instance_methods: &lt;/span&gt;&lt;span class="kp"&gt;false&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Rails won't generate auxiliary methods with &lt;code&gt;instance_methods: false&lt;/code&gt;. Currently, we expect to have methods like:&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;payment&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Payment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;first&lt;/span&gt;

&lt;span class="n"&gt;payment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;succeeded?&lt;/span&gt;
&lt;span class="n"&gt;payment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;failed?&lt;/span&gt;

&lt;span class="n"&gt;payment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;succeeded!&lt;/span&gt;
&lt;span class="n"&gt;payment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;failed!&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Support for Common Table Expressions
&lt;/h2&gt;

&lt;p&gt;Rails 7.1 will have in-built support for Common Table Expressions (CTEs). This ensures that code will be more succinct but, more importantly, that we won't have to use &lt;code&gt;Arel::Nodes&lt;/code&gt; for complex queries.&lt;/p&gt;

&lt;p&gt;With Rails 7.1, we'll have a new &lt;code&gt;.with&lt;/code&gt; method to write queries similar to the one below:&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;Post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;with&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="ss"&gt;posts_with_comments: &lt;/span&gt;&lt;span class="no"&gt;Post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"comments_count &amp;gt; ?"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="ss"&gt;posts_with_tags: &lt;/span&gt;&lt;span class="no"&gt;Post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"tags_count &amp;gt; ?"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Support for Async Bulk Record Destruction
&lt;/h2&gt;

&lt;p&gt;As mentioned, Rails 7.1 will introduce several ways to run code asynchronously. One such new addition to async code executions is the &lt;code&gt;destroy_association_async_batch_size&lt;/code&gt; configuration.&lt;/p&gt;

&lt;p&gt;With this new configuration, Rails applications can set a maximum number of records to be destroyed in a single background job by the &lt;code&gt;dependent: :destroy_async&lt;/code&gt; association.&lt;/p&gt;

&lt;p&gt;The default behavior, where all dependent records are destroyed in a single background job when the parent record is destroyed, will remain unchanged. However, if the number of dependent records exceeds the new configuration, they will be destroyed in multiple background jobs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Other Rails 7.1 Updates
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;ActiveRecord::Relation#explain&lt;/code&gt; Accepts Options
&lt;/h3&gt;

&lt;p&gt;Rails 7.1 will allow you to pass database systems that support &lt;code&gt;EXPLAIN&lt;/code&gt; options to &lt;code&gt;ActiveRecord::Relation#explain&lt;/code&gt;. An example query might look 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="no"&gt;Customer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;id: &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;joins&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:orders&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;explain&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:analyze&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:verbose&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Active Record &lt;code&gt;regroup&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Active Record will allow for "regrouping" queries with a new &lt;code&gt;regroup&lt;/code&gt; method that can be used like so: &lt;code&gt;Post.group(:title).regroup(:author)&lt;/code&gt;. This generates SQL equivalent to &lt;code&gt;SELECT posts.* FROM posts GROUP BY posts.author&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The same can be achieved in current versions of Rails with more verbose code:&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;Post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;group&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:title&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="n"&gt;unscope&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:group&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;group&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:author&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  New &lt;code&gt;stub_const method&lt;/code&gt; for Testing
&lt;/h3&gt;

&lt;p&gt;A new &lt;code&gt;stub_const&lt;/code&gt; method for &lt;code&gt;ActiveSupport::TestCase&lt;/code&gt; will be added that stubs a constant for a yield's duration.&lt;/p&gt;

&lt;p&gt;For 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="c1"&gt;# World::List::Import::LARGE_IMPORT_THRESHOLD = 5000&lt;/span&gt;

&lt;span class="n"&gt;stub_const&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;World&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;List&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Import&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:LARGE_IMPORT_THRESHOLD&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;assert_equal&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;World&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;List&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Import&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;LARGE_IMPORT_THRESHOLD&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="n"&gt;assert_equal&lt;/span&gt; &lt;span class="mi"&gt;5000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;World&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;List&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Import&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;LARGE_IMPORT_THRESHOLD&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;5000&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Take note, however, that stubbing a constant will affect its value across all threads in a multi-threaded setup. This means that if multiple concurrent threads rely on the same constant, simultaneous and conflicting stubbing may occur.&lt;/p&gt;

&lt;h3&gt;
  
  
  Password Challenge via &lt;code&gt;has_secure_password&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Rails 7.1 has improved the functionality of &lt;code&gt;has_secure_password&lt;/code&gt; by adding a &lt;code&gt;password_challenge&lt;/code&gt; accessor and a corresponding validation. The validation will verify that a &lt;code&gt;password_challenge&lt;/code&gt; matches the stored &lt;code&gt;password_digest&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;With this, implementing a password challenge becomes as straightforward as a password confirmation. This also enables reusing the same error-handling logic in both the view and the controller.&lt;/p&gt;

&lt;p&gt;For instance, instead of writing separate code in the controller, you will simply use the existing logic for password confirmation.&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;password_params&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:password&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;permit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="ss"&gt;:password_challenge&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="ss"&gt;:password&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="ss"&gt;:password_confirmation&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;with_defaults&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;password_challenge: &lt;/span&gt;&lt;span class="s2"&gt;""&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;current_user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;password_params&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="c1"&gt;# perform some work&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Saving Attachments Returning the Blob
&lt;/h3&gt;

&lt;p&gt;With Rails 7.1, when you save attachments to a record, the &lt;code&gt;attach&lt;/code&gt; method will return the attached blob or blobs. This enables the direct use of blob methods on the attachment. However, if the record fails to save, &lt;code&gt;attach&lt;/code&gt; will return &lt;code&gt;false&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Here's an example demonstrating its use:&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="vi"&gt;@user&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;create!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;name: &lt;/span&gt;&lt;span class="s2"&gt;"Josh"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;avatar&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="vi"&gt;@user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;avatar&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;attach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:avatar&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

&lt;span class="c1"&gt;# You can now directly call blob methods as follows:&lt;/span&gt;
&lt;span class="n"&gt;avatar&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;download&lt;/span&gt;
&lt;span class="n"&gt;avatar&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;url&lt;/span&gt;
&lt;span class="n"&gt;avatar&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;variant&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:thumb&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Storage of CSRF Tokens Outside of Sessions
&lt;/h3&gt;

&lt;p&gt;Rails has introduced a new configuration option to address the excessive creation and eviction of millions of sessions for just storing a CSRF token when sessions are not stored in cookies.&lt;/p&gt;

&lt;p&gt;This option allows the use of a lambda function to store the CSRF token in a custom location, thus enabling the storage of CSRF tokens outside of sessions.&lt;/p&gt;

&lt;p&gt;You can also create custom strategy classes for storing CSRF tokens.&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="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CustomStore&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="c1"&gt;# Return the token from a custom location&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;store&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;csrf_token&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="c1"&gt;# Store the token in a custom location&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;reset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="c1"&gt;# Delete the stored session token&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ApplicationController&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ActionController&lt;/span&gt;&lt;span class="ss"&gt;:x:Base&lt;/span&gt;
  &lt;span class="n"&gt;protect_from_forgery&lt;/span&gt; &lt;span class="ss"&gt;store: &lt;/span&gt;&lt;span class="no"&gt;CustomStore&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Validity Checking for PostgreSQL Indexes
&lt;/h3&gt;

&lt;p&gt;Creating indexes as shown below may lead to an invalid index:&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;add_index&lt;/span&gt; &lt;span class="ss"&gt;:account&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:active&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;algorithm: :concurrently&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With Rails 7.1, you can verify an index's validity as shown here:&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;connection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;index_exists?&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:users&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;valid: &lt;/span&gt;&lt;span class="kp"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;indexes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:users&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;select&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="ss"&gt;:valid?&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;code&gt;ActiveRecord::QueryMethods#select&lt;/code&gt; Accepts a Hash
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;ActiveRecord::QueryMethods#select&lt;/code&gt; in Rails 7.1 now accepts a hash of options. This is best demonstrated with an 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="c1"&gt;# You can now write selects like this:&lt;/span&gt;
&lt;span class="no"&gt;Post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;joins&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:comments&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;select&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="ss"&gt;posts: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="ss"&gt;id: :post_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;title: :post_title&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="ss"&gt;comments: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="ss"&gt;id: :comment_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;body: :comment_body&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# In place of this:&lt;/span&gt;
&lt;span class="no"&gt;Post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;joins&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:comments&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;select&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="s2"&gt;"posts.id as post_id, posts.title as post_title,
  comments.id as comment_id, comments.body as comment_body"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Number of Processors Match the Puma Worker Count
&lt;/h3&gt;

&lt;p&gt;By default, newly generated Rails applications will have Puma workers that are capped at the total number of physical processors on the host machine. This default setting can always be changed in the &lt;code&gt;puma.rb&lt;/code&gt; file.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;puma.rb&lt;/code&gt; file for newly-generated Rails applications will now look like the following:&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="k"&gt;if&lt;/span&gt; &lt;span class="no"&gt;ENV&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"RAILS_ENV"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"production"&lt;/span&gt;
  &lt;span class="n"&gt;worker_count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;ENV&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"WEB_CONCURRENCY"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="no"&gt;Concurrent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;physical_processor_count&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="n"&gt;workers&lt;/span&gt; &lt;span class="n"&gt;worker_count&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;worker_count&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;code&gt;preload&lt;/code&gt; and &lt;code&gt;eager_load&lt;/code&gt; Associations to Be Unscoped
&lt;/h3&gt;

&lt;p&gt;Rails 7.1 will add the ability to unscope preloaded and eager loaded associations in a manner similar to how Active Record's &lt;code&gt;includes&lt;/code&gt;, &lt;code&gt;select&lt;/code&gt;, and &lt;code&gt;joins&lt;/code&gt; methods work.&lt;/p&gt;

&lt;p&gt;This feature allows for the use of aggregate functions on &lt;code&gt;has_many&lt;/code&gt; associations previously loaded through &lt;code&gt;eager_load&lt;/code&gt; or &lt;code&gt;preload&lt;/code&gt; in existing queries.&lt;/p&gt;

&lt;p&gt;An example usage could look like:&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;query&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;unscope&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:eager_load&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:preload&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;group&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:id&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;select&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Default Dockerfiles for New Rails Applications
&lt;/h3&gt;

&lt;p&gt;Docker files are to be added as a default option for new Rails applications. The files include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Dockerfile&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;.dockerignore&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;bin/docker-entrypoint&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These files serve as a starting point for deploying an application in a production environment and are not intended for use during development. However, if desired, you can skip these files by using the &lt;code&gt;--skip-docker&lt;/code&gt; option.&lt;/p&gt;

&lt;h3&gt;
  
  
  Default Health Controller
&lt;/h3&gt;

&lt;p&gt;Rails 7.1 introduces a new endpoint for load balancers and uptime monitors. The endpoint, named &lt;code&gt;Rails::HealthController#show&lt;/code&gt;, is mapped to the "/up" path in newly generated Rails applications. This allows load balancers and uptime monitors to easily track an app's availability.&lt;/p&gt;

&lt;p&gt;Note that monitoring the database, Redis, and internal network connections to microservices that an application relies on must be managed separately.&lt;/p&gt;

&lt;h3&gt;
  
  
  New &lt;code&gt;Rails.env.local?&lt;/code&gt; for Environment Checks
&lt;/h3&gt;

&lt;p&gt;In Rails 7.1, a new &lt;code&gt;local?&lt;/code&gt; method can be used to simplify environment checks.&lt;/p&gt;

&lt;p&gt;You'll be able to replace code like:&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="k"&gt;if&lt;/span&gt; &lt;span class="no"&gt;Rails&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;development?&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="no"&gt;Rails&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;test?&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With:&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="k"&gt;if&lt;/span&gt; &lt;span class="no"&gt;Rails&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;local?&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  New &lt;code&gt;ActiveRecord::Persistence#update_attribute!&lt;/code&gt; Method
&lt;/h3&gt;

&lt;p&gt;Rails has added a new method, &lt;code&gt;ActiveRecord::Persistence#update_attribute!&lt;/code&gt;, which functions similarly to &lt;code&gt;update_attribute&lt;/code&gt; but uses &lt;code&gt;save!&lt;/code&gt; instead of &lt;code&gt;save&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Here's how you could use this new method:&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="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Apm&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&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="n"&gt;before_save&lt;/span&gt; &lt;span class="ss"&gt;:check_name&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;check_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kp"&gt;throw&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:abort&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;name&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"abort"&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="n"&gt;monitor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Apm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;name: &lt;/span&gt;&lt;span class="s2"&gt;"App Signal"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;# =&amp;gt; #&amp;lt;Apm name: "App Signal"&amp;gt;&lt;/span&gt;

&lt;span class="n"&gt;monitor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update_attribute!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"AppSignal"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;# =&amp;gt; #&amp;lt;Apm name: "AppSignal"&amp;gt;&lt;/span&gt;

&lt;span class="n"&gt;monitor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update_attribute!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"abort"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;# raises ActiveRecord::RecordNotSaved&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Templates Capable of Defining Accepted Locals
&lt;/h3&gt;

&lt;p&gt;Templates will be enhanced with the option of required arguments that have default values.&lt;/p&gt;

&lt;p&gt;Currently, templates accept any locals as keyword arguments. With 7.1, Rails templates will define specific accepted locals through a magic comment.&lt;/p&gt;

&lt;p&gt;This improvement provides greater control and customization options for template behavior and functionality.&lt;/p&gt;

&lt;p&gt;A partial in Rails could now look like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight erb"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;%# locals: (title: "Default title", comment_count: 0) %&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;h2&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;&amp;lt;%=&lt;/span&gt; &lt;span class="n"&gt;title&lt;/span&gt; &lt;span class="cp"&gt;%&amp;gt;&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/h2&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;span&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"comment-count"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;&amp;lt;%=&lt;/span&gt; &lt;span class="n"&gt;comment_count&lt;/span&gt; &lt;span class="cp"&gt;%&amp;gt;&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Instead of:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight erb"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;%&lt;/span&gt; &lt;span class="n"&gt;title&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;local_assigns&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:title&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="s2"&gt;"Default title"&lt;/span&gt; &lt;span class="cp"&gt;%&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;&amp;lt;%&lt;/span&gt; &lt;span class="n"&gt;comment_count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;local_assigns&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:comment_count&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="cp"&gt;%&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;h2&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;&amp;lt;%=&lt;/span&gt; &lt;span class="n"&gt;title&lt;/span&gt; &lt;span class="cp"&gt;%&amp;gt;&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/h2&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;span&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"comment-count"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;&amp;lt;%=&lt;/span&gt; &lt;span class="n"&gt;comment_count&lt;/span&gt; &lt;span class="cp"&gt;%&amp;gt;&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Wrapping Up
&lt;/h2&gt;

&lt;p&gt;As you can see, Rails 7.1 promises a lot of further improvements on Rails 7.&lt;/p&gt;

&lt;p&gt;For more information on features, updates, and bug fixes, check out the &lt;a href="https://edgeguides.rubyonrails.org/7_1_release_notes.html"&gt;Rails 7.1 release notes&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Happy coding!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;P.S. If you'd like to read Ruby Magic posts as soon as they get off the press, &lt;a href="https://blog.appsignal.com/ruby-magic"&gt;subscribe to our Ruby Magic newsletter and never miss a single post&lt;/a&gt;!&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>ruby</category>
      <category>rails</category>
    </item>
    <item>
      <title>A Quick Way To Locally Ignore Files From Git.</title>
      <dc:creator>Emmanuel Hayford</dc:creator>
      <pubDate>Fri, 17 May 2019 20:51:47 +0000</pubDate>
      <link>https://dev.to/siaw23/a-quick-way-to-locally-ignore-files-from-git-38n7</link>
      <guid>https://dev.to/siaw23/a-quick-way-to-locally-ignore-files-from-git-38n7</guid>
      <description>&lt;p&gt;Often times, I've found myself having to git ignore some files that I shouldn't be pushing to a repository on GitHub, so I'd do something like &lt;code&gt;git add file.rb another_file.rb&lt;/code&gt; selectively just so I can commit only the files that I want to make changes to. This is tedious, not to mention a huge waste of time. &lt;/p&gt;

&lt;p&gt;If you're familiar with Rails, sometimes you'll need to make a change to your &lt;code&gt;database.yml&lt;/code&gt; or even to your Gemfile. Changes you make to these files are only specific to you and you don't need to push this for everyone else, neither do you want to edit &lt;code&gt;.gitignore&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Here's an easy way to locally ignore your changes so you don't have to keep tracking them mistakenly or spend time to selectively track some files.&lt;/p&gt;

&lt;p&gt;I added these commands to my aliases so they're easy to access:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;alias untrack='git update-index --assume-unchanged'&lt;/code&gt; &lt;/p&gt;

&lt;p&gt;You can use this like so: &lt;code&gt;untrack database.yml&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;To undo this you'd do &lt;code&gt;track database.yml&lt;/code&gt; but only if you've added &lt;code&gt;track='git update-index --no-assume-unchanged'&lt;/code&gt; and of course &lt;code&gt;untrack&lt;/code&gt; and &lt;code&gt;track&lt;/code&gt; can be anything you choose.&lt;/p&gt;

&lt;p&gt;Happy coding!&lt;/p&gt;

</description>
      <category>productivity</category>
      <category>github</category>
    </item>
  </channel>
</rss>
