<?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: Marc Riera</title>
    <description>The latest articles on DEV Community by Marc Riera (@mrcasals).</description>
    <link>https://dev.to/mrcasals</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%2F14031%2F85a2de88-3395-41a9-8371-1dd9c0be0e44.jpeg</url>
      <title>DEV Community: Marc Riera</title>
      <link>https://dev.to/mrcasals</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/mrcasals"/>
    <language>en</language>
    <item>
      <title>How to autocancel GitHub Actions workflows </title>
      <dc:creator>Marc Riera</dc:creator>
      <pubDate>Thu, 05 Mar 2020 09:15:16 +0000</pubDate>
      <link>https://dev.to/codegram/how-to-autocancel-github-actions-workflows-m39</link>
      <guid>https://dev.to/codegram/how-to-autocancel-github-actions-workflows-m39</guid>
      <description>&lt;p&gt;GitHub announced some months ago &lt;a href="https://github.com/features/actions"&gt;GitHub Actions&lt;/a&gt;, a system that allows you to run arbitrary code based on some given events happening around a given repository. People flocked to it, hoping it would allow them to run their test suites. This is particularly true for open-source projects, since GitHub gives out an unlimited amount of minutes to run actions for these kind of repos.&lt;/p&gt;

&lt;p&gt;At Codegram we wanted to try it for some of our repos, but found some little issues that kind of made switching difficult. For example, GitHub Actions does not support autocanceling previous workflows.&lt;/p&gt;

&lt;p&gt;Imagine this scenario:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;I commit to a branch and push it to my repo&lt;/li&gt;
&lt;li&gt;A CI build is triggered&lt;/li&gt;
&lt;li&gt;Before the CI build is finished, I push again&lt;/li&gt;
&lt;li&gt;Another CI build is triggered&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;What I'd like to happen is that the first CI build is stopped, since it's no longer necessary: it's become redundant, now that we have new changes.&lt;/p&gt;

&lt;p&gt;Some CI services (CircleCI, for example) support autocancelling built on these kind of scenarios. Autocancelling is useful because it frees resources so that you can run newer, more up-to-date test suites, and it helps you save money (in case you're paying for those resources, of course).&lt;/p&gt;

&lt;h3&gt;
  
  
  Enter actions!
&lt;/h3&gt;

&lt;p&gt;GitHub Actions has a concept that is a game changer, in my opinion: community actions. This means you can reuse actions made by other people, the whole community can benefit from them. And well, it took a while, but finally someone made it: &lt;a href="https://github.com/marketplace/actions/workflow-run-cleanup-action"&gt;an action to autocancel redundant builds&lt;/a&gt;. Here's how to use it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[]&lt;/span&gt;
&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;my-job&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;rokroskar/workflow-run-cleanup-action@v0.2.2&lt;/span&gt;
      &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;GITHUB_TOKEN&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;${{&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;secrets.GITHUB_TOKEN&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;}}"&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v2.0.0&lt;/span&gt;
    &lt;span class="s"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By running the action &lt;em&gt;before&lt;/em&gt; checking out the repo we save a couple of seconds (&lt;em&gt;it ain't much, but it's honest work&lt;/em&gt;) so we can cancel redundant workflows earlier. Beware, though: as its configured, it will run on any branch. We can limit it, though, to avoid autocancelling workflows on our &lt;code&gt;master&lt;/code&gt; branch.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[]&lt;/span&gt;
&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;my-job&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;rokroskar/workflow-run-cleanup-action@v0.2.2&lt;/span&gt;
      &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;GITHUB_TOKEN&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;${{&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;secrets.GITHUB_TOKEN&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;}}"&lt;/span&gt;
      &lt;span class="na"&gt;if&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;github.ref&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;!=&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;'refs/heads/master'"&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v2.0.0&lt;/span&gt;
    &lt;span class="s"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note the &lt;code&gt;if:&lt;/code&gt; part. I won't go into too much detail here, but we can conditionally run some steps based on the &lt;code&gt;if:&lt;/code&gt; key. In this case, we're telling GitHub Actions to ignore this step if the current branch is &lt;code&gt;master&lt;/code&gt;. You could add other branches, depending on your own workflow, but I hope you get the idea. Don't forget to check &lt;a href="https://github.com/rokroskar/workflow-run-cleanup-action"&gt;the repo&lt;/a&gt; for more info.&lt;/p&gt;

&lt;p&gt;So, in any case, thanks &lt;a href="https://github.com/rokroskar"&gt;Rok Roškar&lt;/a&gt; for your work on this action!&lt;/p&gt;

</description>
      <category>githubactions</category>
      <category>github</category>
    </item>
    <item>
      <title>asdf: a version manager to rule them all</title>
      <dc:creator>Marc Riera</dc:creator>
      <pubDate>Thu, 13 Feb 2020 15:11:11 +0000</pubDate>
      <link>https://dev.to/codegram/asdf-a-version-manager-to-rule-them-all-5bbh</link>
      <guid>https://dev.to/codegram/asdf-a-version-manager-to-rule-them-all-5bbh</guid>
      <description>&lt;p&gt;When I started programming in Ruby, I had to install &lt;a href="https://rvm.io/"&gt;&lt;code&gt;rvm&lt;/code&gt;&lt;/a&gt; (Ruby Version Manager) to use the correct Ruby version for each of the different projects I was in. After some time, I switched to &lt;a href="https://github.com/rbenv/rbenv"&gt;&lt;code&gt;rbenv&lt;/code&gt;&lt;/a&gt; (yes, that's another Ruby version manager) because &lt;code&gt;rvm&lt;/code&gt; was too slow. but then a workmate appeared, saying &lt;a href="https://github.com/postmodern/chruby"&gt;&lt;code&gt;chruby&lt;/code&gt;&lt;/a&gt; (you guessed it, yet another Ruby version manager) was even faster, so I switched again. All was good, flowers were blooming, rainbows appeared in the sky and butterflies... Butterflied? Butterflew? Well, whatever, butterflies did their thing.&lt;/p&gt;

&lt;p&gt;Then NodeJS appeared and, of course, I had to install its own version manager. I went with &lt;a href="https://github.com/nvm-sh/nvm"&gt;&lt;code&gt;nvm&lt;/code&gt;&lt;/a&gt; (Node Version Manager), but then I switched laptops and I tried &lt;a href="https://github.com/tj/n"&gt;&lt;code&gt;n&lt;/code&gt;&lt;/a&gt;, a lighter version manager. I had some problems with it, so I finally went back to &lt;code&gt;nvm&lt;/code&gt;. Butterflies started getting worried.&lt;/p&gt;

&lt;p&gt;Then I started programming in Elixir. Guess my next step.&lt;/p&gt;

&lt;p&gt;At this point, butterflies got sad and stopped butterflying.&lt;/p&gt;

&lt;p&gt;This setup is not sustainable, for me. I need to keep remembering how to install new language versions, and when setting up a project I need to remember what files each of the version managers use to define what version this project uses. Oh, and I need to actually install all the needed version managers, and you'd probably want to set the version autodiscovery, so you always run the correct language version when changing projects...&lt;/p&gt;

&lt;p&gt;"But Marc, you only need to install a new version once in a while, and you can set a project template that adds all the needed files", you might say. And you'd be right, it's not a big deal. But (of course there was a "but", otherwise this post would not make sense) this forces all devs in the project to install a version manager for each of the languages we need, and manually install the correct versions. This doesn't scale well.&lt;/p&gt;

&lt;p&gt;Can we do better? Of course we can.&lt;/p&gt;

&lt;p&gt;Enter &lt;code&gt;asdf&lt;/code&gt;!&lt;/p&gt;

&lt;h3&gt;
  
  
  Managing the managers
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://asdf-vm.com"&gt;&lt;code&gt;asdf&lt;/code&gt;&lt;/a&gt; is a version manager version manager. No, that's not a typo! With &lt;code&gt;asdf&lt;/code&gt; you install language version managers, and it offers a common syntax to install language versions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;asdf plugin-install elixir
asdf plugin-install ruby
asdf &lt;span class="nb"&gt;install &lt;/span&gt;elixir latest
asdf &lt;span class="nb"&gt;install &lt;/span&gt;ruby 2.7.0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;See? I don't even need to know what version managers it uses, internally. And in your project you can &lt;a href="https://asdf-vm.com/#/core-configuration?id=tool-versions"&gt;setup the project language versions&lt;/a&gt; like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# .tool-versions
ruby 2.7.0
node 12.8
elixir 1.4.0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When &lt;code&gt;cd&lt;/code&gt;ing to this project, &lt;code&gt;asdf&lt;/code&gt; will automatically set the correct versions for you. And the best thing is that, if some workmate enters the project and they don't have the dependencies installed they can run this command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;asdf &lt;span class="nb"&gt;install&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And &lt;code&gt;asdf&lt;/code&gt; will install all the needed managers and versions! You can see the list of plugins &lt;a href="https://asdf-vm.com/#/plugins-all"&gt;here&lt;/a&gt;. Be sure to check the official docs for other useful commands!&lt;/p&gt;

&lt;h3&gt;
  
  
  Switching to asdf
&lt;/h3&gt;

&lt;p&gt;Switching all your projects to &lt;code&gt;asdf&lt;/code&gt;, though, might be a little tiring. And maybe not everyone in the team will want to use it (yet). In these cases, &lt;code&gt;asdf&lt;/code&gt; lets you &lt;a href="https://asdf-vm.com/#/core-configuration?id=homeasdfrc"&gt;fallback to legacy version files&lt;/a&gt;, so that managers that support it fallback correctly (e.g. the &lt;code&gt;.ruby-version&lt;/code&gt; file for &lt;code&gt;rbenv&lt;/code&gt;):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# ~/.asdfrc
legacy_version_file = yes
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Wrapping up
&lt;/h3&gt;

&lt;p&gt;I hope you see the advantages of using &lt;code&gt;asdf&lt;/code&gt; in your local machine. It's been a game changer for me, and since I installed it I haven't had any problem remembering how to install new language versions or how to change them.&lt;/p&gt;

&lt;p&gt;Thanks for reading!&lt;/p&gt;

</description>
      <category>languages</category>
      <category>ruby</category>
      <category>elixir</category>
      <category>node</category>
    </item>
    <item>
      <title>An i18n engine with translation rules?</title>
      <dc:creator>Marc Riera</dc:creator>
      <pubDate>Tue, 01 Oct 2019 14:31:09 +0000</pubDate>
      <link>https://dev.to/mrcasals/an-i18n-engine-with-translation-rules-2cfa</link>
      <guid>https://dev.to/mrcasals/an-i18n-engine-with-translation-rules-2cfa</guid>
      <description>&lt;p&gt;This is a long shot, but hopefully someone can help!&lt;/p&gt;

&lt;p&gt;Some time ago I found an i18n engine that allowed you to define custom rules to improve the translation quality. Most i18n engines simply interpolate the argument to the translated string. This causes non-natural translations. An example is languages that use articles and apostrophes, like Catalan, French or Italian, or languages with cases, like German or Lithuanian.&lt;/p&gt;

&lt;p&gt;This i18n engine let you define custom rules on how to generate those apostrophes depending on the argument that you're sending to the translated string.&lt;/p&gt;

&lt;p&gt;Anyone knows something about it?&lt;/p&gt;

&lt;p&gt;Thanks!&lt;/p&gt;

</description>
      <category>help</category>
      <category>translation</category>
    </item>
    <item>
      <title>Using components in Phoenix templates </title>
      <dc:creator>Marc Riera</dc:creator>
      <pubDate>Wed, 28 Aug 2019 09:40:47 +0000</pubDate>
      <link>https://dev.to/codegram/using-components-in-phoenix-templates-5do1</link>
      <guid>https://dev.to/codegram/using-components-in-phoenix-templates-5do1</guid>
      <description>&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://www.codegram.com/blog/phoenix-templates-components" rel="noopener noreferrer"&gt;Codegram's blog&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;As a mostly-Rails backend developer, &lt;strong&gt;I find &lt;a href="https://guides.rubyonrails.org/layouts_and_rendering.html#using-partials" rel="noopener noreferrer"&gt;Rails partials&lt;/a&gt; confusing&lt;/strong&gt;. Don't get me wrong, they're useful. But they're hard to work with. In my experience, most of the times these partials will accept params, but there's no way to know what params they accept without looking at the partial content itself. And this makes me sad.&lt;/p&gt;

&lt;p&gt;I usually write partials similar to frontend frameworks components. Minus the logic part, because I haven't found a way to have real components in Rails views. The most similar thing to what I'm looking for is &lt;a href="http://trailblazer.to/gems/cells/" rel="noopener noreferrer"&gt;Trailblazer's &lt;code&gt;cells&lt;/code&gt;&lt;/a&gt; (which I really like!), but they're still not quite what I'd like.&lt;/p&gt;

&lt;p&gt;We recently worked on project that had an admin dashboard built on Phoenix based on a Bootstrap template. This kind of templates usually add their own classes on top of Bootstrap, and those components require extra HTML structure so that everything looks as expected.&lt;/p&gt;

&lt;p&gt;"Oh, it's the perfect use case for components!", I thought.&lt;/p&gt;

&lt;h2&gt;
  
  
  Componentizing Phoenix templates
&lt;/h2&gt;

&lt;p&gt;Well, yes. This was the typical use case for partials. But Phoenix does not support partials explicitly as Rails does. Since Phoenix is very flexible, you can &lt;a href="https://blog.danielberkompas.com/2017/01/17/reusable-templates-in-phoenix/" rel="noopener noreferrer"&gt;write a &lt;code&gt;ComponentView&lt;/code&gt; and dump your shared layouts there&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;lt;%=&lt;/span&gt; &lt;span class="n"&gt;render&lt;/span&gt; &lt;span class="no"&gt;ComponentView&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"tabs.html"&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="p"&gt;%&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="o"&gt;&amp;lt;%=&lt;/span&gt; &lt;span class="n"&gt;render&lt;/span&gt; &lt;span class="no"&gt;ComponentView&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"tab.html"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;name:&lt;/span&gt; &lt;span class="s2"&gt;"All Products"&lt;/span&gt; &lt;span class="p"&gt;%&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="o"&gt;&amp;lt;%=&lt;/span&gt; &lt;span class="n"&gt;render&lt;/span&gt; &lt;span class="no"&gt;ComponentView&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"tab.html"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;name:&lt;/span&gt; &lt;span class="s2"&gt;"Featured"&lt;/span&gt; &lt;span class="p"&gt;%&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;%&lt;/span&gt; &lt;span class="k"&gt;end&lt;/span&gt; &lt;span class="p"&gt;%&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;tabs.html&lt;/code&gt; file contains the wrapper layout for a tabs element, and the &lt;code&gt;tab.html&lt;/code&gt; contains the layout for a single tab.&lt;/p&gt;

&lt;p&gt;You can give a little twist to that idea, and simplify it to this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;lt;%=&lt;/span&gt; &lt;span class="n"&gt;component&lt;/span&gt; &lt;span class="s2"&gt;"tabs.html"&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="p"&gt;%&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="o"&gt;&amp;lt;%=&lt;/span&gt; &lt;span class="n"&gt;component&lt;/span&gt; &lt;span class="s2"&gt;"tab.html"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;name:&lt;/span&gt; &lt;span class="s2"&gt;"All Products"&lt;/span&gt; &lt;span class="p"&gt;%&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="o"&gt;&amp;lt;%=&lt;/span&gt; &lt;span class="n"&gt;component&lt;/span&gt; &lt;span class="s2"&gt;"tab.html"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;name:&lt;/span&gt; &lt;span class="s2"&gt;"Featured"&lt;/span&gt; &lt;span class="p"&gt;%&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;%&lt;/span&gt; &lt;span class="k"&gt;end&lt;/span&gt; &lt;span class="p"&gt;%&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we have a similar feature as Rails has, but since we're using a single view for all components, all component-related helpers would be written there. All together.&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%2Fwww.codegram.com%2Fblog%2Fphoenix-view-components-concerned.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.codegram.com%2Fblog%2Fphoenix-view-components-concerned.jpg" alt="Concerned darkwraith meme."&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Multiple views
&lt;/h2&gt;

&lt;p&gt;Exploring alternative implementations of components I found &lt;a href="https://github.com/kimlindholm/phoenix_component_folders" rel="noopener noreferrer"&gt;Kim Lindholm's Phoenix component Folders repo&lt;/a&gt;. If you follow the suggestions in the README file, you'll be able to have multiple component views, so that helper methods can be isolated. This allows us to write something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="c1"&gt;# lib/my_app_web/components/tabs/tabs_view.ex&lt;/span&gt;
&lt;span class="k"&gt;defmodule&lt;/span&gt; &lt;span class="no"&gt;MyAppWeb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Components&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;TabsView&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;alias&lt;/span&gt; &lt;span class="no"&gt;MyAppWeb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Components&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;ComponentHelpers&lt;/span&gt;
  &lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="no"&gt;MyAppWeb&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:view&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;ComponentHelpers&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;view_opts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:tabs&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;# in your template:&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;%=&lt;/span&gt; &lt;span class="n"&gt;component&lt;/span&gt; &lt;span class="ss"&gt;:tabs&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="p"&gt;%&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="o"&gt;&amp;lt;%=&lt;/span&gt; &lt;span class="n"&gt;component&lt;/span&gt; &lt;span class="ss"&gt;:tabs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:tab&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;name:&lt;/span&gt; &lt;span class="s2"&gt;"All Products"&lt;/span&gt; &lt;span class="p"&gt;%&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="o"&gt;&amp;lt;%=&lt;/span&gt; &lt;span class="n"&gt;component&lt;/span&gt; &lt;span class="ss"&gt;:tabs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:tab&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;name:&lt;/span&gt; &lt;span class="s2"&gt;"Featured"&lt;/span&gt; &lt;span class="p"&gt;%&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;%&lt;/span&gt; &lt;span class="k"&gt;end&lt;/span&gt; &lt;span class="p"&gt;%&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This got us the same functionality Rails has... with the same problems: &lt;strong&gt;what params does a component accept?&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Using helper methods to know the needed params
&lt;/h2&gt;

&lt;p&gt;The fact that I couldn't see, at a glance, the params needed to build a component bugged me. I could leave it as it was, really. After all, I had been developing like that with Rails for a long time. But Elixir has a powerful toolkit to generate static docs from the documentation in the code, and I wanted to use that.&lt;/p&gt;

&lt;p&gt;Finally, I created helper methods. Some of them wrapped the calls to the &lt;code&gt;component&lt;/code&gt; methods, others created template syntax directly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;icon&lt;/span&gt;&lt;span class="p"&gt;(%{&lt;/span&gt;&lt;span class="ss"&gt;icon_name:&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;icon_color:&lt;/span&gt; &lt;span class="n"&gt;color&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;content_tag&lt;/span&gt; &lt;span class="ss"&gt;:span&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;class:&lt;/span&gt; &lt;span class="s2"&gt;"icon-holder"&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="no"&gt;ComponentHelpers&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;component&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:icon&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;color:&lt;/span&gt; &lt;span class="n"&gt;color&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;icon:&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You could even use &lt;a href="https://hexdocs.pm/phoenix_html/2.13.3/Phoenix.HTML.html#sigil_E/2" rel="noopener noreferrer"&gt;the &lt;code&gt;~E&lt;/code&gt; sigil&lt;/a&gt; to simplify the needed code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;icon&lt;/span&gt;&lt;span class="p"&gt;(%{&lt;/span&gt;&lt;span class="ss"&gt;icon_name:&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;icon_color:&lt;/span&gt; &lt;span class="n"&gt;color&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="sx"&gt;~E""&lt;/span&gt;&lt;span class="s2"&gt;"
  &amp;lt;span class="&lt;/span&gt;&lt;span class="n"&gt;icon&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;holder&lt;/span&gt;&lt;span class="s2"&gt;"&amp;gt;
    &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="no"&gt;ComponentHelpers&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;component&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:icon&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;color:&lt;/span&gt; &lt;span class="n"&gt;color&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;icon:&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;
  &amp;lt;/span&amp;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;With that I could write static docs, and &lt;strong&gt;my IDE can catch it and give me hints&lt;/strong&gt; about the needed parameters.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;This is quite a new approach for me and I probably need more opportunities to see how it matures, so I don't have a final decision on how to write components in Phoenix. I like the final approach using helper methods wrapping my components to get nice documentation, though.&lt;/p&gt;

&lt;p&gt;What are your thoughts on this approach? Have you used something similar? Is there something I missed? &lt;/p&gt;

</description>
      <category>phoenix</category>
      <category>elixir</category>
      <category>templates</category>
      <category>components</category>
    </item>
  </channel>
</rss>
