<?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: Nuttee</title>
    <description>The latest articles on DEV Community by Nuttee (@nuttapon).</description>
    <link>https://dev.to/nuttapon</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%2F316983%2F80952472-5d0b-4947-b214-46d291f78bad.jpg</url>
      <title>DEV Community: Nuttee</title>
      <link>https://dev.to/nuttapon</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/nuttapon"/>
    <language>en</language>
    <item>
      <title>Enhancing User Input Validation: Ensuring Proper Decimal Formatting with Regular Expressions</title>
      <dc:creator>Nuttee</dc:creator>
      <pubDate>Thu, 30 Mar 2023 06:20:11 +0000</pubDate>
      <link>https://dev.to/nuttapon/enhancing-user-input-validation-ensuring-proper-decimal-formatting-with-regular-expressions-4ce8</link>
      <guid>https://dev.to/nuttapon/enhancing-user-input-validation-ensuring-proper-decimal-formatting-with-regular-expressions-4ce8</guid>
      <description>&lt;p&gt;Because the user must pass a string of numbers, I must use regex to validate the input to ensure proper decimal format. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example values and results.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Input   result&lt;br&gt;
"2" ✅&lt;br&gt;
"2.3"   ✅&lt;br&gt;
"2.35"  ✅&lt;br&gt;
"2.357" ❌&lt;br&gt;
1   ❌&lt;br&gt;
1.0 ❌&lt;br&gt;
1.325   ❌&lt;br&gt;
"a" ❌&lt;br&gt;
"1."    ❌&lt;br&gt;
"1.a"   ❌&lt;br&gt;
""  ❌&lt;/p&gt;

&lt;p&gt;So the regex should be&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;~r/^\d+(\.\d{1,2})?$/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here's the breakdown of the updated pattern:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;^: Start of the string.&lt;/li&gt;
&lt;li&gt;\d+: One or more digits (0-9).&lt;/li&gt;
&lt;li&gt;(.\d{1,2})?: This part is optional, denoted by the ? at the end. If there is a decimal point ., it must be followed by 1 to 2 digits (\d{1,2}). Now, the input requires at least one digit after the decimal point.&lt;/li&gt;
&lt;li&gt;$: End of the string.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This pattern will only match valid strings with one or more digits before the decimal point and, if a decimal point is present, at least one digit after it.&lt;/p&gt;

</description>
      <category>todayilearned</category>
      <category>regex</category>
    </item>
    <item>
      <title>Handle CSRF issue when upgrade Rails from 5 to 6</title>
      <dc:creator>Nuttee</dc:creator>
      <pubDate>Fri, 09 Apr 2021 07:43:32 +0000</pubDate>
      <link>https://dev.to/nuttapon/handle-csrf-issue-when-upgrade-rails-from-5-to-6-1edp</link>
      <guid>https://dev.to/nuttapon/handle-csrf-issue-when-upgrade-rails-from-5-to-6-1edp</guid>
      <description>&lt;p&gt;I would like to share my knowledge on how to handle the issue regarding the authenticated token from &lt;code&gt;csrf_meta_tags&lt;/code&gt; that are not compatible between Rails 5 and 6 versions, which causes an error something like this;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjxwqwxhyhrcw80m0oxkz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjxwqwxhyhrcw80m0oxkz.png" alt="Screenshot 2564-04-09 at 13.20.27"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  What is &lt;code&gt;csrf_meta_tags&lt;/code&gt;?
&lt;/h4&gt;

&lt;p&gt;It's a helper method to generate meta tags "csrf-param" and "csrf-token" with the name of the cross-site request forgery protection parameter and token. It's also a view helper that embeds the authenticity token into the HTML.&lt;/p&gt;

&lt;p&gt;As you know, Rails 6 has a different algorithm for csrf token generation and its incompatibility, and to avoid showing errors to users, we decorated csrf generate function to catch the aforementioned errors and reset the session.&lt;/p&gt;

&lt;p&gt;As mentioned previously, csrf token generation between Rails 5 and 6 is incompatibility so what should do is as given below;&lt;/p&gt;

&lt;p&gt;Firstly, If you found that you got the error &lt;code&gt;ArgumentError&lt;/code&gt; with &lt;code&gt;invalid base64&lt;/code&gt; due to an incompatible csrf token generated in your application, then you could implement the code by using the &lt;code&gt;rescue&lt;/code&gt; concept.&lt;/p&gt;

&lt;p&gt;Putting in &lt;code&gt;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="n"&gt;rescue_from&lt;/span&gt; &lt;span class="no"&gt;ArgumentError&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;exception&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
  &lt;span class="k"&gt;if&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;format&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;html?&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;exception&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;message&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"invalid base64"&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;reset_session&lt;/span&gt; &lt;span class="c1"&gt;# reset your old existing session.&lt;/span&gt;
    &lt;span class="n"&gt;redirect_to&lt;/span&gt; &lt;span class="n"&gt;login_path&lt;/span&gt; &lt;span class="c1"&gt;# your login page.&lt;/span&gt;
  &lt;span class="k"&gt;else&lt;/span&gt;
    &lt;span class="k"&gt;raise&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;exception&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;Next, How about if your application needs to handle the AJAX request, then.&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;rescue_from&lt;/span&gt; &lt;span class="no"&gt;ArgumentError&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;exception&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
  &lt;span class="k"&gt;if&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;format&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;html?&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;exception&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;message&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"invalid base64"&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;reset_session&lt;/span&gt;
    &lt;span class="n"&gt;redirect_to&lt;/span&gt; &lt;span class="n"&gt;signin_path&lt;/span&gt;
  &lt;span class="k"&gt;elsif&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;xhr?&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;exception&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;message&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"invalid base64"&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;reset_session&lt;/span&gt;
    &lt;span class="n"&gt;render&lt;/span&gt; &lt;span class="ss"&gt;js: &lt;/span&gt;&lt;span class="s2"&gt;"window.location = '&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;login_path&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;'"&lt;/span&gt;
  &lt;span class="k"&gt;else&lt;/span&gt;
    &lt;span class="k"&gt;raise&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;exception&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;From the above snippet code, You can also check whether the request is &lt;code&gt;xhr?&lt;/code&gt; because the &lt;code&gt;AJAX&lt;/code&gt; request is not a request from HTML format. So it would be best if you handled this case as well.&lt;/p&gt;

&lt;p&gt;You can then redirect a user back to the login page again if a token that's generated from the &lt;code&gt;csrf_meta_tags&lt;/code&gt; incompatibility.&lt;/p&gt;

&lt;p&gt;I hope this solution may solve the special issue of &lt;code&gt;csrf_meta_tags&lt;/code&gt; that comes from upgrade Rails 5 to 6 and prevent showing the error page from the user perspective.&lt;/p&gt;

</description>
      <category>rails</category>
    </item>
    <item>
      <title>Check the connectivity of PG database</title>
      <dc:creator>Nuttee</dc:creator>
      <pubDate>Thu, 28 Jan 2021 13:35:02 +0000</pubDate>
      <link>https://dev.to/nuttapon/check-the-connectivity-of-pg-database-88b</link>
      <guid>https://dev.to/nuttapon/check-the-connectivity-of-pg-database-88b</guid>
      <description>&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fah7m5eqt5pmfs7fe046v.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fah7m5eqt5pmfs7fe046v.jpg" alt="Check the connectivity of PG database"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Basically, You want to know that the PG connection is still alive and ready for the queries used by your application.&lt;/p&gt;

&lt;p&gt;You may have your application checked for the database connectivity via &lt;code&gt;/ping&lt;/code&gt; for a health check.&lt;/p&gt;

&lt;p&gt;Which Rails provide the built-in method for checking the status as follows;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;

&lt;span class="o"&gt;&amp;gt;&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;connection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;active?&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="c1"&gt;# true&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;If &lt;code&gt;true&lt;/code&gt; means that the PG connection is still alive; otherwise, it was down.&lt;/p&gt;

&lt;p&gt;Or maybe you will try something like this instead.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;

&lt;span class="o"&gt;&amp;gt;&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;connection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'SELECT 1'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="c1"&gt;# (0.5ms)  SELECT 1&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="c1"&gt;#&amp;lt;PG::Result:0x007f8e98bf3758 status=PGRES_TUPLES_OK ntuples=1 nfields=1 cmd_tuples=1&amp;gt;&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The above sample works well, but I found that the query performance of &lt;code&gt;SELECT 1&lt;/code&gt; is worse than the empty string &lt;code&gt;''&lt;/code&gt;. It is raised on &lt;a href="http://gitlab.com/gitlab-org/gitlab/-/issues/220055" rel="noopener noreferrer"&gt;Here&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The solution is referred to &lt;a href="https://gitlab.com/gitlab-org/gitlab/-/merge_requests/49730" rel="noopener noreferrer"&gt;Use empty query instead of "SELECT 1"&lt;/a&gt; That improves database throughput to reduce the usage of CPUs in the database due to health checks.&lt;/p&gt;

&lt;p&gt;Luckily, Rails supports queries with the empty string as follows;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;

&lt;span class="o"&gt;&amp;gt;&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;connection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;''&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;0.4&lt;/span&gt;&lt;span class="n"&gt;ms&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="c1"&gt;#&amp;lt;PG::Result:0x007f8ea485e8e8 status=PGRES_EMPTY_QUERY ntuples=0 nfields=0 cmd_tuples=0&amp;gt;&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

</description>
      <category>rails</category>
      <category>postgres</category>
      <category>ruby</category>
    </item>
    <item>
      <title>10 things to guide you when you design an API</title>
      <dc:creator>Nuttee</dc:creator>
      <pubDate>Fri, 22 Jan 2021 10:27:20 +0000</pubDate>
      <link>https://dev.to/nuttapon/10-things-to-guide-you-when-you-design-an-api-5fdh</link>
      <guid>https://dev.to/nuttapon/10-things-to-guide-you-when-you-design-an-api-5fdh</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--rhpemU94--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/82vzmvlgtr5z41h2dmow.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--rhpemU94--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/82vzmvlgtr5z41h2dmow.jpg" alt="10 things to guide you when you design an API"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I want to share what I've learned to be nice to the developer when designing the new API with the best practices.&lt;/p&gt;

&lt;h4&gt;
  
  
  1. Naming resource
&lt;/h4&gt;

&lt;p&gt;My question was, Should this be singular or plural? I guess it depends on a specific resource. Mostly, we use the noun plural form of the name of a resource.&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;# To create a customer&lt;/span&gt;
&lt;span class="no"&gt;POST&lt;/span&gt; &lt;span class="sr"&gt;/customers

GET /&lt;/span&gt;&lt;span class="n"&gt;customers&lt;/span&gt; &lt;span class="c1"&gt;# To get all customers&lt;/span&gt;

&lt;span class="c1"&gt;# To update the specified customer (#id)&lt;/span&gt;
&lt;span class="no"&gt;PUT&lt;/span&gt; &lt;span class="sr"&gt;/customers/&lt;/span&gt;&lt;span class="ss"&gt;:id&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You will notice that the naming resource is plural.&lt;/p&gt;

&lt;p&gt;However, if you need to deal with the relation between resources, let's assume the customer has many orders, so you want to know all the customer's orders.&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;GET&lt;/span&gt; &lt;span class="sr"&gt;/customers/&lt;/span&gt;&lt;span class="ss"&gt;:id&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;orders&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or&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;# Allowing the customer to make a new order.&lt;/span&gt;
&lt;span class="no"&gt;POST&lt;/span&gt; &lt;span class="sr"&gt;/customers/&lt;/span&gt;&lt;span class="ss"&gt;:id&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;orders&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Unless the resource is singular, then it would be 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="c1"&gt;# To get a user profile&lt;/span&gt;
&lt;span class="no"&gt;GET&lt;/span&gt; &lt;span class="sr"&gt;/profile
GET /me&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Here's my suggestion below&lt;/em&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Try not to use an abbreviation term like &lt;code&gt;POST /cust&lt;/code&gt; (&lt;code&gt;customers&lt;/code&gt;). It's hard to forecast. Bear in mind that you should build API to be &lt;em&gt;predictable&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Try not to use a verb in URI like &lt;code&gt;POST /create-customers&lt;/code&gt; because CRUD (Create) helps us create a new record, so it's pretty redundant.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  2. Using version
&lt;/h3&gt;

&lt;p&gt;Your API can allow versioning even though you think your API framework is tiny. Often, you don't have a choice because you need to change your response structure and rename the attribute, but versioning lets you escape this situation.&lt;/p&gt;

&lt;p&gt;There are a variety of ways to apply to the version.&lt;/p&gt;

&lt;p&gt;2.1) Place it in the URI prefix.&lt;/p&gt;

&lt;p&gt;Ex:&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="sr"&gt;/v2/&lt;/span&gt;&lt;span class="n"&gt;customers&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;try not to use URI postfix to say the version like &lt;code&gt;/customers/api_version2&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;2.2) Place it in the &lt;code&gt;Accept&lt;/code&gt; Header with a custom.&lt;/p&gt;

&lt;p&gt;Ex:&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;application&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;vnd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;myapp&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="n"&gt;version&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;2.3) Place it in Query.&lt;/p&gt;

&lt;p&gt;Ex:&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="sr"&gt;/customers?api_version=2
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you add a new attribute, you don't need to build a new version of the API because you don't interrupt the business transition.&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="no"&gt;GET&lt;/span&gt; &lt;span class="sr"&gt;/v1/&lt;/span&gt;&lt;span class="n"&gt;customers&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;cust_12345&lt;/span&gt;

&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="s2"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"cust_12345"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s2"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"jone doe"&lt;/span&gt;
    &lt;span class="s2"&gt;"email"&lt;/span&gt; &lt;span class="s2"&gt;"jone@mail"&lt;/span&gt; &lt;span class="c1"&gt;# Add a new `email` attribute. You can add it directly.&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On the order hand, If you wish to rename the attribute from &lt;code&gt;name&lt;/code&gt; to &lt;code&gt;fullname&lt;/code&gt; you need to re-thinking what happenห if the person who uses your API is attempting to use the &lt;code&gt;name&lt;/code&gt; attribute's gone.&lt;/p&gt;

&lt;p&gt;Then you may decide to build a new version of &lt;code&gt;/v2&lt;/code&gt;, or you add more attributes like &lt;code&gt;fullname&lt;/code&gt; into &lt;code&gt;/v1&lt;/code&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Separation Concern
&lt;/h3&gt;

&lt;p&gt;It's a distinction between concerns that looks like in the Object-Oriented.&lt;/p&gt;

&lt;p&gt;Let's assume you have the resource name &lt;code&gt;User&lt;/code&gt;, which has several columns, such as &lt;code&gt;email&lt;/code&gt;, &lt;code&gt;password&lt;/code&gt;, &lt;code&gt;address&lt;/code&gt;, &lt;code&gt;mobile_number&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;You want the API to be able to change your password.&lt;/p&gt;

&lt;p&gt;If it looks simple and generic to modify a user like the below one.&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;PATCH&lt;/span&gt; &lt;span class="sr"&gt;/v1/use&lt;/span&gt;&lt;span class="n"&gt;rs&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="ss"&gt;:id&lt;/span&gt;

&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="ss"&gt;email: &lt;/span&gt;&lt;span class="s2"&gt;"john@mail"&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;"abcdefg"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="ss"&gt;confirmation_passowrd: &lt;/span&gt;&lt;span class="s2"&gt;"abcdefg"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After looking at the name of this endpoint, I should not recognize it immediately. And in my view, the number of comprehensive users would change.&lt;/p&gt;

&lt;p&gt;This may not be convenient for the person who uses this API so that the API can be divided into two APIs;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;One for modifying the generic user details.&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&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="sr"&gt;/v1/use&lt;/span&gt;&lt;span class="n"&gt;rs&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="ss"&gt;:id&lt;/span&gt;

&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="ss"&gt;address: &lt;/span&gt;&lt;span class="s2"&gt;"new address"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="ss"&gt;mobile_number: &lt;/span&gt;&lt;span class="s2"&gt;"new mobile number"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;One for just changing a password.&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&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="sr"&gt;/v1/use&lt;/span&gt;&lt;span class="n"&gt;rs&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="ss"&gt;:id&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;password&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;"abcdefg"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="ss"&gt;confirmation_passowrd: &lt;/span&gt;&lt;span class="s2"&gt;"abcdefg"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  4. Time format
&lt;/h3&gt;

&lt;p&gt;It should return times in UTC formatted to ISO8601. &lt;/p&gt;

&lt;p&gt;ISO8601 format: &lt;code&gt;YYYY-MM-DDTHH:MM:SSZ&lt;/code&gt;&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 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;"created_at"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2021-01-21T15:23:38Z"&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;Typically, I describe the name of the field base for the category between Date and DateTime that look like below; &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;_on&lt;/code&gt; suffixes for Date&lt;br&gt;
&lt;code&gt;_at&lt;/code&gt; suffixes for DateTime&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  5. camelCase or snake_case
&lt;/h3&gt;

&lt;p&gt;It depends on your preference, but I feel that &lt;code&gt;snake_case&lt;/code&gt; is easier to read than &lt;code&gt;camelCase&lt;/code&gt; for attribute names.&lt;/p&gt;

&lt;h3&gt;
  
  
  6. Errors
&lt;/h3&gt;

&lt;p&gt;It's similar when you have an error on the website that displays an error with a thorough explanation.&lt;/p&gt;

&lt;p&gt;As far as the API is concerned, it should also include a meaningful human-readable error message and support a unique error class for each type of error to the client.&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="no"&gt;The&lt;/span&gt; &lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="n"&gt;code&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="no"&gt;HTTP&lt;/span&gt; &lt;span class="n"&gt;should&lt;/span&gt; &lt;span class="n"&gt;be&lt;/span&gt; &lt;span class="mi"&gt;404&lt;/span&gt;

&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="ss"&gt;type: &lt;/span&gt;&lt;span class="s2"&gt;"account_not_found"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="ss"&gt;message: &lt;/span&gt;&lt;span class="s2"&gt;"The account is not existing"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  7. Using HTTP verbs and status codes correctly
&lt;/h3&gt;

&lt;p&gt;HTTP offers a wonderful mechanism to inform the API to consumers whether the request is successful or not.&lt;/p&gt;

&lt;p&gt;You may also refer to a lof of &lt;a href="https://en.wikipedia.org/wiki/List_of_HTTP_status_codes"&gt;HTTP status code&lt;/a&gt; to apply to the API.&lt;/p&gt;

&lt;h4&gt;
  
  
  HTTP verbs
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;GET&lt;/code&gt; to retrieve a resource.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;POST&lt;/code&gt; to create a resource (Sometime, you might use it without creating any record)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;PATCH&lt;/code&gt; to modify the partial resource&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;PUT&lt;/code&gt; to replace a resource or collect of a resource.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;DELETE&lt;/code&gt; to delete a resource.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  HTTP status codes
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;2xx Success&lt;/code&gt; Everything's going smoothly.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;200 OK&lt;/code&gt; It's a successful response that everything goes well.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;201 Created&lt;/code&gt; Most of the time, it's used to &lt;code&gt;POST&lt;/code&gt; that results in a creation.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;204 No content&lt;/code&gt; It is also used for &lt;code&gt;DELETE&lt;/code&gt;, which resource has been removed and the returned body is null.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;400 Bad Request&lt;/code&gt; The request is invalid/unacceptable, or an appropriate parameter is lacking.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;401 Unauthorized&lt;/code&gt; Mostly, It's used for invalid authentication.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;404 NotFound&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;429 Too many requests&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;5xx&lt;/code&gt; Something went wrong with us.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  8. Pagination
&lt;/h3&gt;

&lt;p&gt;You might fail to worry about how large the data is since it returns a lot of records at once, so you should have a way to limit the number of records per request.&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;GET&lt;/span&gt; &lt;span class="sr"&gt;/v1/&lt;/span&gt;&lt;span class="n"&gt;customers?page&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;per_page&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;30&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  9. Rate limiting
&lt;/h3&gt;

&lt;p&gt;You might be surprised if someone attempts to spam your API unreasonably. So you may start implementing a rate-limit early.&lt;/p&gt;

&lt;p&gt;You may use &lt;a href="https://redis.io/"&gt;Redis&lt;/a&gt; with EXPIRE feature to limit the specified person's request.&lt;/p&gt;

&lt;h3&gt;
  
  
  10. Good Documentation
&lt;/h3&gt;

&lt;p&gt;You should have good API documentation that should be reliable and simple for the developer to understand. I think all developers (including me) enjoy good examples; not only do they have code samples like &lt;code&gt;curl --&lt;/code&gt; but they can cover all test cases like Postman Examples or Swagger Examples.&lt;/p&gt;

&lt;p&gt;See &lt;a href="https://learning.postman.com/docs/sending-requests/examples/"&gt;Postman Examples&lt;/a&gt; and &lt;a href="https://swagger.io/docs/specification/adding-examples/"&gt;Swagger Examples&lt;/a&gt; for more details.&lt;/p&gt;

</description>
      <category>todayilearned</category>
      <category>api</category>
    </item>
    <item>
      <title>How  to know the analyzer of Elasticsearch tokenize</title>
      <dc:creator>Nuttee</dc:creator>
      <pubDate>Sat, 16 Jan 2021 10:49:16 +0000</pubDate>
      <link>https://dev.to/nuttapon/how-to-know-the-analyzer-of-elasticsearch-tokenize-5g8e</link>
      <guid>https://dev.to/nuttapon/how-to-know-the-analyzer-of-elasticsearch-tokenize-5g8e</guid>
      <description>&lt;p&gt;Sometimes, you may be curious about what a given analyzer is tokening your queries to your code that you're working on it.&lt;/p&gt;

&lt;p&gt;For example. Let's say your index's mapping look like as given below;&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;"mappings"&lt;/span&gt;&lt;span class="p"&gt;:&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;span class="nl"&gt;"user"&lt;/span&gt;&lt;span class="p"&gt;:&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;span class="nl"&gt;"properties"&lt;/span&gt;&lt;span class="p"&gt;:&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;span class="nl"&gt;"fullname"&lt;/span&gt;&lt;span class="p"&gt;:&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;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"text"&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;span class="nl"&gt;"email"&lt;/span&gt;&lt;span class="p"&gt;:&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;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"text"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"analyzer"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"keyword_ngram_analyzer"&lt;/span&gt;&lt;span class="p"&gt;,&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;span class="p"&gt;}&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;span class="p"&gt;}&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;Let's check one by one.&lt;/p&gt;

&lt;p&gt;First, &lt;code&gt;properties&lt;/code&gt; uses the default analyzer because there is no specified analyzer. See &lt;a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/analysis-standard-analyzer.html"&gt;Elasticsearch documentation&lt;/a&gt; for more details)&lt;/p&gt;

&lt;p&gt;So we're trying to debug by using &lt;code&gt;analyze&lt;/code&gt; with the query is &lt;code&gt;Scott Leblanc&lt;/code&gt; then.&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="err"&gt;POST&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;/_analyze&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;span class="nl"&gt;"analyzer"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"standard"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"text"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Scott Leblanc"&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;Output will be&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;"tokens"&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;span class="p"&gt;[&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;span class="nl"&gt;"token"&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;span class="s2"&gt;"scott"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"start_offset"&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;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"end_offset"&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;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"type"&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;span class="s2"&gt;"&amp;lt;ALPHANUM&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"position"&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;span class="mi"&gt;0&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;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"token"&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;span class="s2"&gt;"leblanc"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"start_offset"&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;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"end_offset"&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;span class="mi"&gt;13&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"type"&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;span class="s2"&gt;"&amp;lt;ALPHANUM&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"position"&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;span class="mi"&gt;1&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;span class="p"&gt;]&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;Second, What about &lt;code&gt;keyword_ngram_analyzer&lt;/code&gt; that defined to &lt;code&gt;email&lt;/code&gt;?&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="err"&gt;POST&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;/_analyze&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;span class="nl"&gt;"analyzer"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"keyword_ngram_analyzer"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"text"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"joh@m.co"&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;Output will be&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;"tokens"&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;span class="p"&gt;[&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;span class="nl"&gt;"token"&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;span class="s2"&gt;"joh"&lt;/span&gt;&lt;span class="p"&gt;,&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;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"token"&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;span class="s2"&gt;"joh@"&lt;/span&gt;&lt;span class="p"&gt;,&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;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"token"&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;span class="s2"&gt;"joh@m"&lt;/span&gt;&lt;span class="p"&gt;,&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;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"token"&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;span class="s2"&gt;"joh@m."&lt;/span&gt;&lt;span class="p"&gt;,&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;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"token"&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;span class="s2"&gt;"joh@m.c"&lt;/span&gt;&lt;span class="p"&gt;,&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;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"token"&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;span class="s2"&gt;"joh@m.co"&lt;/span&gt;&lt;span class="p"&gt;,&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;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"token"&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;span class="s2"&gt;"oh@"&lt;/span&gt;&lt;span class="p"&gt;,&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;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"token"&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;span class="s2"&gt;"oh@m"&lt;/span&gt;&lt;span class="p"&gt;,&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;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"token"&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;span class="s2"&gt;"oh@m."&lt;/span&gt;&lt;span class="p"&gt;,&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;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"token"&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;span class="s2"&gt;"oh@m.c"&lt;/span&gt;&lt;span class="p"&gt;,&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;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"token"&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;span class="s2"&gt;"oh@m.co"&lt;/span&gt;&lt;span class="p"&gt;,&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;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"token"&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;span class="s2"&gt;"h@m"&lt;/span&gt;&lt;span class="p"&gt;,&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;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"token"&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;span class="s2"&gt;"h@m."&lt;/span&gt;&lt;span class="p"&gt;,&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;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"token"&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;span class="s2"&gt;"h@m.c"&lt;/span&gt;&lt;span class="p"&gt;,&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;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"token"&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;span class="s2"&gt;"h@m.co"&lt;/span&gt;&lt;span class="p"&gt;,&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;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"token"&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;span class="s2"&gt;"@m."&lt;/span&gt;&lt;span class="p"&gt;,&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;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"token"&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;span class="s2"&gt;"@m.c"&lt;/span&gt;&lt;span class="p"&gt;,&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;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"token"&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;span class="s2"&gt;"@m.co"&lt;/span&gt;&lt;span class="p"&gt;,&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;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"token"&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;span class="s2"&gt;"m.c"&lt;/span&gt;&lt;span class="p"&gt;,&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;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"token"&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;span class="s2"&gt;"m.co"&lt;/span&gt;&lt;span class="p"&gt;,&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;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"token"&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;span class="s2"&gt;".co"&lt;/span&gt;&lt;span class="p"&gt;,&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;span class="p"&gt;]&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;Above the sample, you can query/filter by entering these tokens such as &lt;code&gt;joh@&lt;/code&gt; or &lt;code&gt;@m.co&lt;/code&gt; or referring to resulting tokens.&lt;/p&gt;

&lt;p&gt;Conclusion&lt;/p&gt;

&lt;p&gt;If you want to know, each analyzer of Elasticsearch tokenizes your queries. You can use Analyze API to analyze it.&lt;/p&gt;

&lt;p&gt;See more &lt;a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/indices-analyze.html#indices-analyze"&gt;Analyze API&lt;/a&gt; for more details.&lt;/p&gt;

</description>
      <category>elasticsearch</category>
    </item>
    <item>
      <title>Integrate CircleCI on Bitbucket with Ruby on Rails project</title>
      <dc:creator>Nuttee</dc:creator>
      <pubDate>Wed, 13 Jan 2021 14:22:19 +0000</pubDate>
      <link>https://dev.to/nuttapon/integrate-circleci-on-bitbucket-with-ruby-on-rails-project-2j3f</link>
      <guid>https://dev.to/nuttapon/integrate-circleci-on-bitbucket-with-ruby-on-rails-project-2j3f</guid>
      <description>&lt;p&gt;First of all, I want to share my experience integrating CircleCI to the Bitbucket Cloud repository with a Rails project using Postgres as a Database to run automatically test the project.&lt;/p&gt;

&lt;p&gt;You need to create and commit a &lt;code&gt;.bitbucket-pipelines.yml&lt;/code&gt; in your project’s root directory.&lt;/p&gt;

&lt;p&gt;Once you push a commit to Bitbucket, CircleCI will automatically build and test the project.&lt;/p&gt;

&lt;p&gt;Below example is a sample build without Postgres;&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="ss"&gt;image: &lt;/span&gt;&lt;span class="n"&gt;ruby&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mf"&gt;2.6&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;

&lt;span class="ss"&gt;pipelines:
  default:
    &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="ss"&gt;parallel:
      &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="ss"&gt;step:
          name: &lt;/span&gt;&lt;span class="no"&gt;Test&lt;/span&gt;
          &lt;span class="ss"&gt;script:
            &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;bundle&lt;/span&gt; &lt;span class="n"&gt;install&lt;/span&gt;
            &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="no"&gt;RAILS_ENV&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;test&lt;/span&gt; &lt;span class="n"&gt;bundle&lt;/span&gt; &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="n"&gt;rake&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="ss"&gt;:setup&lt;/span&gt;
            &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="no"&gt;RAILS_ENV&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;test&lt;/span&gt; &lt;span class="n"&gt;bundle&lt;/span&gt; &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="n"&gt;rake&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="ss"&gt;:test:prepare&lt;/span&gt;
            &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="no"&gt;RAILS_ENV&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;test&lt;/span&gt; &lt;span class="n"&gt;bundle&lt;/span&gt; &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="n"&gt;rake&lt;/span&gt; &lt;span class="nb"&gt;test&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;From the example built above, I'm using Ruby version &lt;code&gt;2.6.6&lt;/code&gt; you can adjust what version you're using instead. It's enough to let CircleCI run the test automatically.&lt;/p&gt;

&lt;p&gt;What if you use Postgres as a Database?&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="ss"&gt;image: &lt;/span&gt;&lt;span class="n"&gt;ruby&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mf"&gt;2.6&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;

&lt;span class="ss"&gt;pipelines:
  default:
    &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="ss"&gt;parallel:
      &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="ss"&gt;step:
          name: &lt;/span&gt;&lt;span class="no"&gt;Test&lt;/span&gt;
          &lt;span class="ss"&gt;script:
            &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;apt&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt; &lt;span class="n"&gt;update&lt;/span&gt;
            &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;apt&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt; &lt;span class="n"&gt;install&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="n"&gt;build&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;essential&lt;/span&gt; &lt;span class="n"&gt;libpq&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;dev&lt;/span&gt; &lt;span class="n"&gt;nodejs&lt;/span&gt;
            &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;export&lt;/span&gt; &lt;span class="no"&gt;DATABASE_URL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;postgresql&lt;/span&gt;&lt;span class="ss"&gt;:/&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;test_user&lt;/span&gt;&lt;span class="ss"&gt;:test_user_password&lt;/span&gt;&lt;span class="vi"&gt;@localhost&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;pipelines&lt;/span&gt;
            &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;bundle&lt;/span&gt; &lt;span class="n"&gt;install&lt;/span&gt;
            &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="no"&gt;RAILS_ENV&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;test&lt;/span&gt; &lt;span class="n"&gt;bundle&lt;/span&gt; &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="n"&gt;rake&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="ss"&gt;:setup&lt;/span&gt;
            &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="no"&gt;RAILS_ENV&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;test&lt;/span&gt; &lt;span class="n"&gt;bundle&lt;/span&gt; &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="n"&gt;rake&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="ss"&gt;:test:prepare&lt;/span&gt;
            &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="no"&gt;RAILS_ENV&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;test&lt;/span&gt; &lt;span class="n"&gt;bundle&lt;/span&gt; &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="n"&gt;rake&lt;/span&gt; &lt;span class="nb"&gt;test&lt;/span&gt;
          &lt;span class="ss"&gt;services:
            &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;postgres&lt;/span&gt;

&lt;span class="ss"&gt;definitions:
  services:
    postgres:
      image: &lt;/span&gt;&lt;span class="n"&gt;postgres&lt;/span&gt;
      &lt;span class="ss"&gt;environment:
        &lt;/span&gt;&lt;span class="no"&gt;POSTGRES_DB&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;pipelines&lt;/span&gt;
        &lt;span class="no"&gt;POSTGRES_USER&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;test_user&lt;/span&gt;
        &lt;span class="no"&gt;POSTGRES_PASSWORD&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;test_user_password&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Above 2 samples, &lt;code&gt;bundle install&lt;/code&gt; is still running without being cached every time it takes a bit of time to set it up.&lt;/p&gt;

&lt;p&gt;By having a cache, we would save the building time.&lt;/p&gt;

&lt;p&gt;Define &lt;code&gt;bundler&lt;/code&gt; into &lt;code&gt;caches&lt;/code&gt; step.&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="o"&gt;-&lt;/span&gt; &lt;span class="ss"&gt;step:
    caches:
      &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;bundler&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Change &lt;code&gt;bundle install&lt;/code&gt; command with a specific path.&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="ss"&gt;script:
  &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;bundle&lt;/span&gt; &lt;span class="n"&gt;install&lt;/span&gt; &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="n"&gt;vendor&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;bundle&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Make a new definition looks 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="ss"&gt;definitions:
  caches:
    bundler: &lt;/span&gt;&lt;span class="n"&gt;vendor&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;bundle&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Example full file pipeline.&lt;/p&gt;

&lt;p&gt;By the way, some of the other dependencies that might happen based on your project.&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="ss"&gt;image: &lt;/span&gt;&lt;span class="n"&gt;ruby&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mf"&gt;2.6&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;

&lt;span class="ss"&gt;pipelines:
  default:
    &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="ss"&gt;parallel:
      &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="ss"&gt;step:
          caches:
            &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;bundler&lt;/span&gt;
          &lt;span class="ss"&gt;name: &lt;/span&gt;&lt;span class="no"&gt;Test&lt;/span&gt;
          &lt;span class="ss"&gt;script:
            &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;apt&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt; &lt;span class="n"&gt;update&lt;/span&gt;
            &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;apt&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt; &lt;span class="n"&gt;install&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="n"&gt;build&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;essential&lt;/span&gt; &lt;span class="n"&gt;libpq&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;dev&lt;/span&gt; &lt;span class="n"&gt;nodejs&lt;/span&gt;
            &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;export&lt;/span&gt; &lt;span class="no"&gt;DATABASE_URL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;postgresql&lt;/span&gt;&lt;span class="ss"&gt;:/&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;test_user&lt;/span&gt;&lt;span class="ss"&gt;:test_user_password&lt;/span&gt;&lt;span class="vi"&gt;@localhost&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;pipelines&lt;/span&gt;
            &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;bundle&lt;/span&gt; &lt;span class="n"&gt;install&lt;/span&gt; &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="n"&gt;vendor&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;bundle&lt;/span&gt;
            &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="no"&gt;RAILS_ENV&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;test&lt;/span&gt; &lt;span class="n"&gt;bundle&lt;/span&gt; &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="n"&gt;rake&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="ss"&gt;:setup&lt;/span&gt;
            &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="no"&gt;RAILS_ENV&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;test&lt;/span&gt; &lt;span class="n"&gt;bundle&lt;/span&gt; &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="n"&gt;rake&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="ss"&gt;:test:prepare&lt;/span&gt;
            &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="no"&gt;RAILS_ENV&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;test&lt;/span&gt; &lt;span class="n"&gt;bundle&lt;/span&gt; &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="n"&gt;rake&lt;/span&gt; &lt;span class="nb"&gt;test&lt;/span&gt;
          &lt;span class="ss"&gt;services:
            &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;postgres&lt;/span&gt;

&lt;span class="ss"&gt;definitions:
  caches:
    bundler: &lt;/span&gt;&lt;span class="n"&gt;vendor&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;bundle&lt;/span&gt;
  &lt;span class="ss"&gt;services:
    postgres:
      image: &lt;/span&gt;&lt;span class="n"&gt;postgres&lt;/span&gt;
      &lt;span class="ss"&gt;environment:
        &lt;/span&gt;&lt;span class="no"&gt;POSTGRES_DB&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;pipelines&lt;/span&gt;
        &lt;span class="no"&gt;POSTGRES_USER&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;test_user&lt;/span&gt;
        &lt;span class="no"&gt;POSTGRES_PASSWORD&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;test_user_password&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>rails</category>
    </item>
    <item>
      <title>How to access a Hash either string or symbol keys</title>
      <dc:creator>Nuttee</dc:creator>
      <pubDate>Wed, 06 Jan 2021 13:18:01 +0000</pubDate>
      <link>https://dev.to/nuttapon/how-to-access-a-hash-either-string-or-symbol-keys-14ka</link>
      <guid>https://dev.to/nuttapon/how-to-access-a-hash-either-string-or-symbol-keys-14ka</guid>
      <description>&lt;p&gt;Sometimes, You may have stumbled across these cases why you got &lt;code&gt;nil&lt;/code&gt; value from accessing a hash.&lt;/p&gt;

&lt;p&gt;For example&lt;/p&gt;

&lt;p&gt;First case,&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;fruit&lt;/span&gt; &lt;span class="o"&gt;=&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;"Grape"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;color: &lt;/span&gt;&lt;span class="s2"&gt;"purple"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then&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;fruit&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;"Grape"&lt;/span&gt;

&lt;span class="n"&gt;fruit&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"name"&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Second case,&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;fruit&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;"Grape"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"color"&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;"purple"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then&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;fruit&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kp"&gt;nil&lt;/span&gt;

&lt;span class="n"&gt;fruit&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;"Grape"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These two examples show that you need to know the hash key's structure, whether it's a string or a symbol key, to access it correctly.&lt;/p&gt;

&lt;p&gt;Or you can convert it by using &lt;code&gt;symbolize_keys()&lt;/code&gt; (returns a new hash with all keys converted to be symbols) and you can access it by using the symbol key.&lt;/p&gt;

&lt;h3&gt;
  
  
  Would it be better if we can access a hash either string or symbol keys?
&lt;/h3&gt;

&lt;p&gt;Using &lt;code&gt;with_indifferent_access()&lt;/code&gt; &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="n"&gt;fruit&lt;/span&gt; &lt;span class="o"&gt;=&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;"Grape"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;color: &lt;/span&gt;&lt;span class="s2"&gt;"purple"&lt;/span&gt; &lt;span class="p"&gt;}.&lt;/span&gt;&lt;span class="nf"&gt;with_indifferent_access&lt;/span&gt;

&lt;span class="n"&gt;fruit&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;"Grape"&lt;/span&gt;

&lt;span class="n"&gt;fruit&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;"Grape"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It's pretty convenient because it ensures you get the value of the hash.&lt;/p&gt;

&lt;p&gt;Reference: &lt;a href="https://api.rubyonrails.org/classes/ActiveSupport/HashWithIndifferentAccess.html"&gt;https://api.rubyonrails.org/classes/ActiveSupport/HashWithIndifferentAccess.html&lt;/a&gt;&lt;/p&gt;

</description>
      <category>rails</category>
      <category>ruby</category>
    </item>
    <item>
      <title>How to install bundler for Ruby &lt; 2.3</title>
      <dc:creator>Nuttee</dc:creator>
      <pubDate>Mon, 04 Jan 2021 08:16:49 +0000</pubDate>
      <link>https://dev.to/nuttapon/how-to-install-bundler-for-ruby-2-3-52da</link>
      <guid>https://dev.to/nuttapon/how-to-install-bundler-for-ruby-2-3-52da</guid>
      <description>&lt;p&gt;You may get the following error when you attempt to install Bundler 2 with Ruby version &amp;lt; 2.3&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ERROR:  Error installing bundler:
    bundler requires Ruby version &amp;gt;= 2.3.0.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In order to address this, we must update the ruby version of your project or set up the last supported Bundler version for Ruby &amp;lt; 2.3&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;gem install bundler -v '~&amp;gt;1'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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