<?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>Forem: Main Street</title>
    <description>The latest articles on Forem by Main Street (@mainstreet).</description>
    <link>https://forem.com/mainstreet</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%2Forganization%2Fprofile_image%2F2633%2F22308430-15a4-4e8d-9bde-320994d23333.jpg</url>
      <title>Forem: Main Street</title>
      <link>https://forem.com/mainstreet</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/mainstreet"/>
    <language>en</language>
    <item>
      <title>Using Ruby Procs to improve readability</title>
      <dc:creator>Manuel Ortega</dc:creator>
      <pubDate>Sat, 24 Apr 2021 12:12:52 +0000</pubDate>
      <link>https://forem.com/mainstreet/using-ruby-procs-to-improve-readability-5bfg</link>
      <guid>https://forem.com/mainstreet/using-ruby-procs-to-improve-readability-5bfg</guid>
      <description>&lt;p&gt;We always try to avoid adding comments to our code. There may be some exceptions but ideally the code itself should clearly express what it is doing.&lt;/p&gt;

&lt;p&gt;In this pursuit of code readability and expressiveness Procs are helpful in many scenarios. For example when we are dealing with a complex logic within a block we want to pass to a method (&lt;code&gt;map&lt;/code&gt;, &lt;code&gt;select&lt;/code&gt;, etc) from the &lt;a href="http://ruby-doc.org/core-2.2.3/Enumerable.html"&gt;Enumerable&lt;/a&gt; module.&lt;/p&gt;

&lt;h3&gt;
  
  
  Before
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&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;error_messages&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;errors&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;      
  &lt;span class="n"&gt;errors&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;message&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="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;strip&lt;/span&gt; &lt;span class="k"&gt;rescue&lt;/span&gt; &lt;span class="s2"&gt;""&lt;/span&gt; &lt;span class="p"&gt;}.&lt;/span&gt;&lt;span class="nf"&gt;uniq&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&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="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's focus on the block &lt;code&gt;{ |e| e.message.split(":")[3].strip rescue "" }&lt;/code&gt; we are passing to the &lt;code&gt;map&lt;/code&gt; method. It is not extremely complex but still getting your head around it could take a while especially if it is the first time to face this code or functionally within an application.&lt;/p&gt;

&lt;h3&gt;
  
  
  After
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&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;error_messages&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;errors&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;extract_readable_message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;proc&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;message&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="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;strip&lt;/span&gt; &lt;span class="k"&gt;rescue&lt;/span&gt; &lt;span class="s2"&gt;""&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="n"&gt;errors&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;extract_readable_message&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;uniq&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&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="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This second version adding a Proc didn't change what the code does, but now anyone coming to these lines of code will easily understand not only what the code does but also why it does it.&lt;/p&gt;

&lt;p&gt;What you think? Do you find this is worth it? Have you ever add a Proc as a way to improve readability?&lt;/p&gt;

</description>
      <category>ruby</category>
      <category>rails</category>
      <category>5days5blogposts</category>
    </item>
    <item>
      <title>The "What" and "Why" or How We are hiding those ugly IF's in our Service Objects</title>
      <dc:creator>Manuel Ortega</dc:creator>
      <pubDate>Tue, 20 Apr 2021 10:32:24 +0000</pubDate>
      <link>https://forem.com/mainstreet/service-objects-the-what-and-why-50gg</link>
      <guid>https://forem.com/mainstreet/service-objects-the-what-and-why-50gg</guid>
      <description>&lt;p&gt;We use &lt;a href="https://dev.to/joker666/ruby-on-rails-pattern-service-objects-b19"&gt;Service Objects&lt;/a&gt; to encapsulate and organize business domain logic in our Rails applications. But how do we organize the "What" and "Why" within a single Service Object?&lt;/p&gt;

&lt;p&gt;The "What" and "Why"? What do I mean? I hope the following code bites makes clear my point here.&lt;/p&gt;

&lt;h3&gt;
  
  
  Before
&lt;/h3&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;Customers::CreateService&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ApplicationService&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;initialize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;customer_params&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="vi"&gt;@customer_params&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;customer_params&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;perform&lt;/span&gt;
    &lt;span class="vi"&gt;@customer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Customer&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="vi"&gt;@assignment_params&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="vi"&gt;@customer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;save&lt;/span&gt;
      &lt;span class="n"&gt;sync_customer&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="no"&gt;TestApp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;config&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:sync_enabled&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;     
      &lt;span class="n"&gt;create_qualified_notification&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="vi"&gt;@customer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status_qualified?&lt;/span&gt;
      &lt;span class="n"&gt;create_twilio_proxy_session&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="no"&gt;TestApp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;config&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:proxy_enabled&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
      &lt;span class="no"&gt;Result&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="vi"&gt;@customer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kp"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;
      &lt;span class="no"&gt;Result&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="vi"&gt;@customer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kp"&gt;false&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;span class="kp"&gt;private&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;sync_customer&lt;/span&gt;
    &lt;span class="o"&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;create_qualified_notification&lt;/span&gt;
    &lt;span class="o"&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;create_twilio_proxy_session&lt;/span&gt;
    &lt;span class="o"&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;As you can see in this before version of our Service Object we are mixing the "What" and "Why" within the &lt;code&gt;perform&lt;/code&gt; public method. We are putting what the perform method does when a customer is created, for example, it creates a qualified notification, but we are also putting the "Why" here, it is, we are creating the qualified notification because the customer is being created with &lt;code&gt;qualified&lt;/code&gt; status.&lt;/p&gt;

&lt;p&gt;The "What" is what the Service Object does and the "Why" is the control-flow logic.&lt;/p&gt;

&lt;h3&gt;
  
  
  After
&lt;/h3&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;Customers::CreateService&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ApplicationService&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;initialize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;customer_params&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="vi"&gt;@customer_params&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;customer_params&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;perform&lt;/span&gt;
    &lt;span class="vi"&gt;@customer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Customer&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="vi"&gt;@assignment_params&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="vi"&gt;@customer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;save&lt;/span&gt;
      &lt;span class="n"&gt;sync_customer&lt;/span&gt;     
      &lt;span class="n"&gt;create_qualified_notification&lt;/span&gt;
      &lt;span class="n"&gt;create_twilio_proxy_session&lt;/span&gt;
      &lt;span class="no"&gt;Result&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="vi"&gt;@customer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kp"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;
      &lt;span class="no"&gt;Result&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="vi"&gt;@customer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kp"&gt;false&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;span class="kp"&gt;private&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;sync_customer&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="no"&gt;TestApp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;config&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:sync_enabled&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
      &lt;span class="o"&gt;...&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;def&lt;/span&gt; &lt;span class="nf"&gt;create_qualified_notification&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="vi"&gt;@customer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status_qualified?&lt;/span&gt;
      &lt;span class="o"&gt;...&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;def&lt;/span&gt; &lt;span class="nf"&gt;create_twilio_proxy_session&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="no"&gt;TestApp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;config&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:proxy_enabled&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
      &lt;span class="o"&gt;...&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;As you can see in the after version we are moving the control-flow logic, the "Why", to the private methods and keeping only the "What" in the &lt;code&gt;perform&lt;/code&gt; public 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="n"&gt;sync_customer&lt;/span&gt;     
 &lt;span class="n"&gt;create_qualified_notification&lt;/span&gt;
 &lt;span class="n"&gt;create_twilio_proxy_session&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The argument for this is that anyone from our team or future me can read the &lt;code&gt;perform&lt;/code&gt; method and reason about what it is trying to accomplish faster because it's just the "What".&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Much of the credit goes to &lt;a href="https://github.com/jeanpaulsio"&gt;JP&lt;/a&gt; for recommending this "What" and "Why" separation in a code review&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ruby</category>
      <category>rails</category>
      <category>5days5blogposts</category>
    </item>
    <item>
      <title>How to name Rails Concerns? </title>
      <dc:creator>Manuel Ortega</dc:creator>
      <pubDate>Thu, 15 Apr 2021 18:28:57 +0000</pubDate>
      <link>https://forem.com/mainstreet/how-to-name-rails-concerns-3m86</link>
      <guid>https://forem.com/mainstreet/how-to-name-rails-concerns-3m86</guid>
      <description>&lt;p&gt;&lt;a href="https://api.rubyonrails.org/v6.1.3/classes/ActiveSupport/Concern.html"&gt;Rails concerns&lt;/a&gt; are a handy technique to organize code / logic within your classes. But how do we name these Rails Concerns?&lt;/p&gt;

&lt;p&gt;We usually follow these two conventions:&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;able&lt;/strong&gt; suffix
&lt;/h3&gt;

&lt;p&gt;We suffix Concerns with &lt;code&gt;able&lt;/code&gt; when the object we are including the concern to is able to act or behave as the concern describes.&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;module&lt;/span&gt; &lt;span class="nn"&gt;Avatarable&lt;/span&gt;
  &lt;span class="kp"&gt;extend&lt;/span&gt; &lt;span class="no"&gt;ActiveSupport&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Concern&lt;/span&gt;
  &lt;span class="o"&gt;...&lt;/span&gt;

  &lt;span class="n"&gt;included&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="o"&gt;...&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="o"&gt;...&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 Concern above tells us that the class we include this concern to is able to act / behave as we would expect from an avatar.&lt;/p&gt;

&lt;p&gt;We also follow this convention when we can execute the action that the concern describes to the object we are including the concern 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="k"&gt;module&lt;/span&gt; &lt;span class="nn"&gt;Subscribable&lt;/span&gt;
  &lt;span class="kp"&gt;extend&lt;/span&gt; &lt;span class="no"&gt;ActiveSupport&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Concern&lt;/span&gt;
  &lt;span class="o"&gt;...&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this case we are making clear we are able to subscribe to objects from the class we include this &lt;code&gt;Subscribable&lt;/code&gt; Concern to.  &lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;has&lt;/strong&gt; prefix
&lt;/h3&gt;

&lt;p&gt;We prefix our Concerns with &lt;code&gt;has&lt;/code&gt; when the logic we are trying to group within our Concern is not describing a behavior but a &lt;code&gt;has&lt;/code&gt; relation between the class where we will include the Concern to and a second entity. In the following scenario we may have a &lt;code&gt;User&lt;/code&gt; entity that has mentions within a blogging platform. At some point we may come up with a Concern that groups all the logic tied to a user having mentions.&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;module&lt;/span&gt; &lt;span class="nn"&gt;HasMentions&lt;/span&gt;
  &lt;span class="kp"&gt;extend&lt;/span&gt; &lt;span class="no"&gt;ActiveSupport&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Concern&lt;/span&gt;

  &lt;span class="n"&gt;included&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="o"&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;In case none of the conventions described above makes sense within a specific scenario we don't follow them and goes with whatever better describes what the concern groups together.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How do you name your Rails Concerns? What conventions do you follow?&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>rails</category>
      <category>ruby</category>
      <category>5days5blogposts</category>
    </item>
    <item>
      <title>Great Ruby Gems Most People Haven’t Heard About</title>
      <dc:creator>Ronak Bhatt</dc:creator>
      <pubDate>Fri, 01 Jan 2021 06:39:34 +0000</pubDate>
      <link>https://forem.com/mainstreet/great-ruby-gems-most-people-haven-t-heard-about-56jh</link>
      <guid>https://forem.com/mainstreet/great-ruby-gems-most-people-haven-t-heard-about-56jh</guid>
      <description>&lt;p&gt;What are the best Ruby gems that you can use in your Rails projects?&lt;/p&gt;

&lt;p&gt;That’s what you’ll discover in this article!&lt;/p&gt;

&lt;p&gt;I’m going to give you 7 gems, but not the same old gems that you’ve seen a million times, I’m going to be sharing with you some gems that are very helpful, but little-known.&lt;/p&gt;

&lt;p&gt;But before we do that…&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;A warning.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I’ve seen developers that pull in a gem for just about everything.&lt;/p&gt;

&lt;p&gt;If it remotely sounds like it could be helpful.&lt;/p&gt;

&lt;p&gt;Without taking a moment to think if that gem solves the problem they have if it’s the best option, well-maintained &amp;amp; documented, etc.&lt;/p&gt;

&lt;p&gt;That’s a mistake.&lt;/p&gt;




&lt;h3&gt;
  
  
  &lt;strong&gt;1. Find Dead Routes To Keep Your Code Clean&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;As your Rails application grows, you’ll accumulate more &amp;amp; more routes.&lt;/p&gt;

&lt;p&gt;You’ll change code &amp;amp; some of these routes become stale.&lt;/p&gt;

&lt;p&gt;No longer needed…&lt;/p&gt;

&lt;p&gt;But they’ll stay there, in your &lt;code&gt;config/routes.rb&lt;/code&gt;, making it harder to manage.&lt;/p&gt;

&lt;p&gt;How do you find which routes to delete?&lt;/p&gt;

&lt;p&gt;There is a gem called &lt;code&gt;traceroute&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;It loads your routes &amp;amp; compares them to the controller actions you’ve defined.&lt;/p&gt;

&lt;p&gt;But right now it has two limitations:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It doesn’t work with Rails 6&lt;/li&gt;
&lt;li&gt;It doesn’t detect implicit controller actions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can find it &lt;a href="https://github.com/amatsuda/traceroute" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;




&lt;h3&gt;
  
  
  &lt;strong&gt;2. Make Your Migrations Safer So You Can Avoid Problems Rails migrations can cause a lot of problems if done wrong.&lt;/strong&gt;
&lt;/h3&gt;

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

&lt;p&gt;Removing a column can cause problems because Rails has a cache of columns, and running a migration doesn’t reset this cache.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Another example:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If you add an index &amp;amp; you’re running PostgreSQL the whole table gets locked until the operation is complete.&lt;/p&gt;

&lt;p&gt;Not good for your users.&lt;/p&gt;

&lt;p&gt;Your application won’t be able to respond to requests that need to work with a locked table.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The good news?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You don’t have to remember all of these things.&lt;/p&gt;

&lt;p&gt;With the help of the &lt;code&gt;strong_migrations&lt;/code&gt; gem, you’ll know when you have one of these unsafe migrations before it makes it into production.&lt;/p&gt;

&lt;p&gt;You can find it &lt;a href="https://github.com/ankane/strong_migrations" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;




&lt;h3&gt;
  
  
  &lt;strong&gt;3. Find Your Slow Tests &amp;amp; Make Them Faster&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Slow tests are no fun.&lt;/p&gt;

&lt;p&gt;But there are tools to help you find why your &lt;a href="https://www.rubyguides.com/2018/07/rspec-tutorial/" rel="noopener noreferrer"&gt;tests&lt;/a&gt; are slow so you can fix them!&lt;/p&gt;

&lt;p&gt;One of these tools is the combination of test-prof + ruby-prof.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Here’s how to use it:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;TEST_RUBY_PROF=1 rake
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Outputs:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;%self       total       self         wait        child       calls   name
 43.21      2.001     2.001     0.000     0.000        1     Kernel#sleep
   2.97      0.184     0.138     0.000     0.046     1640   Array#permutation
   1.39      0.064     0.064     0.000     0.000      144   PG::Connection#async_exec
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here I can clearly see my call to &lt;code&gt;sleep&lt;/code&gt;, but this could easily be an API call, reading a big file, a slow SQL query, etc.&lt;/p&gt;

&lt;p&gt;Another thing you can do is to use the event profiler.&lt;/p&gt;

&lt;p&gt;Btw, &lt;a href="https://github.com/rails/rails/pull/31900" rel="noopener noreferrer"&gt;Rails 6 added parallel testing&lt;/a&gt;, you’ve to enable this in &lt;code&gt;test/test_helpers.rb&lt;/code&gt; if you’re upgrading your current project.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;4. Find Out Which Code Is Used In Production &amp;amp; Which Isn’t&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Let’s finish with another tool to help you improve your code.&lt;/p&gt;

&lt;p&gt;It’s called &lt;code&gt;coverband&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;If you run this gem in production (low overhead), you’ll get a coverage report of what code is being run.&lt;/p&gt;

&lt;p&gt;You can even track unused views!&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%2Fi%2Fvhvyrv6e10ifbmcv3220.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%2Fi%2Fvhvyrv6e10ifbmcv3220.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This can help you make decisions when deleting code &amp;amp; cleaning your project.&lt;/p&gt;

&lt;p&gt;Don’t let unused code build up!&lt;/p&gt;

&lt;p&gt;You can find it &lt;a href="https://github.com/danmayer/coverband" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Thanks for reading!&lt;br&gt;
I hope that helps someone. Thanks :).&lt;/p&gt;

&lt;p&gt;I’d love to hear thoughts or comments around this. Feel free to email me at &lt;a href="mailto:ronakabhattrz@gmail.com"&gt;ronakabhattrz@gmail.com&lt;/a&gt; or hit me up on Twitter, &lt;a class="mentioned-user" href="https://dev.to/ronakabhattrz"&gt;@ronakabhattrz&lt;/a&gt; .&lt;/p&gt;

</description>
      <category>ruby</category>
      <category>rails</category>
    </item>
    <item>
      <title>What is the Difference between Ruby Blocks, Procs and Lambdas
</title>
      <dc:creator>Ronak Bhatt</dc:creator>
      <pubDate>Fri, 13 Nov 2020 09:20:36 +0000</pubDate>
      <link>https://forem.com/mainstreet/what-is-the-difference-between-ruby-blocks-procs-and-lambdas-oen</link>
      <guid>https://forem.com/mainstreet/what-is-the-difference-between-ruby-blocks-procs-and-lambdas-oen</guid>
      <description>&lt;p&gt;Having a problem understanding the difference between ruby blocks, procs and lamdas. What are the blocks? What is the difference between procs and lambdas? Let's break this down.&lt;/p&gt;

&lt;h4&gt;
  
  
  BLOCKS:
&lt;/h4&gt;

&lt;p&gt;A block is a collection of code enclosed in a do/end statement or between braces { }. They are chunks of code that you can pick up and drop into another method as input or chunk of code that you associate with a method call. If you have used each before to loop through an Enumerable then you have used blocks.&lt;/p&gt;

&lt;h4&gt;
  
  
  Defining a block
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;def block_method
  puts "we are in the method"
end

block_method { puts "The block is called"}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  PROCS
&lt;/h4&gt;

&lt;p&gt;So what if you want to pass two blocks to your function. How can you save your block into a variable?&lt;br&gt;
Ruby introduces procs so that we are able to pass blocks around. Proc objects are blocks of code that have been bound to a set of local variables.Once bound, the code may be called in different contexts and still access those variables.&lt;/p&gt;
&lt;h4&gt;
  
  
  Defining procs
&lt;/h4&gt;

&lt;p&gt;You can call new on the Proc class to create a proc . You can use the kernel object proc. Proc method is simply an alias for Proc.new. This can be assigned into a variable.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;factor = Proc.new {|n| print n*2 }

or 

factor = proc {|n| print n*2}

//using the proc value

[3,2,1].each(&amp;amp;factor)

&amp;gt;642
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  LAMBDAS
&lt;/h4&gt;

&lt;h5&gt;
  
  
  Can be defined using the method lambda or can be defined as stuby lambda
&lt;/h5&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;lamb = lambda {|n| puts 'I am a lambda' }
lamb = -&amp;gt; (n) { puts 'I am a stuby lambda' }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Difference between Procs and Lambdas
&lt;/h4&gt;

&lt;p&gt;Procs don’t care about the correct number of arguments, while lambdas will raise an exception.&lt;/p&gt;

&lt;p&gt;Return and break behaves differently in procs and lambdas&lt;br&gt;
Next behaves same way in both procs and lambdas&lt;/p&gt;

&lt;h3&gt;
  
  
  References
&lt;/h3&gt;

&lt;p&gt;rubyguides.com : &lt;a href="http://www.rubyguides.com/2016/02/ruby-procs-and-lambdas/"&gt;Click Here!!!!&lt;/a&gt;     &lt;/p&gt;

&lt;p&gt;I hope that helps someone. Thanks :).&lt;/p&gt;

&lt;p&gt;Thanks for reading. 🙂&lt;/p&gt;

&lt;p&gt;I’d love to hear thoughts or comments around this. Feel free to email me at &lt;a href="mailto:ronakabhattrz@gmail.com"&gt;ronakabhattrz@gmail.com&lt;/a&gt; or hit me up on twitter, &lt;a class="mentioned-user" href="https://dev.to/ronakabhattrz"&gt;@ronakabhattrz&lt;/a&gt; .&lt;/p&gt;

</description>
      <category>ruby</category>
      <category>rails</category>
    </item>
    <item>
      <title>Rails 6, Stimulus  events</title>
      <dc:creator>Ronak Bhatt</dc:creator>
      <pubDate>Tue, 27 Oct 2020 12:54:57 +0000</pubDate>
      <link>https://forem.com/mainstreet/rails-6-stimulus-events-3bje</link>
      <guid>https://forem.com/mainstreet/rails-6-stimulus-events-3bje</guid>
      <description>&lt;p&gt;An action is a connection between:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a controller method&lt;/li&gt;
&lt;li&gt;the controller’s element&lt;/li&gt;
&lt;li&gt;a DOM event listener&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;gallery_controller.js&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// controllers/gallery_controller.js
import { Controller } from "stimulus"

export default class extends Controller {
  next(event) {
    alert("Justclick !!! :")
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h5&gt;
  
  
  View File Setup
&lt;/h5&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;div data-controller="gallery"&amp;gt;
  &amp;lt;button data-action="click-&amp;gt;gallery#next"&amp;gt;…&amp;lt;/button&amp;gt;
&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h5&gt;
  
  
  Descriptors
&lt;/h5&gt;

&lt;p&gt;The data-action value click-&amp;gt;gallery#next is called an action descriptor. In this descriptor:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;click is the name of the DOM event to listen for&lt;/li&gt;
&lt;li&gt;gallery is the controller identifier&lt;/li&gt;
&lt;li&gt;next is the name of the method to invoke&lt;/li&gt;
&lt;/ul&gt;

&lt;h5&gt;
  
  
  The full set of these shorthand pairs is as follows:
&lt;/h5&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%2Fi%2F9jqk87rgkbp6v8xv77d1.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%2Fi%2F9jqk87rgkbp6v8xv77d1.png" alt="Screenshot 2020-10-27 at 6.24.03 PM"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I hope that helps someone. Thanks :).&lt;/p&gt;

&lt;p&gt;Thanks for reading. 🙂&lt;/p&gt;

&lt;p&gt;I’d love to hear thoughts or comments around this. Feel free to email me at &lt;a href="mailto:ronakabhattrz@gmail.com"&gt;ronakabhattrz@gmail.com&lt;/a&gt; or hit me up on twitter, &lt;a class="mentioned-user" href="https://dev.to/ronakabhattrz"&gt;@ronakabhattrz&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>ruby</category>
      <category>rails</category>
    </item>
    <item>
      <title>How to Use Scopes in Ruby on Rails</title>
      <dc:creator>Ronak Bhatt</dc:creator>
      <pubDate>Thu, 15 Oct 2020 07:24:53 +0000</pubDate>
      <link>https://forem.com/mainstreet/how-to-use-scopes-in-ruby-on-rails-1mhj</link>
      <guid>https://forem.com/mainstreet/how-to-use-scopes-in-ruby-on-rails-1mhj</guid>
      <description>&lt;p&gt;Scopes are custom queries that you define inside your Rails models with the scope method.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Every scope takes two arguments:&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A name, which you use to call this scope in your code&lt;br&gt;
A lambda, which implements the query&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;It looks like this:&lt;br&gt;
&lt;/p&gt;


&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class User &amp;lt; ApplicationRecord
  scope :active, -&amp;gt; { where("status: 0") }
end
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As a result of calling a scope, you’ll get an ActiveRecord::Relation object.&lt;/p&gt;

&lt;p&gt;Which means you can chain &amp;amp; combine scopes!&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;User.active
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  When To Use Scopes?
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;Let’s see an example.&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;def index
  @books = Book.where("LENGTH(title) &amp;gt; 20")
end 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is an index controller action that wants to display books with titles longer than 20 characters.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;It’s fine.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;But if you want to use this query in other places, you’re going to have duplicated code.&lt;/p&gt;

&lt;p&gt;Duplicated code makes your project harder to maintain.&lt;/p&gt;

&lt;p&gt;Let’s move this query into a scope.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Like this:&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class Book
  scope :with_long_title, -&amp;gt; { where("LENGTH(title) &amp;gt; 20") }
end
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Now our controller action looks like this:&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;def index
  @books = Book.with_long_title
end
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Summary&lt;br&gt;
&lt;code&gt;Good job! As a result of reading this article, you’ve learned how to use Rails scopes in the most effective way.&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;code&gt;Don’t forget to put this new knowledge into practice so you can remember how it works.&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Thanks for reading. 🙂&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;I’d love to hear thoughts or comments around this. Feel free to email me at &lt;a href="mailto:ronakabhattrz@gmail.com"&gt;ronakabhattrz@gmail.com&lt;/a&gt; or hit me up on twitter, &lt;a class="mentioned-user" href="https://dev.to/ronakabhattrz"&gt;@ronakabhattrz&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>ruby</category>
      <category>rails</category>
    </item>
    <item>
      <title>Rails 6, Stimulus and Select2</title>
      <dc:creator>Ronak Bhatt</dc:creator>
      <pubDate>Wed, 02 Sep 2020 09:01:24 +0000</pubDate>
      <link>https://forem.com/mainstreet/rails-6-stimulus-and-select2-4901</link>
      <guid>https://forem.com/mainstreet/rails-6-stimulus-and-select2-4901</guid>
      <description>&lt;p&gt;This is just a quicky, to help out anyone using &lt;a href="https://rubyonrails.org"&gt;Rails 6&lt;/a&gt;, or any &lt;a href="https://stimulusjs.org"&gt;Stimulus-enabled&lt;/a&gt; Rails project and &lt;a href="https://select2.org"&gt;Select2&lt;/a&gt;, the amazing jQuery plugin for better select boxes.&lt;/p&gt;

&lt;h5&gt;
  
  
  add select2 &amp;amp; select2-bootstrap-theme package in web-pack
&lt;/h5&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;yarn add select2
yarn add select2-bootstrap-theme
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h5&gt;
  
  
  Simple Select2 + Stimulus Controller
&lt;/h5&gt;

&lt;p&gt;&lt;strong&gt;select2_controller.js&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { Controller } from "stimulus"
import $ from 'jquery';

require("select2/dist/css/select2")
require("select2-bootstrap-theme/dist/select2-bootstrap")

import Select2 from "select2"

export default class extends Controller {
  connect() {
    $('.content-search').select2();
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h5&gt;
  
  
  Replace f.select dropdown according to select2 specifications
&lt;/h5&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;div class="form-group" data-controller='select2'&amp;gt;
  &amp;lt;%= f.select :user_id, User.all.map { |user| user.name }, {include_blank: false, required: true, include_hidden: false}, class: 'form-control content-search' %&amp;gt;
&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I hope that helps someone. Thanks :).&lt;/p&gt;

&lt;p&gt;I’d love to hear thoughts or comments around this. Feel free to email me at &lt;a href="mailto:ronakabhattrz@gmail.com"&gt;ronakabhattrz@gmail.com&lt;/a&gt; or hit me up on Twitter, &lt;a class="mentioned-user" href="https://dev.to/ronakabhattrz"&gt;@ronakabhattrz&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>ruby</category>
      <category>rails</category>
    </item>
    <item>
      <title>Tables and other Advanced Formatting in Action Text (Kind of) </title>
      <dc:creator>John Jacob</dc:creator>
      <pubDate>Fri, 07 Aug 2020 22:12:06 +0000</pubDate>
      <link>https://forem.com/mainstreet/tables-and-other-advanced-formatting-in-action-text-kind-of-1dbn</link>
      <guid>https://forem.com/mainstreet/tables-and-other-advanced-formatting-in-action-text-kind-of-1dbn</guid>
      <description>&lt;p&gt;I work on an in house Learning Management system built in Rails. This Learning Management system allows our content team to create articles, videos and quizzes. This content is delivered through lessons for new business owners. Through these tracks they learn all they need to learn to start and run new service businesses.&lt;/p&gt;

&lt;p&gt;Since were on rails and we needed rich text editing we reached for &lt;a href="https://edgeguides.rubyonrails.org/action_text_overview.html"&gt;Action Text&lt;/a&gt;. Action Text gives you the solid &lt;a href="https://trix-editor.org/"&gt;Trix editor&lt;/a&gt; plug and play in your app. &lt;/p&gt;

&lt;p&gt;&lt;em&gt;Rails Action Text in Practice in our Content Library Back-end&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  However: Action Text / Trix doesn't support tables.
&lt;/h3&gt;

&lt;p&gt;Our content team had lots of tables of information they wanted to be able to communicate. Sometimes it's hard to get across nuanced information for estimating and process without a table. We realized we needed table support in Action Text / Trix. &lt;/p&gt;

&lt;h3&gt;
  
  
  First Direction — Action Text Attachments
&lt;/h3&gt;

&lt;p&gt;My first path was to extend the Action Text attachment model. This is what the &lt;a href="https://readtimelapse.com/how-we-built-table-support-for-trix-editor-cd4f14c03463"&gt;team at Timelapse documented&lt;/a&gt;. Although they provided some good direction, there was nothing I could directly leverage. Also, this seems like a lot of front end complexity for a v1 of a product. Was looking for something similar. In this research I found this great &lt;a href="https://www.youtube.com/watch?v=2iGBuLQ3S0c"&gt;Rails Conf video&lt;/a&gt; from Chris Oliver of Go Rails, a strongly recommended resource on Action Text attachments in general. However, decided against doing something so front end heavy (for now). &lt;/p&gt;

&lt;h2&gt;
  
  
  The Crazy Idea that worked: Render Code-blocks as HTML
&lt;/h2&gt;

&lt;p&gt;Since this project didn't ever need a "Code Block" these articles render to a non-technical audience, why not allow any valid HTML written in a code block to render as HTML.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pros:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;No extra front end work&lt;/li&gt;
&lt;li&gt;Simple Extension of the Article Decorator&lt;/li&gt;
&lt;li&gt;Very maintainable portable simple content (Just HTML)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Cons:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Your users have to be reasonably technical to update HTML code-blocks&lt;/li&gt;
&lt;li&gt;You don't get a WYSIWYG interface when editing content&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I put a rough prototype and did a &lt;a href="https://www.loom.com/share/004c75360fe94207b00cb4f38371c753"&gt;screen recording&lt;/a&gt; to get my colleagues thoughts.&lt;/p&gt;

&lt;h2&gt;
  
  
  Execution
&lt;/h2&gt;

&lt;p&gt;All credit goes to the great &lt;a href="https://dev.to/ortegacmanuel"&gt;Manuel Ortega&lt;/a&gt; for actually making my crazy idea work, he was able to build a clean implementation that solved many of the pitfalls my prototype was riddled with.&lt;/p&gt;

&lt;p&gt;It all essentially boils down to one plain ol' ruby object — this &lt;code&gt;Richtext::CodeBlocks::HtmlService&lt;/code&gt; object:&lt;br&gt;
&lt;/p&gt;

&lt;div class="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;Richtext::CodeBlocks::HtmlService&lt;/span&gt;
  &lt;span class="nc"&gt;ALLOWED_HTML_TAGS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"table"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"tr"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"td"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"th"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"col"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"pre"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"p"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"h1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"h2"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"h3"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"summary"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"details"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"row"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"code"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="no"&gt;ALLOWED_HTML_ATTRIBUTES&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;

  &lt;span class="c1"&gt;# To Validate HTML tags and protect from bad formatted input&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;validate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;html&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;errors&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
    &lt;span class="n"&gt;html&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Nokogiri&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;HTML&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;DocumentFragment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;html&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;html&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;search&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"pre"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;each&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;pre_tag&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
      &lt;span class="n"&gt;pre_tag_html&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;pre_tag_errors&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ensure_well_formed_markup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pre_tag&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="n"&gt;errors&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pre_tag_errors&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;unless&lt;/span&gt; &lt;span class="n"&gt;pre_tag_errors&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;empty?&lt;/span&gt;
      &lt;span class="n"&gt;inner_html&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;extract_inner_html_from_pre_tag&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pre_tag_html&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="n"&gt;inner_html&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;remove_not_allowed_tags_and_attributes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;inner_html&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="n"&gt;pre_tag&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;children&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;first&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;Nokogiri&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;XML&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Text&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;inner_html&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;pre_tag&lt;/span&gt;
      &lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
    &lt;span class="n"&gt;html&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;ActionText&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Fragment&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;html&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;html&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;to_html&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;errors&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;flatten&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;uniq&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="c1"&gt;# To parse each code block tag and render it to HTML&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;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rich_text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;html&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Nokogiri&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;HTML&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;DocumentFragment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rich_text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;html&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;search&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"pre"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;each&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;pre_tag&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
      &lt;span class="n"&gt;inner_html&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Nokogiri&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;HTML&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;DocumentFragment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pre_tag&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="n"&gt;inner_html&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;add_styles_to_tables&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;inner_html&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="n"&gt;advanced_code_block&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"&amp;lt;div class='advanced-code-block'&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;inner_html&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;to_html&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;/div&amp;gt;"&lt;/span&gt;
      &lt;span class="n"&gt;pre_tag&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;advanced_code_block&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
    &lt;span class="n"&gt;html&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;to_html&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="kp"&gt;private&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;ensure_well_formed_markup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;html&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;parsed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Nokogiri&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;XML&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"&amp;lt;pre&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;html&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;/pre&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;parsed&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;parsed&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;errors&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="c1"&gt;# To add our bootstrap specific classes to table elements&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;add_styles_to_tables&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;html&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;html&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;search&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"table"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;each&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;table&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
      &lt;span class="n"&gt;table&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"class"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"table"&lt;/span&gt;
      &lt;span class="n"&gt;table&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;wrap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"&amp;lt;div class='table-responsive'&amp;gt;&amp;lt;/div&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
    &lt;span class="n"&gt;html&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;extract_inner_html_from_pre_tag&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;html&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="no"&gt;Nokogiri&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;XML&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;html&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;at&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"pre"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;inner_html&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="c1"&gt;# To add error messages to mis-formatted HTML&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;error_messages&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;errors&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;readable_message&lt;/span&gt; &lt;span class="o"&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="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;message&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="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;strip&lt;/span&gt; &lt;span class="k"&gt;rescue&lt;/span&gt; &lt;span class="s2"&gt;""&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;errors&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;readable_message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}.&lt;/span&gt;&lt;span class="nf"&gt;uniq&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&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="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;h3&gt;
  
  
  Using the HtmlService
&lt;/h3&gt;

&lt;p&gt;You can just add a method in the article model:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;formatted_body&lt;/span&gt;
  &lt;span class="no"&gt;Richtext&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;CodeBlocks&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;HtmlService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;to_s&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;html_safe&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

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



&lt;p&gt;and then call it in the view&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight erb"&gt;&lt;code&gt;  &lt;span class="cp"&gt;&amp;lt;%=&lt;/span&gt; &lt;span class="vi"&gt;@article&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;formatted_body&lt;/span&gt; &lt;span class="cp"&gt;%&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h3&gt;
  
  
  Screenshots
&lt;/h3&gt;

&lt;p&gt;Here's the example of the editor with code blocks:&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--nyaOXCo---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/b8ldei9o4dbu2wdxbz4r.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--nyaOXCo---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/b8ldei9o4dbu2wdxbz4r.png" alt="Example input"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here's the example output of that article:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--rcKigWCf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/58y51xkjtubr6hlivj4a.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--rcKigWCf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/58y51xkjtubr6hlivj4a.png" alt="Rendered output"&gt;&lt;/a&gt;&lt;br&gt;
Here's example validation being thrown to prevent you from saving bad HTML.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--tq_qwpYv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/lsbvwedrclxfn0iib36w.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--tq_qwpYv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/lsbvwedrclxfn0iib36w.png" alt="Validation"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  In Production
&lt;/h2&gt;

&lt;p&gt;Obviously this repo is a very limited example, but used well in production with an extended CSS framework this can be pretty powerful in practice:&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--0LfD3v62--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/rw5pifmgid8g9vdjkku5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--0LfD3v62--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/rw5pifmgid8g9vdjkku5.png" alt="Production Example 1"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--xIVLkMr2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/sfzt3di1gdeb8auqfpp0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--xIVLkMr2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/sfzt3di1gdeb8auqfpp0.png" alt="Production example 2"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://github.com/Johnsalzarulo/action_text_code_blocks"&gt;Github Repo&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;This is just a basic demo rails app using this approach. Excited to get feedback from anyone else looking to explore a feature like this. &lt;/p&gt;

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