<?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: Christian</title>
    <description>The latest articles on DEV Community by Christian (@a_chris).</description>
    <link>https://dev.to/a_chris</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%2F272186%2Fbcc72838-4b34-43ac-a2a2-6f0075f9ef9e.jpeg</url>
      <title>DEV Community: Christian</title>
      <link>https://dev.to/a_chris</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/a_chris"/>
    <language>en</language>
    <item>
      <title>Integrating a Blog section to your Rails app using Markdown in minutes</title>
      <dc:creator>Christian</dc:creator>
      <pubDate>Sat, 27 Jan 2024 09:57:05 +0000</pubDate>
      <link>https://dev.to/a_chris/integrating-a-blog-section-to-your-rails-app-using-markdown-in-minutes-dn1</link>
      <guid>https://dev.to/a_chris/integrating-a-blog-section-to-your-rails-app-using-markdown-in-minutes-dn1</guid>
      <description>&lt;p&gt;Having a blog on your website is a fantastic way to attract new visitors and ensure search engines, like Google, index your content. I recently faced this challenge while working on my web app, &lt;a href="https://titrovo.casa" rel="noopener noreferrer"&gt;tiTrovo.casa&lt;/a&gt;, a free service assisting users in finding homes to rent or buy in Italy.&lt;/p&gt;

&lt;p&gt;Recognizing the value of sharing experiences, especially when dealing with complex topics like Italian bureaucracy, I decided to add a blog section. People often seek practical advice from those who've been through similar situations, and having personally navigated the intricacies of the Italian system, I knew a blog could be immensely helpful.&lt;/p&gt;

&lt;h2&gt;
  
  
  Defining Our Objectives
&lt;/h2&gt;

&lt;p&gt;The idea is to create articles quickly using Markdown, a user-friendly and familiar format. These Markdown files will collectively form the article list within the blog section.&lt;/p&gt;

&lt;p&gt;A functional blog section should have an index page listing all available articles, each with its title, description, images, and additional information. Clicking on an article should smoothly transition the user to the dedicated article page, styled with our custom CSS. For a modern touch, we might even consider adding share buttons at the end.&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%2F6f2aw82r9n39wq3frq0m.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%2F6f2aw82r9n39wq3frq0m.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Tools of the Trade
&lt;/h2&gt;

&lt;p&gt;So, how do we achieve all of this using just Markdown files?&lt;/p&gt;

&lt;p&gt;Here's our roadmap:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Parse Markdown files and convert them to HTML.&lt;/li&gt;
&lt;li&gt;Make Rails dynamically recognize routes.&lt;/li&gt;
&lt;li&gt;Extract information from Markdown files: title, description, image, and article URL.&lt;/li&gt;
&lt;li&gt;Customizing the article page.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Let's dive into step 1.&lt;/p&gt;

&lt;h3&gt;
  
  
  Parsing Markdown Files and Converting to HTML
&lt;/h3&gt;

&lt;p&gt;To accomplish this, we'll leverage the &lt;a href="https://github.com/vmg/redcarpet" rel="noopener noreferrer"&gt;Redcarpet&lt;/a&gt; gem, a straightforward tool for Markdown conversion.&lt;br&gt;
Following the gem's README, we can use the following code snippet:&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;markdown&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Redcarpet&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Markdown&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="no"&gt;Redcarpet&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Render&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;HTML&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;extensions&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;markdown&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="s2"&gt;"This is *markdown*, indeed."&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;This converts Markdown to HTML, and we can further customize the HTML generation with extensions if needed. For this tutorial, we'll keep it simple.&lt;/p&gt;

&lt;p&gt;To automate the processing of .md files with Redcarpet in a Rails application, let's create our &lt;strong&gt;MarkdownToHtml&lt;/strong&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;# lib/converters/markdown_to_html.rb&lt;/span&gt;

&lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nn"&gt;Converters&lt;/span&gt;
  &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MarkdownToHtml&lt;/span&gt;
    &lt;span class="k"&gt;def&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;template&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="n"&gt;markdown&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Redcarpet&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Markdown&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="no"&gt;Redcarpet&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Render&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;HTML&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

      &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;markdown&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="n"&gt;source&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;inspect&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.html_safe"&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;Next, create an initializer to bind the Markdown converter to files with the .md extension:&lt;/p&gt;

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

&lt;span class="c1"&gt;# config/initializers/converters.rb&lt;/span&gt;

&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;'converters/markdown_to_html'&lt;/span&gt;

&lt;span class="no"&gt;ActionView&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Template&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;register_template_handler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:md&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;Converters&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;MarkdownToHtml&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;With these configurations, Rails is ready to process Markdown files placed in the &lt;code&gt;app/views/blog/&lt;/code&gt; folder.&lt;/p&gt;

&lt;p&gt;To view it in your browser, add the required route:&lt;/p&gt;

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

&lt;span class="c1"&gt;# config/routes.rb&lt;/span&gt;

&lt;span class="n"&gt;get&lt;/span&gt; &lt;span class="s1"&gt;'blog/my_first_article'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;to: &lt;/span&gt;&lt;span class="s1"&gt;'blog#my_first_article'&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;And create the Rails controller, &lt;strong&gt;BlogController&lt;/strong&gt; in this case:&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;# app/controllers/blog_controller.rb&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;my_first_article&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;At this point, creating the &lt;code&gt;app/views/blog/my_first_article.md&lt;/code&gt; file should display its content in the browser. 😁&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Making Rails Recognize Dynamic Routes
&lt;/h3&gt;

&lt;p&gt;Instead of manually adding a new route and action for each article, let's make the routes dynamic.&lt;/p&gt;

&lt;p&gt;Open the routes file and add two routes: the index and the article "show" page:&lt;/p&gt;

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

&lt;span class="c1"&gt;# config/routes.rb&lt;/span&gt;

&lt;span class="n"&gt;get&lt;/span&gt; &lt;span class="s1"&gt;'blog'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;to: &lt;/span&gt;&lt;span class="s1"&gt;'blog#index'&lt;/span&gt;
&lt;span class="n"&gt;get&lt;/span&gt; &lt;span class="s1"&gt;'blog/:any'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;to: &lt;/span&gt;&lt;span class="s1"&gt;'blog#article'&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;Now, create the &lt;code&gt;article&lt;/code&gt; action in the BlogController:&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;# app/controllers/blog_controller.rb&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;index&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;article&lt;/span&gt;
  &lt;span class="n"&gt;render&lt;/span&gt; &lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:any&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;to_sym&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;Magic! This setup renders the right article based on the &lt;code&gt;params[:any]&lt;/code&gt; provided in the URL.&lt;/p&gt;

&lt;p&gt;For now, the index action is empty, but we'll fill it in the next step.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Extracting Information from the Markdown File
&lt;/h3&gt;

&lt;p&gt;To collect article information, we'll utilize front matter!&lt;/p&gt;

&lt;h3&gt;
  
  
  What is front matter?
&lt;/h3&gt;

&lt;p&gt;In the world of Markdown, front matter is a powerful tool that allows you to embed metadata or configuration settings directly within your document. This metadata is typically placed at the beginning of a Markdown file and is enclosed by triple dashes (---).&lt;/p&gt;

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

&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;My Awesome Blog Post&lt;/span&gt;
&lt;span class="na"&gt;author&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;John Doe&lt;/span&gt;
&lt;span class="na"&gt;date&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;2024-01-25&lt;/span&gt;
&lt;span class="na"&gt;tags&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;Markdown&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;Front Matter&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;Blogging&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;

&lt;span class="c1"&gt;# Heading 1&lt;/span&gt;

&lt;span class="s"&gt;This is the content of my blog post. Front matter provides a convenient way to include additional information about the document, such as the title, author, date, and tags.&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;In this example, the front matter contains metadata such as the title of the blog post, the author's name, the publication date, and a list of tags associated with the content. This structured information can be leveraged by various systems and tools to enhance the presentation and organization of your Markdown documents.&lt;/p&gt;

&lt;p&gt;Front matter is commonly used in static site generators, blogging platforms, and other applications that process Markdown files to provide a richer and more customizable user experience.&lt;/p&gt;

&lt;h3&gt;
  
  
  Integrating front matter
&lt;/h3&gt;

&lt;p&gt;At the beginning of each Markdown file, include front matter with blog post information you want to display in the posts list. Common fields include:&lt;/p&gt;

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

&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Article title&lt;/span&gt;
&lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/blog/article_image.png"&lt;/span&gt;
&lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;description&lt;/span&gt;
&lt;span class="c1"&gt;# other information here&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;Parse these front matter fields using the &lt;a href="https://github.com/waiting-for-dev/front_matter_parser" rel="noopener noreferrer"&gt;front_matter_parser&lt;/a&gt; Ruby gem, like this:&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;content&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;File&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;read&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'article.md'&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;FrontMatterParser&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Parser&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="ss"&gt;:md&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;content&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;front_matter&lt;/span&gt; &lt;span class="c1"&gt;# contains title, image, description and other fields&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;and integrate this into our BlogController:&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;def&lt;/span&gt; &lt;span class="nf"&gt;index&lt;/span&gt;
    &lt;span class="n"&gt;blog_folder&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'app/views/blog'&lt;/span&gt;

    &lt;span class="c1"&gt;# Array&amp;lt;{ title:, description:, image:, url: }&amp;gt;&lt;/span&gt;
    &lt;span class="vi"&gt;@articles&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Dir&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;blog_folder&lt;/span&gt;&lt;span class="p"&gt;)&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;select&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;_1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ends_with?&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'md'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
                   &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&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;filename&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
                     &lt;span class="n"&gt;fm&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;FrontMatterParser&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Parser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse_file&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;blog_folder&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;filename&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;front_matter&lt;/span&gt;
                     &lt;span class="n"&gt;fm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;merge!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;url: &lt;/span&gt;&lt;span class="s2"&gt;"blog/&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;filename&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;gsub&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'.md'&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="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                     &lt;span class="n"&gt;fm&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="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;We've added the url for each blog post since we dynamically calculate the equivalent of the show page, allowing users to navigate to that page when clicking on a blog post.&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%2Foteenxxhp4yonyc2spzi.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%2Foteenxxhp4yonyc2spzi.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Customizing for the article page.
&lt;/h3&gt;

&lt;p&gt;With our fully functional blog section showcasing a list of available posts and the ability to navigate to individual post pages, let's add the finishing touches for a polished user experience. In this step, we'll focus on customizing the article page by introducing custom CSS styling and incorporating a social sharing feature using AddToAny.&lt;/p&gt;

&lt;p&gt;Here's how we make these enhancements to the &lt;code&gt;MarkdownToHtml&lt;/code&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;Converters&lt;/span&gt;
  &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MarkdownToHtml&lt;/span&gt;
    &lt;span class="no"&gt;TEMPLATE_CONTENT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;-&lt;/span&gt;&lt;span class="no"&gt;HTML&lt;/span&gt;&lt;span class="sh"&gt;
      &amp;lt;div class="post-page"&amp;gt;

        ${content}

        &amp;lt;!-- AddToAny BEGIN --&amp;gt;
        &amp;lt;div class="a2a_kit a2a_kit_size_32 a2a_default_style"&amp;gt;
          Condividi su
          &amp;lt;a class="a2a_button_x"&amp;gt;&amp;lt;/a&amp;gt;
          &amp;lt;a class="a2a_button_whatsapp"&amp;gt;&amp;lt;/a&amp;gt;
          &amp;lt;a class="a2a_button_facebook"&amp;gt;&amp;lt;/a&amp;gt;
          &amp;lt;a class="a2a_button_telegram"&amp;gt;&amp;lt;/a&amp;gt;
          &amp;lt;a class="a2a_button_linkedin"&amp;gt;&amp;lt;/a&amp;gt;
        &amp;lt;/div&amp;gt;
        &amp;lt;script&amp;gt;
            var a2a_config = a2a_config || {};
            a2a_config.num_services = 5;
        &amp;lt;/script&amp;gt;
        &amp;lt;script async src="https://static.addtoany.com/menu/page.js"&amp;gt;&amp;lt;/script&amp;gt;
          &amp;lt;!-- AddToAny END --&amp;gt;
        &amp;lt;/div&amp;gt;
      &amp;lt;/div&amp;gt;
&lt;/span&gt;&lt;span class="no"&gt;    HTML&lt;/span&gt;

    &lt;span class="k"&gt;def&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;template&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="n"&gt;markdown&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Redcarpet&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Markdown&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="no"&gt;Redcarpet&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Render&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;HTML&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

      &lt;span class="c1"&gt;# remove the front matter information&lt;/span&gt;
      &lt;span class="n"&gt;sanitized_source&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;gsub&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/---([\S\s]*)---/&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;""&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;strip&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;TEMPLATE_CONTENT&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;gsub&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"${content}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;markdown&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="n"&gt;sanitized_source&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

      &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&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;inspect&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.html_safe"&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;In this modification, we've introduced the &lt;code&gt;${content}&lt;/code&gt; placeholder in the HTML template, acting as a marker for the Markdown content. This placeholder gets replaced with the actual HTML-rendered content using the gsub method.&lt;/p&gt;

&lt;p&gt;Additionally, we've removed the front matter information from the source to prevent it from appearing in the final HTML.&lt;/p&gt;

&lt;p&gt;To make the page visually appealing, create a CSS file, for example, &lt;code&gt;app/assets/stylesheets/blog.scss&lt;/code&gt;, and define styles for elements inside &lt;code&gt;.post-page&lt;/code&gt;:&lt;/p&gt;

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

&lt;span class="nc"&gt;.post-page&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;margin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;auto&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;padding-top&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2em&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;@media&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;min-width&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;$mobile-width&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;max-width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;800px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nt"&gt;h1&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;font-size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2em&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;text-align&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;center&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;margin-top&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="mi"&gt;.8em&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;margin-bottom&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="mi"&gt;.8em&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nt"&gt;h2&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;font-size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="mi"&gt;.6em&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;margin-top&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2em&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;margin-bottom&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="mi"&gt;.7em&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nt"&gt;p&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;line-height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;font-size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;19px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nt"&gt;img&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;aspect-ratio&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;5&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="m"&gt;3&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;object-fit&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;cover&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100%&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;border-radius&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;8px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;margin-top&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="mi"&gt;.8em&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nc"&gt;.a2a_kit&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;flex&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;justify-content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;flex-end&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;margin-bottom&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;3rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;margin-top&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;3rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="nt"&gt;a&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nl"&gt;margin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="mi"&gt;.3rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;This CSS file defines styles for various elements within .post-page, ensuring a visually pleasing layout for your blog posts.&lt;/p&gt;

&lt;p&gt;Feel free to customize these styles further to match your design preferences. As your blog takes shape, these enhancements will contribute to a delightful reading experience.&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%2F2xf3nxnu7a0ds2oun07q.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%2F2xf3nxnu7a0ds2oun07q.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;In conclusion, with this step-by-step guide, you've empowered your Rails application with a dynamic and Markdown-driven blog section. By seamlessly integrating Redcarpet for Markdown conversion, creating dynamic routes, and utilizing front matter for rich metadata, you've crafted an engaging space for sharing valuable content.&lt;/p&gt;

&lt;p&gt;Now, as your blog section takes shape, remember that this is just the beginning. Explore further customization, experiment with styling, and continue sharing your insights. Whether you're a seasoned developer or just starting, the versatility of Markdown brings a user-friendly approach to content creation.&lt;/p&gt;

&lt;p&gt;Feel the satisfaction of providing practical advice, sharing experiences, and connecting with your audience.&lt;/p&gt;

&lt;p&gt;If you have questions, feedback, or encounter any challenges along the way, don't hesitate to reach out on &lt;a href="https://twitter.com/achris_15" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt;. Happy blogging!&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>rails</category>
      <category>ruby</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Rails live reloading assets</title>
      <dc:creator>Christian</dc:creator>
      <pubDate>Thu, 02 Jun 2022 14:58:12 +0000</pubDate>
      <link>https://dev.to/a_chris/rails-live-reloading-assets-1k9e</link>
      <guid>https://dev.to/a_chris/rails-live-reloading-assets-1k9e</guid>
      <description>&lt;p&gt;Recently I've been trying to learn more about the Rails assets pipeline. The standard documentation is very well written and has tons of tips and best practices but there's something I was still missing: &lt;strong&gt;live reloading the assets&lt;/strong&gt;, in particular the css/scss assets.&lt;/p&gt;

&lt;p&gt;Working with React this is the pretty standard behaviour: you update a file and you can instantly see the changes on the browser.&lt;/p&gt;

&lt;p&gt;The Rails documentation does not explain how to obtain this behaviour and, honestly, I've never managed to make the live compilation work, so I've been killing the server, running &lt;code&gt;bundle exec rails assets:precompile&lt;/code&gt; and restarting the server the whole time, until now.&lt;/p&gt;

&lt;p&gt;Luckily, a few days ago I discovered an handy gem that solves this issue in a very simple way: &lt;a href="https://github.com/railsjazz/rails_live_reload" rel="noopener noreferrer"&gt;rails_live_reload&lt;/a&gt;.&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%2Fcb5e1x12jw5bj1zz2dim.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%2Fcb5e1x12jw5bj1zz2dim.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Install the rails_live_reload
&lt;/h2&gt;

&lt;p&gt;Adds this gem in the &lt;code&gt;development&lt;/code&gt; group, or whatever group you need, in you Gemfile&lt;/p&gt;

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

group :development do
  gem 'rails_live_reload'
  ...
end


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

&lt;/div&gt;

&lt;p&gt;and un &lt;code&gt;bundle install&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tweak the development settings
&lt;/h2&gt;

&lt;p&gt;Open the &lt;code&gt;config/environments/development.rb&lt;/code&gt; file and add these lines:&lt;/p&gt;

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

config.assets.compile = true
config.assets.digest = false


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

&lt;/div&gt;

&lt;p&gt;the &lt;code&gt;assets.compile&lt;/code&gt; option enables the live compilation through Sprockets, as stated in &lt;a href="https://guides.rubyonrails.org/asset_pipeline.html#live-compilation" rel="noopener noreferrer"&gt;the official documentation&lt;/a&gt; while the &lt;code&gt;assets.digest&lt;/code&gt; turns off the generation of digest strings for the assets names. To be honest I'm not sure why the latter is required &lt;strong&gt;but if it is omitted both the live reloading and the live compilation won't work&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Run the css watch
&lt;/h2&gt;

&lt;p&gt;We need to open a terminal window and spawn the process that watches for changes in the the css/scss files.&lt;br&gt;
If you are using the &lt;code&gt;dartsass-rails&lt;/code&gt; gem you can run:&lt;/p&gt;

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

bundle exec rails dartsass:watch


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

&lt;/div&gt;

&lt;p&gt;while if you are using &lt;code&gt;cssbunding-rails&lt;/code&gt; or any other solutions you probably want to run:&lt;/p&gt;

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

yarn build:css --watch


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

&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;keep this terminal running, do not kill it.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The Rails server
&lt;/h2&gt;

&lt;p&gt;Finally, open a new terminal and run the Rails server to enjoy the live reloading assets 😎.&lt;/p&gt;

&lt;p&gt;Feel free to write any suggestion or question in the comments. I would be really happy if someone could explain to me, and everyone who will read this tutorial, why the &lt;code&gt;config.assets.digest = false&lt;/code&gt; is required to make the auto compilation/reloading work 🤯&lt;/p&gt;

</description>
      <category>ruby</category>
      <category>rails</category>
      <category>tutorial</category>
      <category>webdev</category>
    </item>
    <item>
      <title>How to install the mysql2 Ruby gem on a Mac M1</title>
      <dc:creator>Christian</dc:creator>
      <pubDate>Wed, 18 May 2022 07:27:27 +0000</pubDate>
      <link>https://dev.to/a_chris/how-to-install-the-mysql2-ruby-gem-on-a-mac-m1-4oip</link>
      <guid>https://dev.to/a_chris/how-to-install-the-mysql2-ruby-gem-on-a-mac-m1-4oip</guid>
      <description>&lt;p&gt;The Mac M1 family has been presented more than two year ago and I still encounter a new issue every time I try to install the mysql2 Ruby gem.&lt;br&gt;
But... I think I've finally found a set of commands to fix all these  issues!&lt;/p&gt;

&lt;p&gt;First of all, install the required dependencies:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;brew install gcc zstd openssl mysql
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;now export all the libraries paths which we need to build the gem:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export LDFLAGS="-L/opt/homebrew/opt/openssl@3/lib"
export CPPFLAGS="-I/opt/homebrew/opt/openssl@3/include"
export LIBRARY_PATH=$LIBRARY_PATH:$(brew --prefix zstd)/lib/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;aaaand now install the mysql gem:&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 mysql2 -v '0.5.4' -- --with-opt-dir=$(brew --prefix openssl) --with-ldflags=-L$(brew --prefix zstd)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;woila', I'm 100% this will succed, if don't please leave a comment so we can figure out a new solution to help who will read this post 🚀 &lt;/p&gt;

</description>
      <category>ruby</category>
      <category>rails</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Small tip to reduce your Docker images size</title>
      <dc:creator>Christian</dc:creator>
      <pubDate>Thu, 05 May 2022 12:59:12 +0000</pubDate>
      <link>https://dev.to/a_chris/small-tip-to-shrink-your-docker-images-size-57i5</link>
      <guid>https://dev.to/a_chris/small-tip-to-shrink-your-docker-images-size-57i5</guid>
      <description>&lt;p&gt;Hi everyone, first post on dev.to, I whish to be more active in the future!&lt;/p&gt;

&lt;p&gt;Today I want to explain a small tip I recently fond out to reduce the Docker images size, in my case I was able to reduce the size by half!&lt;/p&gt;

&lt;p&gt;Let's assume that you are working with a language like Ruby or Python, even if these languages are not compiled they often need some system libraries to work properly, in particular if you are working with databases (MySQL, SQLite, Postgres) you need to compile the gem or the library for the specific architecture of your machine.&lt;/p&gt;

&lt;p&gt;In my case I'm working with Ruby and I'm trying to install the SQLite gem that, unfortunately, requires the &lt;code&gt;build-base&lt;/code&gt; system library.&lt;/p&gt;

&lt;p&gt;Here is the project I'm working on:&lt;br&gt;
&lt;a href="https://github.com/a-chris/faenz"&gt;Faenz Analytics&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So I thought to install it, compile the SQLite gem and uninstall everything I do not need anymore, here is my Dockerfile:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;FROM ruby:3.0.4-alpine3.15
WORKDIR /faenz-analytics
RUN apk update &amp;amp;&amp;amp; \
    apk add make &amp;amp;&amp;amp; \
    apk add build-base &amp;amp;&amp;amp; \ # this takes 200Mb of space!!
    apk add sqlite-dev

# ...some instructions

RUN bundle install  # installing Ruby gems
RUN apk del build-base

# ...some other instructions
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;easy, right? we installed &lt;code&gt;build-base&lt;/code&gt;, compiled and installed the gems and removed &lt;code&gt;build-base&lt;/code&gt; to reduce the image size. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The problem is that this does not work! The image size is the same as if we did not remove &lt;code&gt;build-base&lt;/code&gt;. Let's discover why.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;We wrote three &lt;code&gt;RUN&lt;/code&gt; instructions, each one generates a layer and these layer are put togheter by Docker to create the final image:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;the first &lt;code&gt;RUN&lt;/code&gt; installs the system libraries&lt;/li&gt;
&lt;li&gt;the second &lt;code&gt;RUN&lt;/code&gt; install the gems/libraries by Ruby or whatever language you are using&lt;/li&gt;
&lt;li&gt;the third &lt;code&gt;RUN&lt;/code&gt; removes the system libraries&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;since we installed the system libraries in one of the layer they will take some space and will increase the image size, there's no way we can reduce the image size with the next layers.&lt;/p&gt;

&lt;p&gt;It's like a sum with no negative numbers. The size can only increase or stay the same from a layer to another.&lt;/p&gt;

&lt;h2&gt;
  
  
  What? Don't give up, we got this 🚀
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Here is the solution: put these operations in the same layer!&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;FROM ruby:3.0.4-alpine3.15
WORKDIR /faenz-analytics
RUN apk update &amp;amp;&amp;amp; \
    apk add make &amp;amp;&amp;amp; \
    apk add sqlite-dev

# ...some instructions

RUN apk add build-base &amp;amp;&amp;amp; \
    bundle install &amp;amp;&amp;amp; \
    apk del build-base

# ...some other instructions
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;grouping the operations in just one &lt;code&gt;RUN&lt;/code&gt; instruction avoids Docker to waste space to store the &lt;code&gt;build-base&lt;/code&gt; in a layer. The layer is generated at the end of the instruction so we are going to install, use the &lt;code&gt;build-base&lt;/code&gt; and prontly remove it so that the layer will not contain it at all.&lt;/p&gt;

&lt;p&gt;With this little tip my image size went from 400Mb to 170mb, less than half!&lt;/p&gt;

&lt;p&gt;If you want to exagerate with the micro optimizations, you can apply the same solution to &lt;code&gt;apk update&lt;/code&gt; (or &lt;code&gt;apt-get update&lt;/code&gt; for debian/ubuntu images) by deleting the cache created by this command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;RUN apk update &amp;amp;&amp;amp; \
    add build-base &amp;amp;&amp;amp; \
    # install other dependencies here...
    bundle install &amp;amp;&amp;amp; \
    apk del build-base &amp;amp;&amp;amp; \
    rm -rf /var/cache/apk &amp;amp;&amp;amp; \
    rm -rf tmp/cache
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I'm not a Docker expert, so, if you know a better solution or want to share similar tips to reduce the image size please leave a comment, I'm all ears 🙏&lt;/p&gt;

</description>
      <category>docker</category>
      <category>ruby</category>
      <category>python</category>
      <category>tutorial</category>
    </item>
  </channel>
</rss>
