<?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: Jerry Weyer</title>
    <description>The latest articles on DEV Community by Jerry Weyer (@jerryweyer).</description>
    <link>https://dev.to/jerryweyer</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%2F229539%2F52fc438e-7555-470a-9901-8a3a97a04cc0.jpeg</url>
      <title>DEV Community: Jerry Weyer</title>
      <link>https://dev.to/jerryweyer</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/jerryweyer"/>
    <language>en</language>
    <item>
      <title>Converting PDFs to/from images in a Ruby on Rails application</title>
      <dc:creator>Jerry Weyer</dc:creator>
      <pubDate>Fri, 05 Nov 2021 12:06:37 +0000</pubDate>
      <link>https://dev.to/jerryweyer/converting-pdfs-tofrom-images-in-a-ruby-on-rails-application-9gb</link>
      <guid>https://dev.to/jerryweyer/converting-pdfs-tofrom-images-in-a-ruby-on-rails-application-9gb</guid>
      <description>&lt;p&gt;There are quite a few options if you need to convert images to/from PDFs in Ruby (on Rails). I am going to detail two of the most common options I came across in my projects: using &lt;a href="https://imagemagick.org/index.php"&gt;ImageMagick&lt;/a&gt; and using an external API (&lt;a href="https://www.convertapi.com/"&gt;ConvertAPI&lt;/a&gt; in my case).&lt;/p&gt;

&lt;h2&gt;
  
  
  ImageMagick
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://imagemagick.org/index.php"&gt;ImageMagick&lt;/a&gt; is a free open-source &lt;strong&gt;command line tool&lt;/strong&gt; which enables you to convert images to/from PDFs (among other things). You can install the software directly on your system, or in a Rails app via the RMagick gem to create an &lt;em&gt;interface between the Ruby programming language and the ImageMagick image processing library&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Once installed, you can manipulate images with the command-line interface (e.g. converting an image to a PDF of a certain size and DPI):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;`convert -density 300 -units 'PixelsPerInch' image.jpg -extent 2479x3508 -format pdf result.pdf`
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you are using Rails &lt;a href="https://edgeguides.rubyonrails.org/active_storage_overview.html#transforming-images"&gt;Active Storage&lt;/a&gt;, ImageMagick is the default processor for image analysis and transformations. This allows you to create different image variants on upload, without the need to add your custom CLI commands:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight erb"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;%=&lt;/span&gt; &lt;span class="n"&gt;image_tag&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;avatar&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;variant&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;resize_to_limit: &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="cp"&gt;%&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ImageMagick is an extremely powerful tool, but getting it to do exactly what you want can be challenging at times. Check out the authoritative website &lt;a href="https://imagemagick.org/"&gt;imagemagick.org&lt;/a&gt; for all the different options at your disposal.&lt;/p&gt;

&lt;p&gt;A disadvantage of ImageMagick is that managing installations and policies can be difficult if you do not have full access to your system. One problem I ran into when &lt;strong&gt;deploying to Heroku&lt;/strong&gt; was that I could not directly read an image served via https, because of the restrictive default policy. The &lt;a href="https://help.heroku.com/RFDJQSG3/how-can-i-override-imagemagick-settings-in-a-policy-xml-file"&gt;Heroku helpdesk article 'How can I override ImageMagick settings in a policy.xml file?'&lt;/a&gt; didn't solve the problem. I finally got the confirmation from Heroku support, that&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;[...] because we use the pre-packaged Ubuntu ImageMagic which is built with the 'installed' option you cannot override the policy from the system path [...] You can disable/reduce options that are enabled by the system policy but once something is disabled you can't re-enable it.&lt;/p&gt;

&lt;p&gt;Instead of having ImageMagick request the file itself and do a transform on the result of that request, download the image to /tmp and work off that, using local transforms.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In my use-case, I had to first download the image from AWS S3 (active storage) to &lt;code&gt;/tmp&lt;/code&gt; before converting it to a PDF document.&lt;/p&gt;

&lt;p&gt;Another challenge I came across with ImageMagick was converting PDFs with any kind of &lt;strong&gt;transparent elements&lt;/strong&gt;. The resulting image would either miss entire sections or have large black/gray elements as overlays. The solution was to add &lt;code&gt;-alpha remove&lt;/code&gt; to the &lt;code&gt;convert&lt;/code&gt; command.&lt;/p&gt;

&lt;h2&gt;
  
  
  ConvertAPI
&lt;/h2&gt;

&lt;p&gt;Most conversions to/from PDFs can be done via an external service. The advantage of using a 3rd party API that you don't need to worry about the conversion process, managing PDFs versions and edge-cases or implementing new image formats.&lt;/p&gt;

&lt;p&gt;I have had a good experience converting different file formats with &lt;a href="https://www.convertapi.com/"&gt;ConvertAPI&lt;/a&gt;. Their pricing is fair and the API is easy to implement in a Rails project. The ImageMagick version I was using in a project didn't support HEIC images, so I had to use ConvertAPI to convert them to JPEGs.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt; &lt;span class="no"&gt;ConvertApi&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="nf"&gt;api_secret&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'SECRET'&lt;/span&gt;

    &lt;span class="no"&gt;ConvertApi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;convert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'jpg'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="no"&gt;File&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;ConvertApi&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;UploadIO&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;File&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;path&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="ss"&gt;from_format: &lt;/span&gt;&lt;span class="s1"&gt;'heic'&lt;/span&gt;
    &lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;save_files&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;path&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Using an external service is not always possible though. Managing/testing the dependency can be difficult, performance is not ideal and you might not want to send (confidential) customer information to an external service. In that case, ImageMagick remains a powerful alternative!&lt;/p&gt;

</description>
      <category>rails</category>
      <category>ruby</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Combining PDFs in a Ruby on Rails application</title>
      <dc:creator>Jerry Weyer</dc:creator>
      <pubDate>Wed, 27 Oct 2021 16:51:20 +0000</pubDate>
      <link>https://dev.to/jerryweyer/combining-pdfs-in-a-ruby-on-rails-application-m0k</link>
      <guid>https://dev.to/jerryweyer/combining-pdfs-in-a-ruby-on-rails-application-m0k</guid>
      <description>&lt;p&gt;When &lt;a href="https://jerryweyer.lu/creating-pdfs-in-a-ruby-on-rails-application"&gt;creating PDFs&lt;/a&gt; you might need to combine different PDFs into one larger file, for example if you want to add a cover page to a PDF report you are generating, or if you want to add your general terms to an invoice PDF you are sending via your application.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/boazsegev/combine_pdf"&gt;CombinePDF&lt;/a&gt; is a pure Ruby solution to parse PDF files and combine (merge) them with other PDF files, watermark them or stamp them.&lt;/p&gt;

&lt;p&gt;Combining PDFs, for example an invoice and terms and conditions, is pretty straight-forward:&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;pdf&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;CombinePDF&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;
  &lt;span class="n"&gt;pdf&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;CombinePDF&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"invoice.pdf"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;pdf&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;CombinePDF&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;Rails&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;root&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="s1"&gt;'lib'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'data'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'terms.pdf'&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="n"&gt;pdf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;save&lt;/span&gt; &lt;span class="s2"&gt;"combined.pdf"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;CombinePDF offers the handy &lt;code&gt;parse&lt;/code&gt; method to &lt;a href="https://github.com/boazsegev/combine_pdf#loading-and-parsing-pdf-data"&gt;handle PDFs from a remote location&lt;/a&gt;. This can be especially useful when working with ActiveStorage files hosted on Amazon S3 and similar services.&lt;/p&gt;

&lt;p&gt;In one of our apps, our users can upload documents that will be combined into a larger PDF. It is not always possible to scan for compatible PDFs during the upload, and we don't want to abort the entire process when an incompatible PDF is uploaded.&lt;/p&gt;

&lt;p&gt;CombinePDF offers the &lt;code&gt;allow_optional_content&lt;/code&gt; option, which allows you to merge PDFs with &lt;strong&gt;optional content sections&lt;/strong&gt; without raising an exception. We encountered a few instances where uploaded PDFs were not correctly displayed when using this option, but it allows the user to get the final PDFs and assess themselves if they want to replace the PDF in question by a compatible version.&lt;/p&gt;

</description>
      <category>rails</category>
      <category>ruby</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Creating PDFs in a Ruby on Rails application</title>
      <dc:creator>Jerry Weyer</dc:creator>
      <pubDate>Tue, 26 Oct 2021 14:25:39 +0000</pubDate>
      <link>https://dev.to/jerryweyer/creating-pdfs-in-a-ruby-on-rails-application-2kk5</link>
      <guid>https://dev.to/jerryweyer/creating-pdfs-in-a-ruby-on-rails-application-2kk5</guid>
      <description>&lt;p&gt;Working with PDFs in Ruby on Rails can be a daunting task - inflexibility is an inherent part of PDF documents.&lt;/p&gt;

&lt;p&gt;As such the best option is to avoid them if possible. Does you invoice really need to be a PDF? Most of the time it can just be an HTML page that the user can save as PDF via their browser. However, it is not always possible to complete ignore PDFs - f.ex. if the invoice needs to be send as an attachment to an e-mail.&lt;/p&gt;

&lt;p&gt;You have a few options when trying to create a PDF in a Rails environment. &lt;a href="https://github.com/prawnpdf/prawn"&gt;Prawn&lt;/a&gt; and &lt;a href="https://github.com/mileszs/wicked_pdf"&gt;Wicked PDF&lt;/a&gt; have been around for quite a while. I have been using both gems and they work fine. However, they have a few limitations that can make it difficult to handle more complex PDFs. I recently discovered &lt;a href="https://github.com/Studiosity/grover"&gt;Grover&lt;/a&gt;, which can remediate some of this inflexibility in creating PDFs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prawn
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/prawnpdf/prawn"&gt;Prawn&lt;/a&gt; is a &lt;em&gt;pure Ruby PDF generation library that provides a lot of great functionality while trying to remain simple and reasonably performant&lt;/em&gt;. It is quick to setup and create simple PDFs:&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="nb"&gt;require&lt;/span&gt; &lt;span class="s2"&gt;"prawn"&lt;/span&gt;

  &lt;span class="no"&gt;Prawn&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;generate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"hello.pdf"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="s2"&gt;"Hello World!"&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Where Prawn gets more complicated is when trying to create complex PDFs. It uses its own DSL you need to learn in order to "draw" your PDFs by hand. While the &lt;a href="https://prawnpdf.org/manual.pdf"&gt;manual&lt;/a&gt; is very helpful in order to figure our how to add images, tables and styling, you will end up with a lot of custom code to create a more complex PDF.&lt;/p&gt;

&lt;p&gt;There are gems to facilitate handling Prawn PDFs, e.g. &lt;a href="https://github.com/puzzle/prawn-markup"&gt;prawn-markup&lt;/a&gt; which lets you add simple HTML snippets into Prawn-generated PDF.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wicked PDF
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/mileszs/wicked_pdf"&gt;Wicked PDF&lt;/a&gt; allows you to &lt;em&gt;serve a PDF file to a user from HTML&lt;/em&gt;. As such, you can include your custom CSS and Javascript via the helpers provided by Wicked.&lt;/p&gt;

&lt;p&gt;Wicked is a great gem to create PDFs with more complex layouts and styling, without the need to apply a custom DSL. There are quite a few tutorials out there to help you when you are stuck on a specific problem.&lt;/p&gt;

&lt;p&gt;One problem I regularly came across with Wicked was that getting everything running in production proved to be more challenging than expected. Especially the custom CSS (with asset pipeline) and images proved to be a problem.&lt;/p&gt;

&lt;h2&gt;
  
  
  Grover
&lt;/h2&gt;

&lt;p&gt;In my effort to find a replacement for Prawn or Wicked PDF, I recently came across &lt;a href="https://github.com/Studiosity/grover"&gt;Grover&lt;/a&gt;. This gem allows you to transform HTML into PDFs, PNGs or JPEGs using Google Puppeteer and Chromium. It basically imitates the action of a user saving an HTML page as PDF in the Chrome browser.&lt;/p&gt;

&lt;p&gt;While there are fewer tutorials out there on how to get everything up-and-running, the great flexibility it gives me to just use my existing views and print them as PDFs makes this my current favourite for creating PDFs.&lt;/p&gt;

&lt;p&gt;In fact you can save any existing view as PDF, allowing you to reuse your current HTML and/or CSS framework. You can use &lt;a href="https://tailwindcss.com/"&gt;Tailwind&lt;/a&gt; for your CSS or &lt;a href="https://viewcomponent.org/"&gt;ViewComponent&lt;/a&gt; to display your components and print them to PDF.&lt;/p&gt;

&lt;p&gt;However I had a bit of trouble getting Grover to generate PDFs on our Heroku production environment. I finally managed to find a solution in the issue tracker and comments.&lt;/p&gt;

&lt;p&gt;For my setup, it was important to use &lt;code&gt;Grover::HTMLPreprocessor&lt;/code&gt; as well as include the &lt;code&gt;display_url&lt;/code&gt; (make sure to change that in production). You also need to include the correct &lt;a href="https://github.com/Studiosity/grover#running-on-heroku"&gt;buildpacks&lt;/a&gt; mentioned in the readme.&lt;/p&gt;

&lt;p&gt;An example application could include this setup - rendering a view from the controller, including a custom PDF layout and saving it as an A4 PDF with Grover:&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;renderer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;ApplicationController&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;renderer&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;http_host: &lt;/span&gt;&lt;span class="s2"&gt;"http://localhost:3000/"&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="n"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;render_to_string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="s2"&gt;"invoice/show"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;# Any view within your app&lt;/span&gt;
  &lt;span class="ss"&gt;layout: &lt;/span&gt;&lt;span class="s2"&gt;"pdf"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="c1"&gt;# You can add a custom layout as well&lt;/span&gt;
  &lt;span class="ss"&gt;locals: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="ss"&gt;:@invoice&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;invoice&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="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Grover&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;HTMLPreprocessor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;process&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;base_url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"https"&lt;/span&gt;

&lt;span class="no"&gt;Grover&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="ss"&gt;format: &lt;/span&gt;&lt;span class="s2"&gt;"A4"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;# Many other options are available&lt;/span&gt;
  &lt;span class="ss"&gt;emulate_media: &lt;/span&gt;&lt;span class="s2"&gt;"screen"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="ss"&gt;display_url: &lt;/span&gt;&lt;span class="s2"&gt;"http://localhost:3000/"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="ss"&gt;scale: &lt;/span&gt;&lt;span class="mf"&gt;0.9&lt;/span&gt;    &lt;span class="c1"&gt;# This helped me to get the PDF displayed correctly on A4 format&lt;/span&gt;
&lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nf"&gt;to_pdf&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The great advantage of this solution is that whenever I update a component or a layout style, my PDFs will reflect these changes, without the need to modify any PDF-specific resources.&lt;/p&gt;

</description>
      <category>ruby</category>
      <category>rails</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Adding syntax highlighting to a Rails app with PrismJs</title>
      <dc:creator>Jerry Weyer</dc:creator>
      <pubDate>Tue, 12 Oct 2021 13:46:27 +0000</pubDate>
      <link>https://dev.to/jerryweyer/adding-syntax-highlighting-to-a-rails-app-with-prismjs-2n4k</link>
      <guid>https://dev.to/jerryweyer/adding-syntax-highlighting-to-a-rails-app-with-prismjs-2n4k</guid>
      <description>&lt;p&gt;If you are running a technical blog, it is very likely that you want to share some code-snippets. Syntax highlighting is nearly a must in order to make any shared code readable for your audience. There are different solutions to integrate syntax highlighting into a Rails application - I'll quickly show how I integrated &lt;a href="https://prismjs.com/"&gt;Prism&lt;/a&gt; into this blog.&lt;/p&gt;

&lt;p&gt;The first step to get syntax highlighting for your code snippets is to use the correct HTML tags. It is generally advised to add your snippets in a &lt;code&gt;&amp;lt;pre&amp;gt;&amp;lt;code&amp;gt;...&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;block&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Next we will add code highlighting with the javascript library Prism. There are other options (like &lt;a href="https://highlightjs.org/"&gt;highlightjs&lt;/a&gt;), but Prism was the fastest to get running on this Rails blog app.&lt;/p&gt;

&lt;p&gt;First we add Prism via yarn package manager: &lt;code&gt;yarn add prismjs&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Then we add the plugin to our &lt;code&gt;babel.config.js&lt;/code&gt; and define the languages we want to import:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;  &lt;span class="nx"&gt;plugins&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;prismjs&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;languages&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;css&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ruby&lt;/span&gt;&lt;span class="dl"&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;You can find a list of &lt;a href="https://prismjs.com/#supported-languages"&gt;supported languages&lt;/a&gt; on the Prism website.&lt;/p&gt;

&lt;p&gt;Finally, in order to load the script after page load, we update our &lt;code&gt;application.js&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;  &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Prism&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;prismjs&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

  &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;turbo:load&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="nx"&gt;Prism&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;highlightAll&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;If your app runs &lt;code&gt;turbolinks&lt;/code&gt; instead of turbo, you need to change the &lt;code&gt;"turbo:load"&lt;/code&gt; to &lt;code&gt;"turbolinks:load"&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This should be enough to get the basic syntax highlighting working! You can now customize your integration:&lt;/p&gt;

&lt;p&gt;You can &lt;strong&gt;add custom styling&lt;/strong&gt; by simply overriding the theme styling in your css files, e.g. to change the background color:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;  &lt;span class="nd"&gt;:not&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nt"&gt;pre&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nt"&gt;code&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nt"&gt;class&lt;/span&gt;&lt;span class="o"&gt;*=&lt;/span&gt;&lt;span class="s1"&gt;"language-"&lt;/span&gt;&lt;span class="o"&gt;],&lt;/span&gt;
  &lt;span class="nt"&gt;pre&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nt"&gt;class&lt;/span&gt;&lt;span class="o"&gt;*=&lt;/span&gt;&lt;span class="s1"&gt;"language-"&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nl"&gt;background&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#334155&lt;/span&gt; &lt;span class="cp"&gt;!important&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;You can &lt;strong&gt;add custom themes&lt;/strong&gt; via the prism-themes repository. Add the plugin via &lt;code&gt;yarn add prism-themes&lt;/code&gt; and import the corresponding theme in your &lt;code&gt;application.scss&lt;/code&gt; with &lt;code&gt;@import "prism-themes/themes/prism-dracula.css";&lt;/code&gt;. This blog uses a slightly customizes version of the &lt;code&gt;dracula&lt;/code&gt; theme.&lt;/p&gt;

</description>
      <category>rails</category>
      <category>javascript</category>
      <category>webdev</category>
    </item>
    <item>
      <title>How to get Pundit to work with Rails View Component</title>
      <dc:creator>Jerry Weyer</dc:creator>
      <pubDate>Mon, 11 Oct 2021 15:06:10 +0000</pubDate>
      <link>https://dev.to/jerryweyer/how-to-get-pundit-to-work-with-rails-view-component-2kdg</link>
      <guid>https://dev.to/jerryweyer/how-to-get-pundit-to-work-with-rails-view-component-2kdg</guid>
      <description>&lt;p&gt;In &lt;a href="http://facture.lu/"&gt;facture.lu&lt;/a&gt; we use &lt;a href="https://github.com/varvet/pundit"&gt;Pundit&lt;/a&gt; as our authorization system and &lt;a href="https://github.com/heartcombo/devise"&gt;Devise&lt;/a&gt; for authentication. This allows us to assign each signed-in user a role - admins can do everything, read-only user can only read.&lt;/p&gt;

&lt;p&gt;I also included &lt;a href="https://viewcomponent.org/"&gt;View Component&lt;/a&gt; in this project as I noticed in previous apps that it is very difficult to maintain a coherent design over the years if the html and css for each component (e.g. a button or dropdown menu) is not centralized.&lt;/p&gt;

&lt;p&gt;After setting up Pundit and creating policies for each user role, we can hide or show different elements based on the current user's role - f.ex. the button to add a new team member will only be visible to admins.&lt;/p&gt;

&lt;p&gt;In a view we can simply verify &lt;code&gt;if policy(User).create?&lt;/code&gt; and Pundit will call the &lt;code&gt;current_user&lt;/code&gt; method to check if the signed-in user is allowed to perform this action.&lt;/p&gt;

&lt;p&gt;In a view component, this does not work out of the box however, as a component is generally agnostic about the view context.&lt;br&gt;
As such &lt;code&gt;policy(current_user, User).create?&lt;/code&gt; will give you an error:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  undefined method `current_user' for nil:NilClass
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Several solutions to this problem are described in &lt;a href="https://github.com/github/view_component/issues/310"&gt;issue#310 (View Component)&lt;/a&gt;. I prefer the &lt;a href="https://github.com/github/view_component/issues/310#issuecomment-650823756"&gt;CurrentAttributes api solution described by jaredcwhite&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In order to get our &lt;code&gt;current_user&lt;/code&gt; to our components, we take advantage of &lt;a href="https://api.rubyonrails.org/classes/ActiveSupport/CurrentAttributes.html"&gt;ActiveSupport::CurrentAttributes&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;  &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Current&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&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;CurrentAttributes&lt;/span&gt;
    &lt;span class="n"&gt;attribute&lt;/span&gt; &lt;span class="ss"&gt;:user&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 an ApplicationController before_action callback, we set the current user:&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;before_action&lt;/span&gt; &lt;span class="ss"&gt;:initialize_component_context&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;initialize_component_context&lt;/span&gt;
    &lt;span class="no"&gt;Current&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;current_user&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 our view component, we can then access the user via the new class:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;  &lt;span class="no"&gt;Pundit&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;policy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;Current&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;Offer&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;edit?&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the issue comments, you can read more about how to make it work for previews as well. As I'm not using previews at the moment, I didn't include all the recommendations from the post.&lt;/p&gt;

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