<?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: Nicholas Dill</title>
    <description>The latest articles on DEV Community by Nicholas Dill (@nicholasdill).</description>
    <link>https://dev.to/nicholasdill</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%2F216408%2F77161463-368b-4ca1-9afc-079411e91027.jpg</url>
      <title>DEV Community: Nicholas Dill</title>
      <link>https://dev.to/nicholasdill</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/nicholasdill"/>
    <language>en</language>
    <item>
      <title>How to Render Plain Text Templates in Ruby on Rails</title>
      <dc:creator>Nicholas Dill</dc:creator>
      <pubDate>Sat, 29 Oct 2022 15:30:01 +0000</pubDate>
      <link>https://dev.to/nicholasdill/how-to-render-plain-text-templates-in-ruby-on-rails-10l6</link>
      <guid>https://dev.to/nicholasdill/how-to-render-plain-text-templates-in-ruby-on-rails-10l6</guid>
      <description>&lt;p&gt;If you're trying to get your Rails application to return a plain text file, like &lt;code&gt;robots.txt&lt;/code&gt; for search engines, here's how you can do it.&lt;/p&gt;

&lt;p&gt;If you want a quick solution this will work but I'll cover everything more in-depth and give you more customization below.&lt;/p&gt;




&lt;h2&gt;
  
  
  Quickest Way to Render a Text File
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1.&lt;/strong&gt; Place your text file in your views directory: &lt;/p&gt;

&lt;p&gt;&lt;code&gt;app/views/example/robots.txt&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2.&lt;/strong&gt; Create a route to map the request to your text file: &lt;/p&gt;

&lt;p&gt;&lt;code&gt;get '/robots.txt', to: 'example#robots'&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3.&lt;/strong&gt; Add an action to your controller to render this text file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# app/controllers/example_controller.rb
class ExampleController &amp;lt; ApplicationController
    def robots
        render 'example/robots.txt', layout: false, content_type: 'text/plain'
    end
end
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And you're done, this will map any request to &lt;code&gt;example.com/robots.txt&lt;/code&gt; to your text file.&lt;/p&gt;

&lt;p&gt;Now, if you want more control such as handling other formats or avoiding 404s, read on.&lt;/p&gt;




&lt;h2&gt;
  
  
  Control How Your Site Handles TXT Files and Formats
&lt;/h2&gt;

&lt;h2&gt;
  
  
  1. Create the TXT File
&lt;/h2&gt;

&lt;p&gt;First, you need to add the file to your views directory.&lt;/p&gt;

&lt;p&gt;You can change the extension of your file from &lt;code&gt;robots.txt&lt;/code&gt; to &lt;code&gt;robots.text.erb&lt;/code&gt; in order to avoid having to explicitly render the &lt;code&gt;robots.txt&lt;/code&gt;. Rails looks for &lt;a href="https://testsuite.io/ruby-templating-engines"&gt;ERB templates&lt;/a&gt; by default.&lt;/p&gt;

&lt;p&gt;Depending on the name of your controller, the file should be located at &lt;code&gt;app/views/example/robots.text.erb&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This is where we'll route the request to.&lt;/p&gt;




&lt;h2&gt;
  
  
  2. Create the Controller Action
&lt;/h2&gt;

&lt;p&gt;If you're new to Rails, the controller is the actual code your server calls when it gets a request.&lt;/p&gt;

&lt;p&gt;By default, it runs any code you specify and renders a view with a matching name.&lt;/p&gt;

&lt;p&gt;So if we have a controller we named ExampleController, it should be located at &lt;code&gt;app/views/controllers/example_controller.rb&lt;/code&gt;. This will ensure it uses our views at &lt;code&gt;app/views/example/...&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;If all of our files are in the right places and named correctly, this step is really easy.&lt;/p&gt;

&lt;p&gt;We just need to create a method in this controller to point to our text file. It can be empty. The name of the method needs to match the name of the file in order to make things easy.&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;ExampleController&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ApplicationController&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;robots&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 set up the controller method (also known as an action) so that Rails knows the file to render.&lt;/p&gt;

&lt;p&gt;And that's it for the controller. We don't need to run any code so our method can be empty.&lt;/p&gt;




&lt;h2&gt;
  
  
  3. Create a Route For Your Text File
&lt;/h2&gt;

&lt;p&gt;Lastly, routing. You have a few choices here depending on what behavior you want.&lt;/p&gt;

&lt;h3&gt;
  
  
  Option 1: Only Support the TXT Extension
&lt;/h3&gt;

&lt;p&gt;If you only want your server to respond to the &lt;code&gt;txt&lt;/code&gt; format, you can specify that specifically in your &lt;code&gt;config/routes.rb&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;get&lt;/span&gt; &lt;span class="s1"&gt;'/robots.txt'&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;'example#robots'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you attempt a different format, like &lt;em&gt;example.com/robots&lt;/em&gt;, or &lt;em&gt;example.com/robots.json&lt;/em&gt;, your server will return a 404 because those aren't defined in your routes.&lt;/p&gt;

&lt;p&gt;Requests would have to be exactly &lt;em&gt;example.com/robots.txt&lt;/em&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Options 2: Respond With TXT Regardless of the Requested Format
&lt;/h3&gt;

&lt;p&gt;Another option is to allow all formats but instead of responding with a 404 for unknown formats, we can respond with our TXT anyway.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# config/routes.rb&lt;/span&gt;
&lt;span class="n"&gt;get&lt;/span&gt; &lt;span class="s1"&gt;'/robots'&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;'example#robots'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With this approach, there is one additional change we need to make to our controller given it now needs to convert all requested formats to respond with our txt file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# app/controllers/example_controller.rb&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ExampleController&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ApplicationController&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;robots&lt;/span&gt;
        &lt;span class="c1"&gt;# Add the line below&lt;/span&gt;
        &lt;span class="n"&gt;render&lt;/span&gt; &lt;span class="s1"&gt;'example/robots.text.erb'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;layout: &lt;/span&gt;&lt;span class="kp"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;content_type: &lt;/span&gt;&lt;span class="s1"&gt;'text/plain'&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;This controller action will now render our &lt;code&gt;robots.text.erb&lt;/code&gt; file regardless of the format requested. We specify &lt;code&gt;layout: false&lt;/code&gt; to avoid rendering the default layout of our other Rails views. And we pass along the &lt;a href="https://testsuite.io/content-type-header"&gt;content type&lt;/a&gt; of &lt;code&gt;text/plain&lt;/code&gt; to specify that this is a text file.&lt;/p&gt;

&lt;h3&gt;
  
  
  Option 3: Handling Multiple Formats
&lt;/h3&gt;

&lt;p&gt;The last option is to support multiple formats, not just return a text file for everything.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;For example many people do this with their sitemap, you can view it in HTML, XML, anything.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;We can easily support multiple formats, but you must remember to create the template for each supported format in your views directory.&lt;/p&gt;

&lt;p&gt;That means if you want to support XML, you need a &lt;code&gt;robots.xml.erb&lt;/code&gt; too. Same for HTML, &lt;code&gt;robots.html.erb&lt;/code&gt;. (See the full list of supported formats.)&lt;/p&gt;

&lt;p&gt;If you set up routing for a format you don't have a template for, you will encounter an error like &lt;code&gt;ActionController::UnknownFormat in Example#robots&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;It will tell you this:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Example#robots is missing a template for this request format and variant. request.formats: ["text/html"] request.variant: []&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Once we have our templates created for each format, we need to make sure our controller maps each requested format to the template we created.&lt;/p&gt;

&lt;p&gt;We do this by calling &lt;code&gt;respond_to&lt;/code&gt; and listing each format we want to support.&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;ExampleController&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ApplicationController&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;robots&lt;/span&gt;
        &lt;span class="n"&gt;respond_to&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="nb"&gt;format&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
            &lt;span class="nb"&gt;format&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;text&lt;/span&gt;
            &lt;span class="nb"&gt;format&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;html&lt;/span&gt;
            &lt;span class="nb"&gt;format&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;any&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;redirect_to&lt;/span&gt; &lt;span class="s1"&gt;'/robots.txt'&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;end&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; The &lt;code&gt;format.any&lt;/code&gt; acts as a catchall, like an "else" statement if none of the previous formats matched.&lt;/p&gt;

&lt;p&gt;If you don't want this route to return a 404 for any format you can include it and redirect those bad formats to a format you do expect.&lt;/p&gt;

&lt;p&gt;In summary, this controller now responds to any format, &lt;code&gt;example.com/robots.txt&lt;/code&gt; maps to your &lt;code&gt;robots.text.erb&lt;/code&gt; file, &lt;code&gt;example.com/robots&lt;/code&gt; maps to the HTML variant at &lt;code&gt;robots.html.erb&lt;/code&gt;, and anything else gets redirected to the first &lt;code&gt;example.com/robots.txt&lt;/code&gt; endpoint.&lt;/p&gt;

&lt;p&gt;&lt;a id="mimetypes"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  All Mimetypes You Can Respond to With Rails
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"*/*"                      =&amp;gt; :all
"text/plain"               =&amp;gt; :text
"text/html"                =&amp;gt; :html 
"application/xhtml+xml"    =&amp;gt; :html
"text/javascript"          =&amp;gt; :js 
"application/javascript"   =&amp;gt; :js 
"application/x-javascript" =&amp;gt; :js 
"text/calendar"            =&amp;gt; :ics   
"text/csv"                 =&amp;gt; :csv   
"application/xml"          =&amp;gt; :xml 
"text/xml"                 =&amp;gt; :xml 
"application/x-xml"        =&amp;gt; :xml 
"text/yaml"                =&amp;gt; :yaml 
"application/x-yaml"       =&amp;gt; :yaml 
"application/rss+xml"      =&amp;gt; :rss   
"application/atom+xml"     =&amp;gt; :atom  
"application/json"         =&amp;gt; :json 
"text/x-json"              =&amp;gt; :json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Errors and Troubleshooting
&lt;/h2&gt;

&lt;p&gt;Common errors and the reasons they come up.&lt;/p&gt;

&lt;h3&gt;
  
  
  Missing Template
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ActionView::MissingTemplate (Missing template /robots.text.erb with {:locale=&amp;gt;[:en], :formats=&amp;gt;[:text], :variants=&amp;gt;[], :handlers=&amp;gt;[:raw, :erb, :html, :builder, :ruby, :coffee]}. Searched in:
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This means your controller specified a format but you didn't create a template for it. Specifically if you attempted to go to &lt;code&gt;/robots.txt&lt;/code&gt; this means you don't have a view for that response at &lt;code&gt;app/views/example/robots.text.erb&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Create the template and it should work. (But scan for any other templates you might have missed while you're at it.)&lt;/p&gt;

&lt;h3&gt;
  
  
  Unknown Format
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ActionController::UnknownFormat (ExampleController#robots is missing a template for this request format and variant.

request.formats: ["text/plain"]
request.variant: []):
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This means you received a request with a format that wasn't specified in your controller.&lt;/p&gt;

&lt;p&gt;You would get this error if your controller action supports xml and html, but you receive a request with an txt format.&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;def&lt;/span&gt; &lt;span class="nf"&gt;robots&lt;/span&gt;
        &lt;span class="n"&gt;respond_to&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="nb"&gt;format&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
            &lt;span class="nb"&gt;format&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;xml&lt;/span&gt;
            &lt;span class="nb"&gt;format&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;html&lt;/span&gt;
        &lt;span class="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;Find your controller action and either add the format to your list or specify a catchall with &lt;code&gt;format.any&lt;/code&gt;.&lt;/p&gt;

</description>
      <category>rails</category>
      <category>ruby</category>
      <category>webdev</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>How to Prevent Bot Spam on Your Ruby on Rails Website</title>
      <dc:creator>Nicholas Dill</dc:creator>
      <pubDate>Fri, 21 Oct 2022 15:08:37 +0000</pubDate>
      <link>https://dev.to/nicholasdill/how-to-prevent-bot-spam-on-your-ruby-on-rails-website-2nm0</link>
      <guid>https://dev.to/nicholasdill/how-to-prevent-bot-spam-on-your-ruby-on-rails-website-2nm0</guid>
      <description>&lt;p&gt;If you have an unprotected form on your website, bots are going to spam you.&lt;/p&gt;

&lt;p&gt;That's just how it works.&lt;/p&gt;

&lt;p&gt;Luckily, it's not hard at all to protect your forms and prevent this from happening.&lt;/p&gt;

&lt;p&gt;If you &lt;a href="https://testsuite.io/detect-bot-form-submissions"&gt;detect bot spam&lt;/a&gt;, there are 2 strategies that I've found most effective:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Using a honeypot&lt;/li&gt;
&lt;li&gt;Using a captcha tool&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A &lt;a href="https://en.wikipedia.org/wiki/Honeypot_(computing)"&gt;honeypot&lt;/a&gt; is essentially a trap for a bot, a fake field or key piece of information that gives away the fact that a human didn't submit that form. For example, an invisible field. If it was filled out, it was very likely not done by a human.&lt;/p&gt;

&lt;p&gt;Otherwise, you can rely on &lt;a href="https://www.google.com/recaptcha/about/"&gt;Google reCAPTCHA&lt;/a&gt;. But there are a few major drawbacks here. The first is performance, your site will be slower to load since it has to load Recaptcha scripts. And the second is the user experience, people generally hate having to do captchas, "click on all the sidewalks", those kinds of things.&lt;/p&gt;

&lt;p&gt;So ultimately I'm a bigger fan of the honeypot strategy, PLUS is way easier to build into a Rails app.&lt;/p&gt;




&lt;h2&gt;
  
  
  How to Create a Honeypot in Ruby on Rails
&lt;/h2&gt;

&lt;p&gt;A honeypot is a trap, something that a human can easily distinguish but a bot cannot.&lt;/p&gt;

&lt;p&gt;Take for example a form with fields for email and "leave this empty". A bot would likely not leave that field empty because it would not be able to understand the meaning of that label. A human would be much better at following directions and not inputting anything in that field.&lt;/p&gt;

&lt;p&gt;Boom you have a honeypot - granted this one is pretty bad and not a great user experience. &lt;/p&gt;

&lt;p&gt;But hopefully, it outlines how easy it can be to build.&lt;/p&gt;

&lt;h4&gt;
  
  
  BUILDING THE HONEYPOT FRONTEND
&lt;/h4&gt;

&lt;p&gt;Let's build off the above example but make it better.&lt;/p&gt;

&lt;p&gt;Here's a breakdown of the honeypot that this website uses. (And since enabling it we have not received a single bot submission on any of our forms.)&lt;/p&gt;

&lt;p&gt;We start with a normal form, we use &lt;code&gt;form_with&lt;/code&gt; but it doesn't matter how you build your form.&lt;/p&gt;

&lt;p&gt;All we have to do is add a field that should not be filled out, in this case a "hidden message":&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;form&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;email_field&lt;/span&gt; &lt;span class="ss"&gt;:hidden_message&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;placeholder: &lt;/span&gt;&lt;span class="s1"&gt;'Message'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;class: &lt;/span&gt;&lt;span class="s1"&gt;'hidden-message'&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;We give it the CSS class &lt;code&gt;hidden-message&lt;/code&gt; so that we can hide it on the page, but a bot that's just parsing our HTML will still find it and fill it out.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;hidden-message&lt;/code&gt; class is styled like this:&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="nc"&gt;.hidden-message&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="err"&gt;//&lt;/span&gt; &lt;span class="err"&gt;honeypot&lt;/span&gt; &lt;span class="err"&gt;form&lt;/span&gt; &lt;span class="err"&gt;field&lt;/span&gt;
  &lt;span class="nl"&gt;opacity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;position&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;absolute&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;top&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;left&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&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;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;z-index&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;-1&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 ensures it has 0 opacity, position absolute so it doesn't shift anything else in the DOM, and has no dimensions so it cannot be clicked on.&lt;/p&gt;

&lt;p&gt;We simply place this field into our form and are done with the frontend! (that was one line of code plus some optional CSS)&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;form_with&lt;/span&gt; &lt;span class="ss"&gt;url: &lt;/span&gt;&lt;span class="n"&gt;emails_index_path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;local: &lt;/span&gt;&lt;span class="kp"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;id: &lt;/span&gt;&lt;span class="s1"&gt;'email-form'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;class: &lt;/span&gt;&lt;span class="s1"&gt;'form'&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;form&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="cp"&gt;%&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;'field'&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="cp"&gt;&amp;lt;%=&lt;/span&gt; &lt;span class="n"&gt;form&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;email_field&lt;/span&gt; &lt;span class="ss"&gt;:hidden_message&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;placeholder: &lt;/span&gt;&lt;span class="s1"&gt;'Message'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;class: &lt;/span&gt;&lt;span class="s1"&gt;'hidden-message'&lt;/span&gt; &lt;span class="cp"&gt;%&amp;gt;&lt;/span&gt;
    &lt;span class="cp"&gt;&amp;lt;%=&lt;/span&gt; &lt;span class="n"&gt;form&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;email_field&lt;/span&gt; &lt;span class="ss"&gt;:email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;placeholder: &lt;/span&gt;&lt;span class="s1"&gt;'Enter your email'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;class: &lt;/span&gt;&lt;span class="s1"&gt;'input'&lt;/span&gt; &lt;span class="cp"&gt;%&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
  &lt;span class="c"&gt;&amp;lt;%#= form.submit 'Join', class: 'button' %&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;&amp;lt;%&lt;/span&gt; &lt;span class="k"&gt;end&lt;/span&gt; &lt;span class="cp"&gt;%&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  BUILDING THE HONEYPOT BACKEND
&lt;/h4&gt;

&lt;p&gt;Doing anything on the backend is optional now since you can simply filter out your bots by checking to see if the hidden message is filled out or not, but to make things easier you can avoid spam from even being processed and saved in your system.&lt;/p&gt;

&lt;p&gt;We have an endpoint that our email form points to which processes and saves subscribers.&lt;/p&gt;

&lt;p&gt;In order to filter out bot submissions, we just check for the presence of our honeypot field.&lt;/p&gt;

&lt;p&gt;Something like this:&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;redirect_to&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;referrer&lt;/span&gt; &lt;span class="k"&gt;if&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;:hidden_message&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;present?&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What that looks like inside of our form submission endpoint:&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;def&lt;/span&gt; &lt;span class="nf"&gt;emails&lt;/span&gt;
    &lt;span class="k"&gt;if&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;:hidden_message&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;present?&lt;/span&gt;
      &lt;span class="n"&gt;redirect_to&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;referrer&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;
      &lt;span class="c1"&gt;# Logic to handle the form submission&lt;/span&gt;
      &lt;span class="no"&gt;Email&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;email: &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;:email&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
      &lt;span class="n"&gt;redirect_to&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;referrer&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;And that's it!&lt;/p&gt;

&lt;p&gt;By taking an existing Rails form, we added a field and styled it so it was hidden and on the backend redirect you if you filled out the honeypot.&lt;/p&gt;




&lt;h2&gt;
  
  
  Important Points
&lt;/h2&gt;

&lt;p&gt;I prefer the honeypot strategy because it's much more performant, no fancy scripts to load or requests that affect your website's pageload speed. (Pageload has a big impact on user experience but also your SEO - it's important.)&lt;/p&gt;

&lt;p&gt;But do keep in mind, a honeypot is not perfect.&lt;/p&gt;

&lt;p&gt;First, is the issue with &lt;em&gt;accessibility&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;We literally created a field and visually hid it, meaning anyone using a screen reader or other tools will still come across it just as a bot would. This means it's important to name your field clearly and instruct the reader to not fill it out. A bot is going to be less likely to process these instructions correctly.&lt;/p&gt;

&lt;p&gt;And of course, if you are dealing with a direct attack (which is unlikely) the attacker could certainly add to their script and have the bot ignore your honeypot field.&lt;/p&gt;

&lt;p&gt;But the alternative is pulling in scripts and external third-party tools that will impact your site performance, user experience, and overall traffic so the decision is pretty clear to me!&lt;/p&gt;

&lt;p&gt;Good luck in your fight against the bots (and let's hope AI doesn't make this even harder on us in a few years).&lt;/p&gt;

</description>
      <category>ruby</category>
      <category>rails</category>
      <category>webdev</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>What's the Difference Between a Parameter and an Argument?</title>
      <dc:creator>Nicholas Dill</dc:creator>
      <pubDate>Fri, 13 May 2022 15:27:42 +0000</pubDate>
      <link>https://dev.to/nicholasdill/whats-the-difference-between-a-parameter-and-an-argument-3lhn</link>
      <guid>https://dev.to/nicholasdill/whats-the-difference-between-a-parameter-and-an-argument-3lhn</guid>
      <description>&lt;p&gt;I have an embarrassing confession.&lt;/p&gt;

&lt;p&gt;Until just recently, I was using &lt;em&gt;parameters&lt;/em&gt; and &lt;em&gt;arguments&lt;/em&gt; interchangeably when talking and pairing with other software developers on my team.&lt;/p&gt;

&lt;p&gt;Parameters and arguments are not the same things, but they are similar.&lt;/p&gt;

&lt;p&gt;Let's dig into the differences so you don't have to make the same embarrassing mistake as me.&lt;/p&gt;




&lt;h2&gt;
  
  
  Parameters vs Arguments
&lt;/h2&gt;

&lt;p&gt;A &lt;strong&gt;parameter&lt;/strong&gt; is a variable defined in a function definition. It is the variable that the function expects you to pass when it is called. These parameters define the variables that we can use throughout the rest of the function as well.&lt;/p&gt;

&lt;p&gt;An &lt;strong&gt;argument&lt;/strong&gt; is the value that we pass to the function when we call it. Arguments determine the value of the parameter variables in our function.&lt;/p&gt;

&lt;p&gt;They might still sound similar, so here's an example with code.&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;def&lt;/span&gt; &lt;span class="nf"&gt;adder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;adder&lt;/code&gt; function takes 2 parameters &lt;code&gt;x&lt;/code&gt; and &lt;code&gt;y&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;We can then call our &lt;code&gt;adder&lt;/code&gt; function and pass it 2 arguments.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;adder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="mi"&gt;5&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Since we passed the arguments &lt;code&gt;2&lt;/code&gt; and &lt;code&gt;3&lt;/code&gt; the body of the function will run, substituting its parameters with the arguments we supplied.&lt;/p&gt;




&lt;h2&gt;
  
  
  How Keyword Arguments Work
&lt;/h2&gt;

&lt;p&gt;Many programming languages, including Ruby, allow us to name parameters with specific keywords.&lt;/p&gt;

&lt;p&gt;This is useful for a number of reasons.&lt;/p&gt;

&lt;p&gt;When we call a function and pass arguments, our function depends on the order of our arguments.&lt;/p&gt;

&lt;p&gt;For example, if our function instead performed an operation like subtraction or division, the order of our arguments matters significantly.&lt;/p&gt;

&lt;p&gt;For example, if we called the below function with the arguments &lt;code&gt;divider(0,1)&lt;/code&gt; the result would be zero, but if we swap the order our function would raise an exception. (Can't divide by zero, unfortunately...)&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;def&lt;/span&gt; &lt;span class="nf"&gt;divider&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;to_f&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 keyword arguments, we can specify which parameter is which more clearly and when we call the function and pass arguments, the order no longer matters for our keyword arguments.&lt;/p&gt;

&lt;p&gt;If we changed our method to something like this:&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;def&lt;/span&gt; &lt;span class="nf"&gt;divider&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;numerator&lt;/span&gt;&lt;span class="p"&gt;:,&lt;/span&gt; &lt;span class="n"&gt;denominator&lt;/span&gt;&lt;span class="p"&gt;:)&lt;/span&gt;
  &lt;span class="n"&gt;numerator&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;denominator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;to_f&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then to call this method we have to include our keywords:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;divider&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;numerator: &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;denominator: &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="mi"&gt;0&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We could also reverse the order without raising an exception since our parameters are named.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;divider&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;denominator: &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;numerator: &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="mi"&gt;0&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Takeaways
&lt;/h2&gt;

&lt;p&gt;I bet most of your team doesn't know the difference between parameters and arguments.&lt;/p&gt;

&lt;p&gt;There's a subtle difference, but it's easy to understand once you see a few examples.&lt;/p&gt;

&lt;p&gt;Parameters tell us what the function will take, while arguments are the values we pass to a function when we call it.&lt;/p&gt;

&lt;p&gt;Parameters are like variable names, arguments tell us what their values are.&lt;/p&gt;

&lt;p&gt;The order of your parameters and arguments matter. But you can use keyword arguments to make order unnecessary and to more clearly name your arguments when you call your function.&lt;/p&gt;

</description>
      <category>beginners</category>
      <category>programming</category>
      <category>ruby</category>
      <category>rails</category>
    </item>
    <item>
      <title>How to Manage Null Constraints With Migrations in Ruby on Rails</title>
      <dc:creator>Nicholas Dill</dc:creator>
      <pubDate>Sun, 14 Nov 2021 15:47:22 +0000</pubDate>
      <link>https://dev.to/nicholasdill/how-to-manage-null-constraints-with-migrations-in-ruby-on-rails-1pih</link>
      <guid>https://dev.to/nicholasdill/how-to-manage-null-constraints-with-migrations-in-ruby-on-rails-1pih</guid>
      <description>&lt;p&gt;Ruby on Rails makes it easy to write migrations to modify your database schema.&lt;/p&gt;

&lt;p&gt;But null constraints are a topic that requires some special attention. If you don't handle null constraints properly, a poorly written migration can easily wreak havoc on your database and bring down your production server.&lt;/p&gt;

&lt;h3&gt;
  
  
  What is a Null Constraint?
&lt;/h3&gt;

&lt;p&gt;By default most databases allow you to store &lt;code&gt;NULL&lt;/code&gt; values in your table columns. Sometimes you might want to specify that a certain value has to exist, and you can apply a null constraint to enforce that. &lt;/p&gt;

&lt;p&gt;Then whenever a record attempts to save a &lt;code&gt;NULL&lt;/code&gt; value, the database transaction will roll back nicely and prevent it from doing so.&lt;/p&gt;




&lt;h2&gt;
  
  
  Adding a Column With a Null Constraint
&lt;/h2&gt;

&lt;p&gt;When you write a migration, you can specify null constraints whenever you add new columns.&lt;/p&gt;

&lt;p&gt;Using the &lt;code&gt;add_column&lt;/code&gt; helper, you can add the &lt;code&gt;null&lt;/code&gt; keyword argument to specify if the new column allows &lt;code&gt;NULL&lt;/code&gt; values or not. You have the option to add the &lt;code&gt;default&lt;/code&gt; keyword argument too if you need to define what the default value of this column should be. This will ensure that new records have a value even if you don't specify one, so they can abide by your null constraint.&lt;/p&gt;

&lt;p&gt;Here's how this might look:&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;add_column&lt;/span&gt; &lt;span class="ss"&gt;:articles&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:published&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:boolean&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;null: &lt;/span&gt;&lt;span class="kp"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;default: &lt;/span&gt;&lt;span class="kp"&gt;false&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will add a new &lt;code&gt;boolean&lt;/code&gt; column called &lt;code&gt;published&lt;/code&gt; to the &lt;code&gt;articles&lt;/code&gt; table. The &lt;code&gt;null: false&lt;/code&gt; parameter means this column does not allow &lt;code&gt;NULL&lt;/code&gt; values. The &lt;code&gt;default: false&lt;/code&gt; tells us this column will default to false whenever a value isn't specified.&lt;/p&gt;

&lt;p&gt;This is nice because we can guarantee this field will always be either true or false now. It can't be null because the database prevents it. I'd wager that you've probably caused or at least seen a bug from code that didn't handle null values correctly. &lt;/p&gt;

&lt;p&gt;Preventing them at the database level can significantly simplify your logic and save you from future bug squashing!&lt;/p&gt;




&lt;h2&gt;
  
  
  Creating a Table With Columns That Have Null Constraints
&lt;/h2&gt;

&lt;p&gt;If you are creating a new table, the syntax is similar. &lt;/p&gt;

&lt;p&gt;We will use the &lt;code&gt;create_table&lt;/code&gt; helper to define our table and columns.&lt;/p&gt;

&lt;p&gt;Then append the &lt;code&gt;null: false&lt;/code&gt; keyword argument to any column in your &lt;code&gt;create_table&lt;/code&gt; call. You can also add the &lt;code&gt;default:&lt;/code&gt; in the same way to define a default value on a column.&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;create_table&lt;/span&gt; &lt;span class="s2"&gt;"articles"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;force: &lt;/span&gt;&lt;span class="kp"&gt;true&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;t&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
  &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt; &lt;span class="s2"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="ss"&gt;null: &lt;/span&gt;&lt;span class="kp"&gt;false&lt;/span&gt;
  &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;text&lt;/span&gt; &lt;span class="s2"&gt;"body"&lt;/span&gt;
  &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;boolean&lt;/span&gt;  &lt;span class="s2"&gt;"published"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="ss"&gt;default: &lt;/span&gt;&lt;span class="kp"&gt;false&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Changing a Null Constraint on an Existing Column
&lt;/h2&gt;

&lt;p&gt;Removing null constraints on existing columns is no problem, but if we add a new null constraint we run into big problems.&lt;/p&gt;

&lt;p&gt;The thing about migrations is they need to be &lt;em&gt;reversible&lt;/em&gt;. &lt;/p&gt;

&lt;p&gt;You want to be able to roll them back. For example, let's say you pushed a new release to your production environment and later discovered some critical bugs. You want to be able to roll back that release to the prior version where everything worked.&lt;/p&gt;

&lt;p&gt;But if your migrations aren't reversible, you can't always do that.&lt;/p&gt;

&lt;p&gt;If we write a migration to allow null values, add a few records with null values, and then try to roll back the migration... that migration will fail since the table has null values and it can't enforce the new null constraint.&lt;/p&gt;

&lt;h3&gt;
  
  
  How to Write Reversible Null Constraint Migrations
&lt;/h3&gt;

&lt;p&gt;This is critically important, but also trivially easy most of the time.&lt;/p&gt;

&lt;p&gt;When we need to add a null constraint on a column, we just have to make sure that the column has a default value that we can use to replace the current &lt;code&gt;NULL&lt;/code&gt; values.&lt;/p&gt;

&lt;p&gt;In other words, if we specify that a column cannot have any null values, we have to replace every &lt;code&gt;NULL&lt;/code&gt; value with a not null value in order to apply that constraint.&lt;/p&gt;

&lt;p&gt;We can use the &lt;code&gt;change_column_null&lt;/code&gt; helper to update the null constraint on an existing column. It takes a few arguments and should look something like this:&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;def&lt;/span&gt; &lt;span class="nf"&gt;change&lt;/span&gt;
  &lt;span class="n"&gt;change_column_null&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:articles&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kp"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"Untitled"&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;Digging into the arguments:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Table name - &lt;code&gt;:articles&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Column name - &lt;code&gt;:name&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Null constraint, can this column be null?&lt;/li&gt;
&lt;li&gt;Default value, if this column no longer allows &lt;code&gt;NULL&lt;/code&gt;, what do we replace &lt;code&gt;NULL&lt;/code&gt; values with?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This migration is reversible and will let you add or remove null constraints with no issues.&lt;/p&gt;

&lt;h3&gt;
  
  
  Other Ways to Write Reversible Migrations
&lt;/h3&gt;

&lt;p&gt;I'll admit there is some Ruby magic happening in the example above.&lt;/p&gt;

&lt;p&gt;In a migration when you define the &lt;code&gt;change&lt;/code&gt; method, Active Record will try its best to roll back the migration just by doing the opposite. In other words, it knows when you call &lt;code&gt;add_column&lt;/code&gt; to pretty much call &lt;code&gt;remove_column&lt;/code&gt; on the roll back. The same is true for the &lt;code&gt;change_column_null&lt;/code&gt; method.&lt;/p&gt;

&lt;p&gt;There are cases where you can't write a reversible migration all in the &lt;code&gt;change&lt;/code&gt; method though. One example is if you need to do a data migration or backfill some data of some kind too.&lt;/p&gt;

&lt;p&gt;In these scenarios, it's best to refer to the older style of writing migrations.&lt;/p&gt;

&lt;h4&gt;
  
  
  The Up and Down Methods
&lt;/h4&gt;

&lt;p&gt;When you run a migration, say with &lt;code&gt;rake db:migrate&lt;/code&gt; or &lt;code&gt;rake db:migrate:rollback&lt;/code&gt;, under the hood your migration is either running the &lt;code&gt;up&lt;/code&gt; or &lt;code&gt;down&lt;/code&gt; case.&lt;/p&gt;

&lt;p&gt;You can also run &lt;code&gt;rake db:migrate:status&lt;/code&gt; to see which migrations are currently up or down (in other words which have run or not).&lt;/p&gt;

&lt;p&gt;If you're writing a migration that isn't reversible, it's best to fall back to defining the specific &lt;code&gt;up&lt;/code&gt; and &lt;code&gt;down&lt;/code&gt; methods instead of jamming everything into the &lt;code&gt;change&lt;/code&gt; method and relying on magic.&lt;/p&gt;

&lt;p&gt;Here's a quick example of the &lt;code&gt;up&lt;/code&gt; and &lt;code&gt;down&lt;/code&gt; methods:&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;def&lt;/span&gt; &lt;span class="nf"&gt;up&lt;/span&gt;
  &lt;span class="n"&gt;add_column&lt;/span&gt; &lt;span class="ss"&gt;:articles&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:published&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:boolean&lt;/span&gt;
  &lt;span class="n"&gt;rename_column&lt;/span&gt; &lt;span class="ss"&gt;:articles&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:featured&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:temporary_featured&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;down&lt;/span&gt;
  &lt;span class="n"&gt;rename_column&lt;/span&gt; &lt;span class="ss"&gt;:articles&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:temporary_featured&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:featured&lt;/span&gt;
  &lt;span class="n"&gt;remove_column&lt;/span&gt; &lt;span class="ss"&gt;:articles&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:published&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The idea is we explicitly tell the database how to roll back our migration with the &lt;code&gt;down&lt;/code&gt; method. We have more control over what happens.&lt;/p&gt;

&lt;p&gt;Thought most of the time &lt;code&gt;change&lt;/code&gt; is good enough!&lt;/p&gt;

</description>
      <category>ruby</category>
      <category>rails</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Understanding the Content-Type HTTP Header</title>
      <dc:creator>Nicholas Dill</dc:creator>
      <pubDate>Wed, 10 Nov 2021 04:18:16 +0000</pubDate>
      <link>https://dev.to/nicholasdill/understanding-the-content-type-http-header-3ejl</link>
      <guid>https://dev.to/nicholasdill/understanding-the-content-type-http-header-3ejl</guid>
      <description>&lt;p&gt;The &lt;code&gt;Content-Type&lt;/code&gt; header is used in web requests to indicate what type of media or resource is being used in the request or response.&lt;/p&gt;

&lt;p&gt;When you send data in a request such as PUT or POST, you pass the &lt;code&gt;Content-Type&lt;/code&gt; header to tell the server what type of data it is receiving. &lt;/p&gt;

&lt;p&gt;When you receive a response from a server, there will be a &lt;code&gt;Content-Type&lt;/code&gt; header as well. It tells the client what type of data is being returned so it knows how to process it.&lt;/p&gt;




&lt;h2&gt;
  
  
  Is Content-Type a required field?
&lt;/h2&gt;

&lt;p&gt;Nope, Content-Type is not a required field. It's not mandatory per the HTTP 1.1 specification.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec7.html#sec7.2.1"&gt;&lt;/a&gt;&lt;a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec7.html#sec7.2.1"&gt;http://www.w3.org/Protocols/rfc2616/rfc2616-sec7.html#sec7.2.1&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Any HTTP/1.1 message containing an entity-body SHOULD include a Content-Type header field defining the media type of that body. If and only if the media type is not given by a Content-Type field, the recipient MAY attempt to guess the media type via inspection of its content and/or the name extension(s) of the URI used to identify the resource. If the media type remains unknown, the recipient SHOULD treat it as type "application/octet-stream".&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Still, this can potentially cause problems and make it more difficult for the server to understand what it's receiving from you. To avoid any issues down the road, I suggest you pass this header along regardless.&lt;/p&gt;




&lt;h2&gt;
  
  
  Is Content-Type case sensitive?
&lt;/h2&gt;

&lt;p&gt;For your header field names, no.&lt;/p&gt;

&lt;p&gt;If you pass &lt;code&gt;Content-Type&lt;/code&gt; or &lt;code&gt;content-type&lt;/code&gt; or even something very creative like &lt;code&gt;Content-TYPE&lt;/code&gt;... it should work fine!&lt;/p&gt;

&lt;p&gt;From &lt;a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.2"&gt;&lt;/a&gt;&lt;a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.2"&gt;http://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.2&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;4.2 Message Headers&lt;/p&gt;

&lt;p&gt;HTTP header fields, which include general-header (section 4.5), request-header (section 5.3), response-header (section 6.2), and entity-header (section 7.1) fields, follow the same generic format as that given in Section 3.1 of RFC 822 [9]. Each header field consists of a name followed by a colon (":") and the field value. Field names are case-insensitive.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The parameter values you pass for this header can depend though.&lt;/p&gt;

&lt;p&gt;Generally, parameter values can be case sensitive and it depends on the value of the parameter.&lt;/p&gt;

&lt;p&gt;For example, the official &lt;a href="https://www.w3.org/TR/html4/charset.html#h-5.2.1"&gt;W3C specs&lt;/a&gt; state "Names for character encodings are case-insensitive". So, a &lt;code&gt;Content-Type: text/html; charset=UTF-8&lt;/code&gt; should be equivalent to &lt;code&gt;Content-Type: text/html; charset=utf-8&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;These recommendations may also change so I advise using the proper casing from the start so you can relax and not have to worry.&lt;/p&gt;




&lt;h2&gt;
  
  
  What is the difference between the Content-Type and Accept headers?
&lt;/h2&gt;

&lt;p&gt;First, the &lt;code&gt;Accept&lt;/code&gt; header is only used in requests (you probably won't see it in responses), while the &lt;code&gt;Content-Type&lt;/code&gt; is used in both requests and responses.&lt;/p&gt;

&lt;p&gt;This is because the &lt;code&gt;Accept&lt;/code&gt; header is used in a request to tell the server what the type of media in the response should be. &lt;/p&gt;

&lt;p&gt;It's like asking the server for information and telling it what kind of information you expect back.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;Content-Type&lt;/code&gt; header tells you what the type of media in the current request actually is. &lt;/p&gt;

&lt;p&gt;It's like sending the server a document that asks for information, and this header tells the server what type of document you gave them so they can read it properly.&lt;/p&gt;

&lt;h3&gt;
  
  
  Show me an example!
&lt;/h3&gt;

&lt;p&gt;If I post an image to a website, my &lt;code&gt;Content-Type&lt;/code&gt; header might be &lt;code&gt;image/jpeg&lt;/code&gt; because the media in this request is a jpeg image. My &lt;code&gt;Accept&lt;/code&gt; header would tell the website what kind of response I want back. If I don't care, my &lt;code&gt;Accept&lt;/code&gt; header would probably be &lt;code&gt;*/*&lt;/code&gt; which means anything works.&lt;/p&gt;

&lt;p&gt;When the website gets my post request with an image, I'll get a response from them. It too will have a &lt;code&gt;Content-Type&lt;/code&gt; header to tell me the type of their response. In this case, it is &lt;code&gt;application/json;charset=utf-8&lt;/code&gt; meaning their server responded with JSON.&lt;/p&gt;




&lt;h2&gt;
  
  
  What are the possible values of the Content-Type header?
&lt;/h2&gt;

&lt;p&gt;Well, there's a ton. Too many to list here, so I'll cover the most common types which will probably have what you need.&lt;/p&gt;

&lt;p&gt;If you're still curious though, here is the &lt;a href="https://www.iana.org/assignments/media-types/media-types.xhtml"&gt;list of all Content-Type headers&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Text Types
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;text/xml&lt;/li&gt;
&lt;li&gt;text/css
&lt;/li&gt;
&lt;li&gt;text/csv
&lt;/li&gt;
&lt;li&gt;text/html
&lt;/li&gt;
&lt;li&gt;text/plain
&lt;/li&gt;
&lt;li&gt;text/javascript &lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Images
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;image/gif
&lt;/li&gt;
&lt;li&gt;image/png
&lt;/li&gt;
&lt;li&gt;image/jpeg
&lt;/li&gt;
&lt;li&gt;image/svg+xml
&lt;/li&gt;
&lt;li&gt;image/tiff
&lt;/li&gt;
&lt;li&gt;image/x-icon
&lt;/li&gt;
&lt;li&gt;image/vnd.djvu
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Application Types
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;application/zip
&lt;/li&gt;
&lt;li&gt;application/pdf
&lt;/li&gt;
&lt;li&gt;application/xml
&lt;/li&gt;
&lt;li&gt;application/ogg
&lt;/li&gt;
&lt;li&gt;application/json
&lt;/li&gt;
&lt;li&gt;application/ld+json
&lt;/li&gt;
&lt;li&gt;application/EDI-X12
&lt;/li&gt;
&lt;li&gt;application/EDIFACT
&lt;/li&gt;
&lt;li&gt;application/javascript
&lt;/li&gt;
&lt;li&gt;application/xhtml+xml
&lt;/li&gt;
&lt;li&gt;application/java-archive &lt;/li&gt;
&lt;li&gt;application/octet-stream
&lt;/li&gt;
&lt;li&gt;application/x-shockwave-flash&lt;/li&gt;
&lt;li&gt;application/x-www-form-urlencoded
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Audio Types
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;audio/mpeg&lt;/li&gt;
&lt;li&gt;audio/x-wav&lt;/li&gt;
&lt;li&gt;audio/x-ms-wma&lt;/li&gt;
&lt;li&gt;audio/vnd.rn-realaudio&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Video Types
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;video/quicktime&lt;/li&gt;
&lt;li&gt;video/webm
&lt;/li&gt;
&lt;li&gt;video/mpeg
&lt;/li&gt;
&lt;li&gt;video/mp4
&lt;/li&gt;
&lt;li&gt;video/x-flv
&lt;/li&gt;
&lt;li&gt;video/x-msvideo&lt;/li&gt;
&lt;li&gt;video/x-ms-wmv&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Multipart Types
&lt;/h3&gt;

&lt;p&gt;These mean there are 2 or more pieces of content, each with their own type as well.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;multipart/mixed&lt;/li&gt;
&lt;li&gt;multipart/related&lt;/li&gt;
&lt;li&gt;multipart/form-data&lt;/li&gt;
&lt;li&gt;multipart/alternative&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>webdev</category>
      <category>programming</category>
    </item>
    <item>
      <title>How to Add a Canonical Link in HTML</title>
      <dc:creator>Nicholas Dill</dc:creator>
      <pubDate>Sun, 07 Nov 2021 16:20:00 +0000</pubDate>
      <link>https://dev.to/nicholasdill/how-to-add-a-canonical-link-in-html-4d4d</link>
      <guid>https://dev.to/nicholasdill/how-to-add-a-canonical-link-in-html-4d4d</guid>
      <description>&lt;p&gt;Canonical links are one of the most important parts of technical SEO.&lt;/p&gt;

&lt;p&gt;They help search engines understand how to handle duplicate content on your website. Without them, you might face duplicate content penalties that have a devastating impact on your rankings in search.&lt;/p&gt;

&lt;p&gt;Here is what we will cover:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Adding canonical links&lt;/li&gt;
&lt;li&gt;How they work&lt;/li&gt;
&lt;li&gt;When you should use them&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a id="canonical-links"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  How to Add Canonical Links to Your Website
&lt;/h2&gt;

&lt;p&gt;The canonical link belongs in the &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt; section of your website.&lt;/p&gt;

&lt;p&gt;This is what it looks like.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"canonical"&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"https://testsuite.io"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Placing this tag on a page tells search engines that the original copy of this content lives at the address listed in the &lt;code&gt;href&lt;/code&gt; attribute.&lt;/p&gt;

&lt;p&gt;Any links or ranking juice that was pointing to the current page will then be directed to the link supplied in your canonical tag.&lt;/p&gt;

&lt;p&gt;Now, you can have multiple similar pages. Instead of Google punishing you for duplicating content, all of your backlinks will be combined in a sense and boost the reputation of the original page.&lt;/p&gt;

&lt;p&gt;&lt;a id="how-canonical-links-work"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  How the Canonical Tag Works
&lt;/h2&gt;

&lt;p&gt;The HTML &lt;code&gt;&amp;lt;link&amp;gt;&lt;/code&gt; tag is a self-closing or empty tag. It expects you to supplier the &lt;code&gt;rel&lt;/code&gt; attribute and the &lt;code&gt;href&lt;/code&gt; attribute.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;rel&lt;/code&gt; attribute is used to tell the relationship between the document and the linked resources. In other words, we give the browser a link, it needs to know what to do with it. When we defined the link as &lt;code&gt;rel="canonical"&lt;/code&gt; search engines know how to respond.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;href&lt;/code&gt; attribute tells us the actual link to reference. If you're curious, it's short for Hypertext REFerence, and gives us a Hyperlink that can be followed by the Hypertext Transfer Protocol (HTTP).&lt;/p&gt;

&lt;p&gt;In short, the &lt;code&gt;&amp;lt;link&amp;gt;&lt;/code&gt; tag defines a relationship to an external resource (in our case the original source of content). &lt;/p&gt;

&lt;p&gt;The &lt;code&gt;rel="canonical"&lt;/code&gt; attribute tells us what type of relationship this resource has (it's a canonical link). &lt;/p&gt;

&lt;p&gt;And the &lt;code&gt;href="https://testsuite.io"&lt;/code&gt; tells us the external reference.&lt;/p&gt;

&lt;p&gt;&lt;a id="using-canonical-links"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  When to Use a Canonical Link
&lt;/h2&gt;

&lt;p&gt;My advice is to ALWAYS use a canonical link.&lt;/p&gt;

&lt;p&gt;Why you might ask?&lt;/p&gt;

&lt;p&gt;Because first, it doesn't hurt your search rankings. And second, you can't control what backlinks are created to your website.&lt;/p&gt;

&lt;p&gt;Let's dig into a real example from my search analytics.&lt;/p&gt;

&lt;h3&gt;
  
  
  Here's what happens when you don't use a canonical link.
&lt;/h3&gt;

&lt;p&gt;You can go use the &lt;a href="https://search.google.com/search-console/about"&gt;Google Search Console&lt;/a&gt; to analyze how your website is performing in search.&lt;/p&gt;

&lt;p&gt;It will show you all of your current issues and point out what needs to be fixed.&lt;/p&gt;

&lt;p&gt;When you click into the Coverage dashboard, you will probably see a number of links are excluded from search. If you dig into this list you will probably discover this error:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Duplicate without user-selected canonical&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This means Google discovered duplicate content that doesn't have the appropriate canonical tag.&lt;/p&gt;

&lt;p&gt;My problem was... this "duplicate content" was literally the same page as the original. It just had some query parameters at the end of the link.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://testsuite.io/send-emails-from-rails

vs

https://testsuite.io/send-emails-from-rails?ref=testsuite&amp;amp;filter=true
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is what I mean by users creating backlinks you have no control over.&lt;/p&gt;

&lt;p&gt;To fix this I just needed to make sure all of my articles had proper canonical links to themselves.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"canonical"&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"https://testsuite.io/send-emails-from-rails"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And now we're good, no more duplicate content issues!&lt;/p&gt;

&lt;p&gt;Adding a canonical tag to all of your pages will protect you from accidentally creating duplicate content. &lt;/p&gt;

&lt;p&gt;And in the long run, should have a significant impact on your search rankings.&lt;/p&gt;

</description>
      <category>html</category>
      <category>beginners</category>
      <category>webdev</category>
    </item>
    <item>
      <title>How to Add Custom Filters to Administrate Dashboards</title>
      <dc:creator>Nicholas Dill</dc:creator>
      <pubDate>Sat, 06 Nov 2021 01:46:40 +0000</pubDate>
      <link>https://dev.to/nicholasdill/how-to-add-custom-filters-to-administrate-dashboards-2gj6</link>
      <guid>https://dev.to/nicholasdill/how-to-add-custom-filters-to-administrate-dashboards-2gj6</guid>
      <description>&lt;p&gt;Administrate is one of my favorites Rails gems. &lt;/p&gt;

&lt;p&gt;It gives you a CRUD interface for your entire database in seconds.&lt;/p&gt;

&lt;p&gt;This means any admin user can log in and get access to our database records from the browser. They can create, read, update, or delete data without having to write any code, scripts, or SQL. (Don't worry you can limit which tables can be updated or deleted too.)&lt;/p&gt;

&lt;p&gt;One problem is Administrate doesn't come with any kind of filtering and it can be hard to find specific records or records that meet certain conditions. You can sort columns alphabetically but when you have large sets of data this really doesn't help much.&lt;/p&gt;

&lt;p&gt;There are a couple steps needed to add our own custom filters on top of Administrate, but its just a few new lines of code in a few places and I'll dive deep into why and how it works.&lt;/p&gt;

&lt;p&gt;If you want to skip the explanation and just want the code, it's right here.&lt;/p&gt;

&lt;h3&gt;
  
  
  What We Will Cover
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;How to apply custom filters to our Administrate data&lt;/li&gt;
&lt;li&gt;Storing filters in the user's session&lt;/li&gt;
&lt;li&gt;Passing query parameters to update the user's session&lt;/li&gt;
&lt;li&gt;Display the Administrate view using the current filters&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a id="filters"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  How to Filter Records in Administrate
&lt;/h2&gt;

&lt;p&gt;When we land on an Administrate page, the request is routed to an admin controller. &lt;/p&gt;

&lt;p&gt;Just like any other Rails controller, our admin controller is responsible for querying the database and passing this data to the view to render it on the page.&lt;/p&gt;

&lt;p&gt;Administrate gives us a method called &lt;code&gt;scoped_resource&lt;/code&gt;. This method pulls our data from the database and we can add additional conditions to filter out data or organize it in a different way. This method allows us to filter our query any way we like.&lt;/p&gt;

&lt;p&gt;Inside this method we see a variable called &lt;code&gt;resource_class&lt;/code&gt;. This is inferred from the controller you are looking at. For example, the Admin::UsersController references your User model so the &lt;code&gt;resource_class&lt;/code&gt; would evaluate to &lt;code&gt;Users.all&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Our solution will add a few lines of logic to this method so that we can filter our Administrate views based on variables that we set in the current user's session. &lt;/p&gt;

&lt;p&gt;If you aren't familiar with how session storage works within Rails, fear not. We'll jump into this next.&lt;/p&gt;

&lt;p&gt;Plus you can copy the code below and change it for your specific use case and it should work out of the box.&lt;/p&gt;

&lt;p&gt;Here's an example of the &lt;code&gt;scoped_resource&lt;/code&gt; method you will override in the controller.&lt;/p&gt;

&lt;p&gt;This example returns a query result that applies different filters based on the 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="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;scoped_resource&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;current_user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;super_admin?&lt;/span&gt;
    &lt;span class="n"&gt;resource_class&lt;/span&gt;
  &lt;span class="k"&gt;else&lt;/span&gt;
    &lt;span class="n"&gt;resource_class&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;private: &lt;/span&gt;&lt;span class="kp"&gt;false&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the above code we are saying if you are logged in as a super admin, Administrate should return all records. &lt;/p&gt;

&lt;p&gt;BUT if you aren't, only return records where the &lt;code&gt;private: false&lt;/code&gt; condition is met. &lt;/p&gt;

&lt;p&gt;In this example we're assuming the resource has a field called private and any records marked private are only viewable to super admin users.&lt;/p&gt;

&lt;p&gt;This is how you can apply filters to Administrate views. Add your desired conditions to this method and we will exclude any records that don't match.&lt;/p&gt;

&lt;p&gt;&lt;a id="session"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Storing Filters in the User's Session
&lt;/h2&gt;

&lt;p&gt;The previous example above demonstrates how to filter records in Administrate, but it's not dynamic. Meaning we can't click a button to turn this filter on or off. It's just tied to whether or not we are a super admin. &lt;/p&gt;

&lt;p&gt;In order to let users toggle certain filters we need to store some kind of on/off state somewhere. &lt;/p&gt;

&lt;p&gt;This is what Rails session storage is really good at.&lt;/p&gt;

&lt;p&gt;The Rails session is kind of like a dictionary or hash that every visitor gets. We can store and modify variables specific to each user.&lt;/p&gt;

&lt;h3&gt;
  
  
  How to Use Session Variables
&lt;/h3&gt;

&lt;p&gt;We can update the data stored in a user's session by accessing the session hash and updating the entry for a certain key or attribute.&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;session&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:filter_published&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kp"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This would update the &lt;code&gt;filter_published&lt;/code&gt; entry and set it to true only for this user.&lt;/p&gt;

&lt;p&gt;Since session storage uses a hash, we read from this hash as we would any other normal hash. It should look like this.&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;session&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:filter_published&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kp"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The last point I'll make here is that Rails session storage is a backend mechanism. In other words we have to hit the backend again or make an API call to update the user's session data.&lt;/p&gt;

&lt;p&gt;Let's wire up the frontend to set filters on the user's session on the backend.&lt;/p&gt;

&lt;p&gt;&lt;a id="query-params"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Passing Query Parameters to Update the User's Session
&lt;/h2&gt;

&lt;p&gt;For a quick recap, we can currently customize our Administrate views by modifying the query in the &lt;code&gt;scoped_resource&lt;/code&gt; method of our admin controller.&lt;/p&gt;

&lt;p&gt;We can also update the user's session to store and persist any custom filters that are enabled or disabled.&lt;/p&gt;

&lt;p&gt;Now we need to tell the backend which of our filters we want to toggle so we can make the expected change in the user's session.&lt;/p&gt;

&lt;h3&gt;
  
  
  Query Parameter Basics
&lt;/h3&gt;

&lt;p&gt;Query Parameters are the extra attributes added at the end of a URL. You have probably seen a link resembling something like &lt;code&gt;https://testsuite.io/send-emails-from-rails?ref=testsuite&amp;amp;view=focused&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;That link will route you to &lt;code&gt;https://testsuite.io/send-emails-from-rails&lt;/code&gt; but it also adds &lt;code&gt;?ref=testsuite&amp;amp;filter=true&lt;/code&gt;. The latter portion contains the query parameters.&lt;/p&gt;

&lt;p&gt;This tells the server to render the expected page but to take into account the &lt;code&gt;ref=testsuite&lt;/code&gt; and &lt;code&gt;filter=true&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;We can follow the same approach to pass our desired filters to Administrate so that we can customize our Administrate views.&lt;/p&gt;

&lt;h3&gt;
  
  
  How to Pass Query Parameters
&lt;/h3&gt;

&lt;p&gt;First, we need a link that appends our desired query parameters. &lt;/p&gt;

&lt;p&gt;If we use a Rails &lt;code&gt;link_to&lt;/code&gt; helper method it could look something like this:&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;link_to&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Published Filter'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;admin_blog_posts_path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;published: &lt;/span&gt;&lt;span class="kp"&gt;true&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="ss"&gt;class: &lt;/span&gt;&lt;span class="s1"&gt;'admin-filter'&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;This will generate a link with the text "Published Filter".&lt;br&gt;
The link will point to the &lt;code&gt;admin_blog_posts_path&lt;/code&gt; which evaluates to &lt;code&gt;/admin/blog_posts&lt;/code&gt;.&lt;br&gt;
Our route helper, the &lt;code&gt;admin_blog_posts_path(published: true)&lt;/code&gt; also passes the &lt;code&gt;published: true&lt;/code&gt; key/value pair - those are the query parameters!&lt;/p&gt;

&lt;p&gt;The resulting HTML would look something like this:&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="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"/admin/blog_posts?published=true"&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"admin--filter"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  Published Filter
&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And now we have a link that we can click to view our blog posts (or whatever model you desire to add custom filters to in Administrate).&lt;/p&gt;

&lt;p&gt;If we want to allow multiple types of filters or add buttons to apply custom ordering, we can add more buttons that pass different query parameters.&lt;/p&gt;

&lt;p&gt;&lt;a id="applying-filters"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Display the Administrate view using the current filters
&lt;/h2&gt;

&lt;p&gt;Now that we are passing our query parameters to the backend, our controller can save our filters in the user's session.&lt;/p&gt;

&lt;p&gt;In the admin controller that we are filtering, we need to save our query parameters in the user's session storage. It is as easy as updating the session hash with the desired key and value.&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;session&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:published&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&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;:published&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;unless&lt;/span&gt; &lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:published&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;blank?&lt;/span&gt;
&lt;span class="c1"&gt;# Save the published filter to the user's session if it was passed as a query parameter&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can use the same strategy to clear and erase our current filters too:&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;session&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:published&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kp"&gt;nil&lt;/span&gt; &lt;span class="k"&gt;if&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;:clear&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="c1"&gt;# Erase and reset our filter if we pass the clear=true query parameter&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now everything should be wired correctly and we can get back to the &lt;code&gt;scoped_resource&lt;/code&gt; method. This is were it all started and now we have the buttons and session storage setup to persist any filters that we want to set.&lt;/p&gt;

&lt;p&gt;To apply a custom filter on our Administrate view, we need to check if we saved a value in the user's session storage.&lt;/p&gt;

&lt;p&gt;The below example shows how to check the session storage, and modify the &lt;code&gt;resource_class&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;scoped_resource&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:published&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;resource_class&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;published: &lt;/span&gt;&lt;span class="kp"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;else&lt;/span&gt;
    &lt;span class="n"&gt;resource_class&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 look up the published attribute in the user's session storage and if &lt;code&gt;session[:published]&lt;/code&gt; evaluates to true, then we apply the &lt;code&gt;.where(published: true)&lt;/code&gt; condition to our database query. Otherwise, we pull the data normally and nothing is filtered.&lt;/p&gt;

&lt;p&gt;&lt;a id="solution"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Final Solution
&lt;/h2&gt;

&lt;p&gt;Here's all the code without diving into explanations.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Add buttons to your Administrate view that append the desired filters as query parameters
&lt;/h3&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;link_to&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Published'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;admin_blog_posts_path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;published: &lt;/span&gt;&lt;span class="kp"&gt;true&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="ss"&gt;class: &lt;/span&gt;&lt;span class="s1"&gt;'admin--filter'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="cp"&gt;%&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;&amp;lt;%=&lt;/span&gt; &lt;span class="n"&gt;link_to&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Clear Filters'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;admin_blog_posts_path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;clear: &lt;/span&gt;&lt;span class="kp"&gt;true&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="ss"&gt;class: &lt;/span&gt;&lt;span class="s1"&gt;'admin--filter'&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;h3&gt;
  
  
  2. Save the query parameters to the user's session
&lt;/h3&gt;

&lt;p&gt;This code can live in the admin controller that you are calling. Be sure to call it before &lt;code&gt;scoped_resource&lt;/code&gt; so that we update the session before we apply any filters.&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;session&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:published&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kp"&gt;nil&lt;/span&gt; &lt;span class="k"&gt;if&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;:clear&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="c1"&gt;# Erase and reset our filter if we pass the clear=true query parameter&lt;/span&gt;

&lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:published&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&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;:published&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;unless&lt;/span&gt; &lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:published&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;blank?&lt;/span&gt;
&lt;span class="c1"&gt;# Save the published filter to the user's session if it was passed as a query parameter&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3. Apply the filters to the &lt;code&gt;scoped_resource&lt;/code&gt; method
&lt;/h3&gt;

&lt;p&gt;Inside of our &lt;code&gt;scoped_resource&lt;/code&gt; method, we can check for any filters we saved in our session and apply them to our query.&lt;/p&gt;

&lt;p&gt;This will apply a custom filter on our Administrate view and only show us resources that have their published field set to true.&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;def&lt;/span&gt; &lt;span class="nf"&gt;scoped_resource&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:published&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;resource_class&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;published: &lt;/span&gt;&lt;span class="kp"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;else&lt;/span&gt;
    &lt;span class="n"&gt;resource_class&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;h2&gt;
  
  
  Optional: Style buttons
&lt;/h2&gt;

&lt;p&gt;Typically Administrate interfaces are only used by your internal team. &lt;/p&gt;

&lt;p&gt;It's intended for administrative users so the design might not be a high priority, but you can make your filter buttons look good with just a few lines of CSS. Here's a class you can paste into your project.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;style&amp;gt;&lt;/span&gt;
  &lt;span class="nc"&gt;.admin--filter&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;text-decoration&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;none&lt;/span&gt; &lt;span class="cp"&gt;!important&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;5px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;10px&lt;/span&gt; &lt;span class="m"&gt;20px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;background-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#f3f6f9&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/style&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Your Administrate controller isn't going to import your stylesheet by default since it doesn't extend your normal page layout in &lt;code&gt;views/layouts/application.html.erb&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;This layout is typically imported by all your other views and sets up basic things like your meta tags, font imports, and your CSS stylesheets. But since Administrate doesn't extend your &lt;code&gt;application_controller.html.erb&lt;/code&gt; it also doesn't inherit this layout. So your normal fonts and styles won't be accessible on any of your Administrate views.&lt;/p&gt;

&lt;p&gt;A couple of ways around this are to either explicitly add this layout to your Administrate controllers, or to add these styles directly to your Administrate views.&lt;/p&gt;

&lt;p&gt;I find the approach with views faster and easier (granted perhaps not the best long-term solution).&lt;/p&gt;

&lt;p&gt;You have to override the default Administrate view anyway to add your filter buttons so sprinkling in a little bit of CSS in the same view isn't a big deal.&lt;/p&gt;

</description>
      <category>ruby</category>
      <category>rails</category>
    </item>
    <item>
      <title>How to Export to CSV with Ruby on Rails</title>
      <dc:creator>Nicholas Dill</dc:creator>
      <pubDate>Thu, 04 Nov 2021 16:41:08 +0000</pubDate>
      <link>https://dev.to/nicholasdill/how-to-export-to-csv-with-ruby-on-rails-2igm</link>
      <guid>https://dev.to/nicholasdill/how-to-export-to-csv-with-ruby-on-rails-2igm</guid>
      <description>&lt;p&gt;So, you need to export a CSV.&lt;/p&gt;

&lt;p&gt;As with everything in Ruby on Rails, it's really easy to do this. &lt;/p&gt;

&lt;p&gt;I will walk through how I built this feature to export sales leads on another Rails app of mine. But this same approach can be applied to any data you want to export as a CSV file.&lt;/p&gt;

&lt;p&gt;We are going to build an endpoint that a user can navigate to, that will trigger a download of the CSV file.&lt;/p&gt;

&lt;p&gt;The idea is, they land on a route like this &lt;code&gt;https://example.com/export/leads.csv&lt;/code&gt; and we start a download instead of rendering a normal page.&lt;/p&gt;

&lt;h2&gt;
  
  
  Create the Route
&lt;/h2&gt;

&lt;p&gt;First we need to create a route that we point the user to.&lt;/p&gt;

&lt;p&gt;Add something like this to your &lt;code&gt;config/routes.rb&lt;/code&gt; file:&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;get&lt;/span&gt; &lt;span class="s1"&gt;'leads/export'&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;'leads#export'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Change the name of your controller to whatever you want. Same with the method name. I went with &lt;code&gt;export&lt;/code&gt; because that makes it clear what this method is responsible for.&lt;/p&gt;

&lt;h2&gt;
  
  
  Create the Controller
&lt;/h2&gt;

&lt;p&gt;Rails will expect the leads controller to be defined at &lt;code&gt;app/controllers/leads_controller.rb&lt;/code&gt;, let's create that.&lt;/p&gt;

&lt;p&gt;Initially, the contents of this controller should look something like this.&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="s1"&gt;'csv'&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;LeadsController&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ApplicationController&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;export&lt;/span&gt;
    &lt;span class="vi"&gt;@leads&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Leads&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;organization_id: &lt;/span&gt;&lt;span class="n"&gt;current_user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;organization_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;respond_to&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="nb"&gt;format&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
      &lt;span class="nb"&gt;format&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;csv&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
        &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'Content-Type'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'text/csv'&lt;/span&gt;
        &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'Content-Disposition'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"attachment; filename=leads.csv"&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;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We need our &lt;code&gt;export&lt;/code&gt; method to do a few things here.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;pull data from the database&lt;/li&gt;
&lt;li&gt;convert our data into a CSV file&lt;/li&gt;
&lt;li&gt;format the response so we download the CSV&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;First let's pull the data. We'll need to build a query and save the results to an instance variable.&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="vi"&gt;@leads&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Leads&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;organization_id: &lt;/span&gt;&lt;span class="n"&gt;current_user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;organization_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next we have to convert the result of this query into the CSV format.&lt;/p&gt;

&lt;p&gt;At the top of our controller let's import the built-in Rails &lt;code&gt;csv&lt;/code&gt; library:&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="s1"&gt;'csv'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And now we can format our controller to respond when CSV is requested. Rails uses the &lt;code&gt;respond_to&lt;/code&gt; method to allow controller endpoints to respond to multiple formats. You will see a lot of endpoints that respond with HTML, JSON, and even XML.&lt;/p&gt;

&lt;p&gt;Here's what those formats would normally look like.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;respond_to&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="nb"&gt;format&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
    &lt;span class="nb"&gt;format&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;html&lt;/span&gt;
    &lt;span class="nb"&gt;format&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;render&lt;/span&gt; &lt;span class="ss"&gt;json: &lt;/span&gt;&lt;span class="vi"&gt;@leads&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;to_json&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nb"&gt;format&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;xml&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;render&lt;/span&gt; &lt;span class="ss"&gt;xml: &lt;/span&gt;&lt;span class="vi"&gt;@leads&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;to_xml&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;We'll need to slightly modify this to return CSV data.&lt;/p&gt;

&lt;p&gt;Our version will instead respond to &lt;code&gt;format.csv&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;respond_to&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="nb"&gt;format&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
  &lt;span class="nb"&gt;format&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;csv&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'Content-Type'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'text/csv'&lt;/span&gt;
    &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'Content-Disposition'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"attachment; filename=leads.csv"&lt;/span&gt;
    &lt;span class="n"&gt;render&lt;/span&gt; &lt;span class="ss"&gt;template: &lt;/span&gt;&lt;span class="s2"&gt;"path/to/index.csv.erb"&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;This means when someone makes a request to our URL, which was &lt;code&gt;https://example.com/export/leads.csv&lt;/code&gt;, the tailing &lt;code&gt;leads.csv&lt;/code&gt; extension tells our server to respond with the csv format.&lt;/p&gt;

&lt;p&gt;Also, these &lt;a href="https://testsuite.io/content-type-header"&gt;Content-Type headers&lt;/a&gt; tell the browser that we are returning a CSV file to download.&lt;/p&gt;

&lt;h2&gt;
  
  
  Building the CSV File
&lt;/h2&gt;

&lt;p&gt;Our backend is fully wired up to export CSV for the user.&lt;/p&gt;

&lt;p&gt;Now we need to generate the actual CSV file. The controller will automatically render the template found at &lt;code&gt;app/views/leads/export.csv.erb&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;Let's create that, and then here's what it will look like:&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;headers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'Email'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'Date'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="cp"&gt;-%&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;&amp;lt;%=&lt;/span&gt; &lt;span class="no"&gt;CSV&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;generate_line&lt;/span&gt; &lt;span class="n"&gt;headers&lt;/span&gt; &lt;span class="cp"&gt;%&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;&amp;lt;%-&lt;/span&gt; &lt;span class="vi"&gt;@leads&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;each&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;lead&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="cp"&gt;-%&amp;gt;&lt;/span&gt;
  &lt;span class="cp"&gt;&amp;lt;%=&lt;/span&gt; &lt;span class="no"&gt;CSV&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;generate_line&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="n"&gt;lead&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'email'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;lead&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;created_at&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="cp"&gt;-%&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;&amp;lt;%-&lt;/span&gt; &lt;span class="k"&gt;end&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;Formatting a CSV file is very straightforward in Rails. We just need to call &lt;code&gt;CSV.generate_line&lt;/code&gt; to add a row.&lt;/p&gt;

&lt;p&gt;First we declare a variable called &lt;code&gt;headers&lt;/code&gt;, and store the headers of our CSV file.&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;headers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'Email'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'Date'&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;Next we generate the first row for these headers with this call:&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="no"&gt;CSV&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;generate_line&lt;/span&gt; &lt;span class="n"&gt;headers&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;And last, we loop through our query result and again generate a row for each lead:&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="vi"&gt;@leads&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;each&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;lead&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="cp"&gt;-%&amp;gt;&lt;/span&gt;
  &lt;span class="cp"&gt;&amp;lt;%=&lt;/span&gt; &lt;span class="no"&gt;CSV&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;generate_line&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="n"&gt;lead&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'email'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;lead&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;created_at&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="cp"&gt;-%&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;&amp;lt;%-&lt;/span&gt; &lt;span class="k"&gt;end&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;And that's it. &lt;/p&gt;

&lt;p&gt;Now we have an endpoint that a user can access to download their data as a CSV. You can point users to this endpoint with a button and the download should begin automatically.&lt;/p&gt;

&lt;p&gt;Something like this should do the trick!&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="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"/leads/export.csv"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Export CSV&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Of course, replace the query I used and pull whatever records you want in your controller.&lt;/p&gt;

&lt;p&gt;Pass &lt;code&gt;CSV.generate_line()&lt;/code&gt; as many arguments as you want columns, and don't forget to pass headers in the first line to match!&lt;/p&gt;

</description>
      <category>ruby</category>
      <category>rails</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Ruby on Rails is Definitely Dead... Right?</title>
      <dc:creator>Nicholas Dill</dc:creator>
      <pubDate>Mon, 01 Nov 2021 15:40:30 +0000</pubDate>
      <link>https://dev.to/nicholasdill/ruby-on-rails-is-definitely-dead-right-954</link>
      <guid>https://dev.to/nicholasdill/ruby-on-rails-is-definitely-dead-right-954</guid>
      <description>&lt;p&gt;Let's get straight to the answer. Rails is not dead. It is anything but dead.&lt;/p&gt;

&lt;p&gt;Ruby on Rails is more alive than ever with a growing community and more contributors to the open-source project than I've ever seen.&lt;/p&gt;

&lt;p&gt;The project has been improving at a lightning-fast rate too, with almost back-to-back releases of new versions of Rails 5, 6, and 7.&lt;/p&gt;

&lt;p&gt;I'm a Rails developer so take this with a grain of salt, but out of all the languages I've used nothing is quite as enjoyable and easier to build with than Ruby on Rails.&lt;/p&gt;




&lt;h2&gt;
  
  
  Rails Developers are In Demand
&lt;/h2&gt;

&lt;p&gt;It's never been a better time to be a Ruby developer.&lt;/p&gt;

&lt;p&gt;Ruby on Rails developers are highly demanded and well compensated. The average salary for a rails developer is &lt;a href="https://www.talent.com/salary?job=ruby+on+rails+developer"&gt;over $120K&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;And Ruby is one of the easiest and most flexible languages to learn in my opinion.&lt;/p&gt;

&lt;p&gt;It's optimized for developer happiness and rapid feature development. You can literally create a blog from scratch in 5 minutes. &lt;/p&gt;

&lt;p&gt;It's also one of the most popular frameworks used by new and emerging companies. Which is also an excellent opportunity for anyone who wants the opportunity to get early equity in a company before they take off. This is one of my favorite benefits actually.&lt;/p&gt;




&lt;h2&gt;
  
  
  What Companies Use Ruby on Rails?
&lt;/h2&gt;

&lt;p&gt;If you hear someone say nobody uses Rails, don't get upset! They are oblivious to the benefits of Ruby on Rails and this is an opportunity help them learn about this amazing framework and its potential!&lt;/p&gt;

&lt;p&gt;The fact is many major companies use Rails for their production website.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Shopify&lt;/li&gt;
&lt;li&gt;Netflix&lt;/li&gt;
&lt;li&gt;Hulu&lt;/li&gt;
&lt;li&gt;Github&lt;/li&gt;
&lt;li&gt;Groupon&lt;/li&gt;
&lt;li&gt;Zendesk&lt;/li&gt;
&lt;li&gt;Airbnb&lt;/li&gt;
&lt;li&gt;Fiverr&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Just to name a few...&lt;/p&gt;

&lt;p&gt;Even &lt;a href="https://dev.to/ben/the-devto-tech-stack"&gt;Dev.to&lt;/a&gt; is powered by Ruby on Rails!&lt;/p&gt;

&lt;p&gt;And it's one of the best frameworks for new companies and startups to pick up. It lets you build a product faster than any other framework out there.&lt;/p&gt;


&lt;blockquote&gt;
&lt;p&gt;Internet: Ruby doesn’t scale.&lt;br&gt;Ruby: Sorry. I’m busy over here processing $1.5M+ USD Gross Merchant Value (GMV) per minute and 14K+ orders per minute running global &lt;a href="https://twitter.com/hashtag/BFCM?src=hash&amp;amp;ref_src=twsrc%5Etfw"&gt;#BFCM&lt;/a&gt; with &lt;a href="https://twitter.com/ShopifyEng?ref_src=twsrc%5Etfw"&gt;@ShopifyEng&lt;/a&gt;. &lt;a href="https://twitter.com/hashtag/ruby?src=hash&amp;amp;ref_src=twsrc%5Etfw"&gt;#ruby&lt;/a&gt; &lt;a href="https://twitter.com/hashtag/scale?src=hash&amp;amp;ref_src=twsrc%5Etfw"&gt;#scale&lt;/a&gt; 💪💪💪 &lt;a href="https://twitter.com/hashtag/lifeatshopify?src=hash&amp;amp;ref_src=twsrc%5Etfw"&gt;#lifeatshopify&lt;/a&gt; &lt;a href="https://t.co/O7GOblzcbv"&gt;&lt;/a&gt;&lt;a href="https://t.co/O7GOblzcbv"&gt;https://t.co/O7GOblzcbv&lt;/a&gt; &lt;a href="https://t.co/mQKg2uCxvH"&gt;pic.twitter.com/mQKg2uCxvH&lt;/a&gt;&lt;/p&gt;— Lawrence Mandel (@mmmandel) &lt;a href="https://twitter.com/mmmandel/status/1200585514463698944?ref_src=twsrc%5Etfw"&gt;November 30, 2019&lt;/a&gt;
&lt;/blockquote&gt; 


&lt;h2&gt;
  
  
  Understand What Rails is Best For
&lt;/h2&gt;

&lt;p&gt;Every programming language and web development framework has pros and cons that make it better and worse at doing certain things.&lt;/p&gt;

&lt;p&gt;Rails is no different.&lt;/p&gt;

&lt;p&gt;You should not use Ruby on Rails to build certain types of applications.&lt;/p&gt;

&lt;p&gt;But similarly there are certain types of projects where it is without a doubt the absolute best tool for your team.&lt;/p&gt;

&lt;p&gt;The most important thing to consider when you're choosing your development stack, is what you need to get out of it. Consider the features you need to implement. Balance the pros and cons of the technologies you are considering using.&lt;/p&gt;

&lt;p&gt;Fine, Rails won't be the best choice for everything. Often companies adopt Rails for the things it really excels at, and pull in other technologies for the things they excel at. There's no reason you can't pull in Rails to build your website and develop features rapidly. Then connect it to micro-services in Go or Java or whatever language you need to do your other fancy stuff.&lt;/p&gt;

&lt;p&gt;Ultimately, Rails is definitely not dead.&lt;/p&gt;

&lt;p&gt;And if your team is considering Ruby on Rails... I would highly, highly, highly recommend it.&lt;/p&gt;

</description>
      <category>ruby</category>
      <category>rails</category>
      <category>programming</category>
    </item>
    <item>
      <title>Don't Get Hacked: How to Prevent SQL Injection Attacks in Your Ruby on Rails Application</title>
      <dc:creator>Nicholas Dill</dc:creator>
      <pubDate>Sun, 31 Oct 2021 16:48:11 +0000</pubDate>
      <link>https://dev.to/nicholasdill/dont-get-hacked-how-to-prevent-sql-injection-attacks-in-your-ruby-on-rails-application-1cn1</link>
      <guid>https://dev.to/nicholasdill/dont-get-hacked-how-to-prevent-sql-injection-attacks-in-your-ruby-on-rails-application-1cn1</guid>
      <description>&lt;p&gt;Ruby on Rails gives you a lot of tools to protect against &lt;a href="https://testsuite.io/how-sql-injection-works"&gt;SQL injection attacks&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Input sanitization is the most important tool for preventing SQL injection in your database. And Active Record automatically does this when you use it correctly. But that's the key, &lt;em&gt;you have to use it correctly&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;So here's a guide on how to use Active Record to avoid exposing your database to SQL injection.&lt;/p&gt;




&lt;h2&gt;
  
  
  A Quick Introduction to SQL Injection
&lt;/h2&gt;

&lt;p&gt;SQL injection vulnerabilities are caused by code that passes any form of user input directly to the database.&lt;/p&gt;

&lt;p&gt;Here's a quick example.&lt;/p&gt;

&lt;p&gt;Let's say you want to create an account on a new website. This site happens to be vulnerable to SQL injection. &lt;/p&gt;

&lt;p&gt;You could set your email to something odd, 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;hello@example.com';update users set password='password'--
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At some point in the future, that website runs a query and passes your email to the database.&lt;/p&gt;

&lt;p&gt;That query might look something like this:&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;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="no"&gt;FROM&lt;/span&gt; &lt;span class="s2"&gt;"users"&lt;/span&gt; &lt;span class="no"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'hello@example.com'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="n"&gt;update&lt;/span&gt; &lt;span class="n"&gt;users&lt;/span&gt; &lt;span class="n"&gt;set&lt;/span&gt; &lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'password'&lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Can you guess what this might do?... 🤔&lt;/p&gt;

&lt;p&gt;Yeah, it's going to set every single user's password to "password"... not good.&lt;/p&gt;

&lt;p&gt;This is why we need to talk about SQL injection.&lt;/p&gt;

&lt;p&gt;It's a devastating vulnerability.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sanitize Inputs to Prevent SQL Injection
&lt;/h2&gt;

&lt;p&gt;Preventing SQL injection is easy.&lt;/p&gt;

&lt;p&gt;All you need to do is sanitize user inputs. This means taking any strings that users give you and escaping special characters that you don't want to send directly to the database.&lt;/p&gt;

&lt;p&gt;Using the example above &lt;code&gt;hello@example.com';update users set password='password'--&lt;/code&gt;...&lt;/p&gt;

&lt;p&gt;We want to make sure users cannot pass characters, like single quotes, to terminate the intended input string early. &lt;/p&gt;

&lt;p&gt;That's what's letting the rest of their input get interpreted as SQL.&lt;/p&gt;




&lt;h2&gt;
  
  
  Active Record and Input Sanitization
&lt;/h2&gt;

&lt;p&gt;The best part about using an ORM like Active Record, is that it handles all of this for you.&lt;/p&gt;

&lt;p&gt;The caveat is that you have to use it how it was intended.&lt;/p&gt;

&lt;h3&gt;
  
  
  Writing Active Record Queries Correctly
&lt;/h3&gt;

&lt;p&gt;When we build queries in Active Record, we usually pass conditions in our &lt;code&gt;.where()&lt;/code&gt; method.&lt;/p&gt;

&lt;p&gt;Active Record supports 3 ways of supplying these conditions. Pure strings, array conditions, and hash conditions. Generally, Active Record will automatically sanitize inputs passed using arrays or hashes.&lt;/p&gt;

&lt;p&gt;But pure string conditions are vulnerable to SQL injection.&lt;/p&gt;

&lt;p&gt;&lt;a id="#pure-string-conditions"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  A Deep Dive into Pure Strings Conditions
&lt;/h3&gt;

&lt;p&gt;A &lt;a href="https://edgeguides.rubyonrails.org/active_record_querying.html#pure-string-conditions"&gt;pure string condition&lt;/a&gt; is used when you pass SQL directly to the Active Record &lt;code&gt;.where()&lt;/code&gt; method.&lt;/p&gt;

&lt;p&gt;It will usually look something like this:&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;Post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"category = 'books'"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is vulnerable to SQL injection because there is no input sanitization happening. Rails is not going to escape this string because it would break the underlying SQL instruction.&lt;/p&gt;

&lt;p&gt;The above example doesn't pass user input to the database, but we would introduce a vulnerability if we did something like this:&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;Post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"category = &lt;/span&gt;&lt;span class="si"&gt;#{&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;:category&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this example, if we pull the &lt;code&gt;params[:category]&lt;/code&gt; from the URL, a user could attack our database by adjusting the value in the URL 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;https://example.com/products?category=books'+OR+1=1--
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And that value would be passed to our Active Record query and result in a SQL injection attack.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;products&lt;/span&gt; &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;category&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'books'&lt;/span&gt; &lt;span class="k"&gt;OR&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="c1"&gt;--'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This example is probably harmless since the &lt;code&gt;OR 1=1&lt;/code&gt; condition just means our query will expose all rows.&lt;/p&gt;

&lt;p&gt;But an attacker could just as easily add a nasty &lt;code&gt;INSERT&lt;/code&gt; or &lt;code&gt;UPDATE&lt;/code&gt; command to modify our database.&lt;/p&gt;

&lt;p&gt;The takeaway is pretty simple...&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Never use string interpolation to pass variables to pure string conditions.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;When you need to do so, use a different strategy for passing conditions like array conditions or hash conditions.&lt;/p&gt;

&lt;p&gt;&lt;a id="#array-conditions"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Array Conditions
&lt;/h3&gt;

&lt;p&gt;Array conditions prevent SQL injection in Active Record. &lt;/p&gt;

&lt;p&gt;They work like this.&lt;/p&gt;

&lt;p&gt;Like a pure string condition, pass the SQL condition as the first argument to the &lt;code&gt;.where()&lt;/code&gt; method, but pass any variables or user input as additional arguments.&lt;/p&gt;

&lt;p&gt;The first parameter will still contain a string of SQL, but Active Record will sanitize your additional arguments to prevent SQL injection.&lt;/p&gt;

&lt;p&gt;It should look like this:&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;Post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"category = ?"&lt;/span&gt;&lt;span class="p"&gt;,&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;:category&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Active Record will then replace every &lt;code&gt;?&lt;/code&gt; in your query with the arguments it was given.&lt;/p&gt;

&lt;p&gt;You can use this approach with as many arguments as you need.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Using multiple variables&lt;/span&gt;
&lt;span class="no"&gt;Post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"category = ? AND published = ?"&lt;/span&gt;&lt;span class="p"&gt;,&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;:category&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="kp"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Active Record will replace each &lt;code&gt;?&lt;/code&gt; with each supplied argument in the order they were given.&lt;/p&gt;

&lt;p&gt;&lt;a id="#hash-conditions"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Hash Conditions
&lt;/h3&gt;

&lt;p&gt;Active Record also lets you pass your conditions as a hash to avoid writing SQL entirely.&lt;/p&gt;

&lt;p&gt;This prevents SQL injection and automatically escapes user input, making it probably the safest way to build queries in Active Record.&lt;/p&gt;

&lt;p&gt;Hash conditions look like this:&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;Post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;category: &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;:category&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We don't write any SQL and the value of &lt;code&gt;params[:category]&lt;/code&gt; will be sanitized. We should have nothing to worry about!&lt;/p&gt;




&lt;h2&gt;
  
  
  Active Record Best Practices
&lt;/h2&gt;

&lt;p&gt;Use hash conditions whenever possible. Active Record sanitizes these inputs and protects you from SQL injection automatically.&lt;/p&gt;

&lt;p&gt;There are times when you need to use a SQL operator that Active Record doesn't support (such as the &lt;code&gt;LIKE&lt;/code&gt; operator or when comparing dates). These scenarios might prevent you from using hash conditions.&lt;/p&gt;

&lt;p&gt;Avoid using pure string conditions though.&lt;/p&gt;

&lt;p&gt;And definitely avoid using string interpolation inside these conditions. &lt;/p&gt;

&lt;p&gt;If you need to pass a variable or any user input to a query, use array conditions so that Active Record sanitizes that input before giving it to the database.&lt;/p&gt;

</description>
      <category>rails</category>
      <category>ruby</category>
      <category>webdev</category>
      <category>programming</category>
    </item>
    <item>
      <title>A Complete Guide on How SQL Injection Attacks Work</title>
      <dc:creator>Nicholas Dill</dc:creator>
      <pubDate>Sat, 30 Oct 2021 18:40:17 +0000</pubDate>
      <link>https://dev.to/nicholasdill/a-complete-guide-on-how-sql-injection-attacks-work-45e</link>
      <guid>https://dev.to/nicholasdill/a-complete-guide-on-how-sql-injection-attacks-work-45e</guid>
      <description>&lt;p&gt;We need to talk about SQL injection. &lt;/p&gt;

&lt;p&gt;What it is, how to do it, and most importantly how to prevent it. We'll cover some examples of SQL injection too and explain how to identify vulnerabilities so you can protect your data.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What is SQL Injection?&lt;/li&gt;
&lt;li&gt;How Does SQL Injection Work?&lt;/li&gt;
&lt;li&gt;Identifying SQL Injection Vulnerabilities&lt;/li&gt;
&lt;li&gt;Preventing SQL Injection Attacks&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let's get into it.&lt;/p&gt;

&lt;p&gt;&lt;a id="sql-injection"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  What is SQL Injection
&lt;/h2&gt;

&lt;p&gt;SQL injection is a vulnerability that allows a malicious user to access your database in unintended ways.&lt;/p&gt;

&lt;p&gt;This vulnerability is usually created when you allow user input to be passed directly to the database. When an attacker identifies this, they are able to craft inputs that include SQL commands that run on the database. &lt;/p&gt;

&lt;p&gt;They essentially get access to read or manipulate your entire database.&lt;/p&gt;

&lt;p&gt;We will go over examples in a moment, but the idea is this.&lt;/p&gt;

&lt;p&gt;If you have an input on your site, like a search box that returns records from your database. An attacker can enter a string that gets read by the database to return matching results.&lt;/p&gt;

&lt;p&gt;When an attacker identifies an injection vulnerability, they are able to pass SQL instructions in that string to the database. The database will then run whatever SQL commands it was given by the user. &lt;/p&gt;

&lt;p&gt;This is not good.&lt;/p&gt;

&lt;h4&gt;
  
  
  What Can SQL Injection Attacks Expose?
&lt;/h4&gt;

&lt;p&gt;The potential impact of this vulnerability is massive. It can result in anything from letting a user read every row of every table in your database, to being able to write &lt;code&gt;INSERT&lt;/code&gt; or &lt;code&gt;UPDATE&lt;/code&gt; commands to modify or potentially even delete your database.&lt;/p&gt;

&lt;p&gt;Hackers have deleted debts from government databases, and stolen and published the personal information of millions of people because of SQL injection.&lt;/p&gt;

&lt;p&gt;Hopefully, as you can see SQL injection is an incredibly dangerous security vulnerability.&lt;/p&gt;

&lt;p&gt;And somehow even some of the largest companies still regularly expose this vulnerability.&lt;/p&gt;

&lt;p&gt;&lt;a id="how-sql-injection-works"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  How Does SQL Injection Work?
&lt;/h2&gt;

&lt;p&gt;The attack is based on a malicious user passing SQL instructions to your database.&lt;/p&gt;

&lt;p&gt;There are a ton of ways this can be done, and ultimately there is a potential threat on any line of code that you use to communicate with your database.&lt;/p&gt;

&lt;p&gt;Let's set up a scenario. Say your website sells a product and you use categories to filter what the user can see.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://example.com/products?category=books
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Your server takes the URL and parses the category query string to figure out how to filter the results for you.&lt;/p&gt;

&lt;p&gt;It will result in a SQL statement that could look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;products&lt;/span&gt; &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;category&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'books'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But what if a malicious user is savvy enough to realize that you are querying the database based on that URL?&lt;/p&gt;

&lt;p&gt;They might change the URL to something 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;https://example.com/products?category=books'+OR+1=1--
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Your server might then pass that string to the database, resulting in a query like this...&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;products&lt;/span&gt; &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;category&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'books'&lt;/span&gt; &lt;span class="k"&gt;OR&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="c1"&gt;--'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What they are doing is terminating the string early by passing the closing single quote in their input.&lt;/p&gt;

&lt;p&gt;This allows them to add additional SQL to their command. In this case they add an &lt;code&gt;OR 1=1&lt;/code&gt; which means they'll now see all products regardless of category since &lt;code&gt;1=1&lt;/code&gt; will be true for all rows in the table. They then append the final &lt;code&gt;--&lt;/code&gt; which is a comment so when your server adds the closing single quote, it doesn't throw any errors.&lt;/p&gt;

&lt;p&gt;This is a very benign example but demonstrates the easiest way to run raw SQL against someone else's database.&lt;/p&gt;

&lt;p&gt;Now imagine if instead of an &lt;code&gt;OR&lt;/code&gt; operator, a savvy attacker added a &lt;code&gt;UNION&lt;/code&gt; and appended other tables. &lt;/p&gt;

&lt;p&gt;They might even be able to return user emails, passwords, and other sensitive data this way.&lt;/p&gt;

&lt;p&gt;Also, this is just the URL, but any interface that allows user input is a potential attack vector. Input fields on your site, any textbox, forms... anything that interacts with the database creates a potential vulnerability.&lt;/p&gt;

&lt;p&gt;So as you can see, it's easier to pull off a SQL injection attack than you might think.&lt;/p&gt;

&lt;p&gt;&lt;a id="#second-order-injection"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Second-Order SQL Injection
&lt;/h3&gt;

&lt;p&gt;Another form of SQL injection can be categorized as second-order SQL injection.&lt;/p&gt;

&lt;p&gt;In the above example we were able to submit SQL instructions and immediately return results from the database. Second-order attacks work slightly differently and can be harder to detect.&lt;/p&gt;

&lt;p&gt;Instead of passing input to the database, the goal with a second-order attack is to persist malicious SQL commands for future use.&lt;/p&gt;

&lt;h4&gt;
  
  
  Got an example?
&lt;/h4&gt;

&lt;p&gt;Yep, let's walk through an example. Say I want to change my email on a website.&lt;/p&gt;

&lt;p&gt;In the email field, I might enter malicious data that I know will be stored on the database and retrieved later.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;hello@example.com';update users set password='password'--&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Can you guess what this might do?&lt;/p&gt;

&lt;p&gt;If that website ever passes my email directly to the database, it will include my SQL instructions... (and everyone's password will then be set to password).&lt;/p&gt;

&lt;p&gt;This strategy of attack is dangerous because malicious inputs can sit dormant for a long time before they perform their intended exploit.&lt;/p&gt;

&lt;p&gt;&lt;a id="identify-sql-injection"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  How to Identify SQL Injection Vulnerabilities
&lt;/h2&gt;

&lt;p&gt;When you have a good understanding of how SQL injection works, I recommend you try and identify vulnerabilities on your site.&lt;/p&gt;

&lt;p&gt;You can do this by testing your site and trying to inject harmless SQL.&lt;/p&gt;

&lt;p&gt;You should also review your code to make sure you aren't passing strings directly to your database.&lt;/p&gt;

&lt;p&gt;I would recommend you take a look at libraries for the language and framework you use to develop your site. Most frameworks have helpful tools that can detect these kinds of vulnerabilities before you promote them to production environments.&lt;/p&gt;

&lt;h3&gt;
  
  
  Test Your Site For Vulnerabilities
&lt;/h3&gt;

&lt;p&gt;A surefire way to identify SQL injection vulnerabilities is to test your site for them.&lt;/p&gt;

&lt;p&gt;Take some of the examples in the section above. Watch how your server responds. You might be surprised to see that it's easier to perform a SQL injection attack than you thought.&lt;/p&gt;

&lt;p&gt;Don't dismiss this vulnerability just because you can't attack your own system though.&lt;/p&gt;

&lt;p&gt;There are many ways of performing SQL injection beyond passing user input.&lt;/p&gt;

&lt;p&gt;As mentioned above, second order SQL injection can't be detected immediately. It can be difficult to detect if users are storing queries that can be executed at a later time. &lt;/p&gt;

&lt;h3&gt;
  
  
  Carefully Review Your Code
&lt;/h3&gt;

&lt;p&gt;The best approach to protect against SQL injection is to learn and understand how SQL injection is made possible.&lt;/p&gt;

&lt;p&gt;When you understand how it works and what makes it possible, you will have a better idea of where you might be exposing opportunities in your code. Take a look at your code. Anywhere that you interact with your database. And make sure you aren't passing any kind of user input or user generated content (remember, second order injection) directly to your database.&lt;/p&gt;

&lt;p&gt;Ask yourself, what could happen if this string contained malicious SQL instructions?&lt;/p&gt;

&lt;p&gt;It's better to be safe than sorry, or in this case secure rather than exposing your entire database.&lt;/p&gt;

&lt;p&gt;&lt;a id="prevent-sql-injection"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  How to Protect From SQL Injection
&lt;/h2&gt;

&lt;p&gt;Protecting against SQL injection is actually really easy.&lt;/p&gt;

&lt;p&gt;What you need is input validation and sanitization. &lt;/p&gt;

&lt;p&gt;These are techniques that clean user input to prevent it passing harmful strings to your database.&lt;/p&gt;

&lt;p&gt;3 of the top website attacks (SQL injection, cross-site scripting, and remote file inclusion) all come from a lack of input sanitization. &lt;/p&gt;

&lt;p&gt;And luckily, it's not hard to sanitize inputs in most major languages and frameworks.&lt;/p&gt;

&lt;h3&gt;
  
  
  How to Sanitize User Input
&lt;/h3&gt;

&lt;p&gt;The idea is, you take a string the user submitted and you escape any characters that could cause issues.&lt;/p&gt;

&lt;p&gt;Ruby on Rails handles this for you automatically when you use the Active Record ORM correctly.&lt;/p&gt;

&lt;p&gt;But if you don't use Active Record correctly, or if you write SQL directly in code, you can still open your database up to vulnerabilities.&lt;/p&gt;

&lt;p&gt;A good example of how easy it is to accidentally expose your data...&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Don't do this!&lt;/span&gt;
&lt;span class="no"&gt;User&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"id = &lt;/span&gt;&lt;span class="si"&gt;#{&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;:id&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you pass malicious input into the &lt;code&gt;params[:id]&lt;/code&gt;, you can inject SQL into this database call. &lt;/p&gt;

&lt;p&gt;String interpolation is generally a very bad pattern to use in your database calls.&lt;/p&gt;

&lt;p&gt;In this case, the better way to use Active Record would be to pass the string as an additional argument. Active Record will then sanitize it for you.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Better example&lt;/span&gt;
&lt;span class="no"&gt;User&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"id = ?"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:id&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;where()&lt;/code&gt; method sanitizes strings passed as additional arguments, but it won't sanitize the first argument's SQL command.&lt;/p&gt;

&lt;h3&gt;
  
  
  Avoid Writing SQL in Active Record
&lt;/h3&gt;

&lt;p&gt;The truly correct way to use Active Record is to avoid passing raw SQL strings altogether.&lt;/p&gt;

&lt;p&gt;If you use Active Record's methods without string interpolation it will always sanitize your inputs automatically.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Safe example&lt;/span&gt;
&lt;span class="no"&gt;User&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;id: &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;:id&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

&lt;span class="c1"&gt;# or even better&lt;/span&gt;
&lt;span class="no"&gt;User&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&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;:id&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Sometimes you need to write queries with operators that Active Record doesn't support. Such as the &lt;code&gt;LIKE&lt;/code&gt; operator or when comparing dates. Just remember to check for SQL injection vulnerabilities you might be introducing.&lt;/p&gt;

&lt;p&gt;This &lt;a href="https://stackoverflow.com/questions/21886170/best-way-to-go-about-sanitizing-user-input-in-rails"&gt;StackOverflow post&lt;/a&gt; has a great in-depth explanation or input sanitization in Rails, if you're curious.&lt;/p&gt;

&lt;p&gt;Python, PHP, and most other popular languages also come with support for sanitizing user input.&lt;/p&gt;

&lt;p&gt;So as you can see it's not hard to protect your database, it's actually pretty easy. &lt;/p&gt;

&lt;p&gt;The real challenge is how to you prevent incidents where someone &lt;em&gt;forgets&lt;/em&gt; to sanitize and protect from malicious user input.&lt;/p&gt;

&lt;p&gt;That's hard... really hard.&lt;/p&gt;

&lt;p&gt;Even the biggest, most advanced technology companies still struggle with this.&lt;/p&gt;

&lt;p&gt;&lt;a id="sql-injection-news"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Recent SQL Injection Attacks
&lt;/h2&gt;

&lt;h4&gt;
  
  
  The GhostShell Attack
&lt;/h4&gt;

&lt;p&gt;A group of hackers from the APT group Team GhostShell used SQL injection to attack 53 universities. They managed to steal the personal records of 36,000 university students, faculty, and staff.&lt;/p&gt;

&lt;h4&gt;
  
  
  Turkish Government
&lt;/h4&gt;

&lt;p&gt;RedHack collective (another APT group) used SQL injection to access a Turkish government website and erase debt to government agencies.&lt;/p&gt;

&lt;h4&gt;
  
  
  7-Eleven Attack
&lt;/h4&gt;

&lt;p&gt;Attackers used SQL injection to access data from several corporations, including 7-Eleven. They managed to access over 130 million credit card numbers.&lt;/p&gt;

&lt;h4&gt;
  
  
  HBGary Attack
&lt;/h4&gt;

&lt;p&gt;Hackers from the Anonymous activist group used SQL injection to take down the website of IT security company, HBGary. The CEO of HBGary shared that he had the names of Anonymous organization members, which prompted the attack.&lt;/p&gt;

&lt;h3&gt;
  
  
  Recent SQL Injection Vulnerabilities Discovered
&lt;/h3&gt;

&lt;p&gt;You'll recognize some of these companies. It goes to show that nobody is immune from this exploit.&lt;/p&gt;

&lt;h4&gt;
  
  
  Fortnite Vulnerability
&lt;/h4&gt;

&lt;p&gt;In 2019, a SQL injection vulnerability was discovered that allowed attackers to access user accounts. Fortnite, by the way, has over 350 million users. Luckily, the vulnerability was quickly patched. &lt;/p&gt;

&lt;h4&gt;
  
  
  Cisco Vulnerability
&lt;/h4&gt;

&lt;p&gt;In 2018, a SQL injection vulnerability was discovered in the Cisco Prime License Manager. The vulnerability gave attackers shell access to systems where license manager was deployed. This vulnerability has been patched.&lt;/p&gt;

&lt;h4&gt;
  
  
  Tesla Vulnerability
&lt;/h4&gt;

&lt;p&gt;In 2014, security researchers shared that they were able to gain administrative privileges and steal user data through Tesla's website.&lt;/p&gt;




&lt;h2&gt;
  
  
  Final Words
&lt;/h2&gt;

&lt;p&gt;All it takes is one vulnerable line of code, and your entire system is at risk.&lt;/p&gt;

&lt;p&gt;Please, take SQL injection seriously!&lt;/p&gt;

</description>
      <category>rails</category>
      <category>ruby</category>
      <category>sql</category>
      <category>webdev</category>
    </item>
    <item>
      <title>How to Build OR Queries With Active Record</title>
      <dc:creator>Nicholas Dill</dc:creator>
      <pubDate>Fri, 29 Oct 2021 14:30:02 +0000</pubDate>
      <link>https://dev.to/nicholasdill/how-to-build-or-queries-with-active-record-4ce7</link>
      <guid>https://dev.to/nicholasdill/how-to-build-or-queries-with-active-record-4ce7</guid>
      <description>&lt;p&gt;There are a couple of ways to recreate the SQL &lt;code&gt;OR&lt;/code&gt; operator with Ruby on Rails and Active Record.&lt;/p&gt;

&lt;p&gt;Here's how.&lt;/p&gt;

&lt;h2&gt;
  
  
  Checking a Single Column For Multiple Values
&lt;/h2&gt;

&lt;p&gt;First, if you want to pull records where a certain column can be multiple values you won't need to use the &lt;code&gt;OR&lt;/code&gt; SQL operator.&lt;/p&gt;

&lt;p&gt;Instead, pass a list of the accepted values to Active Record and it will use the SQL &lt;code&gt;IN&lt;/code&gt; operator.&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;Model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;column: &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will generate SQL the looks something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;models&lt;/span&gt; &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;column&lt;/span&gt; &lt;span class="k"&gt;IN&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This pattern is extremely common and very practical. A couple of real examples:&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;User&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;role: &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:admin&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:mod&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

&lt;span class="no"&gt;BlogPost&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;tags: &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;ruby_tag&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;rails_tag&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

&lt;span class="n"&gt;comment_ids&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="c1"&gt;# append selected comment ids&lt;/span&gt;
&lt;span class="no"&gt;Comment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;id: &lt;/span&gt;&lt;span class="n"&gt;comment_ids&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Checking Multiple Columns For Multiple Values
&lt;/h2&gt;

&lt;p&gt;If we need to check multiple columns, we can't get away with using the SQL &lt;code&gt;IN&lt;/code&gt; operator anymore.&lt;/p&gt;

&lt;p&gt;Instead, we need to leverage the full strength and flexibility of &lt;code&gt;OR&lt;/code&gt; queries.&lt;/p&gt;

&lt;h3&gt;
  
  
  Using the OR Operator in Rails 5+
&lt;/h3&gt;

&lt;p&gt;Rails 5 introduced the OR condition in Active Record.&lt;/p&gt;

&lt;p&gt;Here's an example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="no"&gt;Post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;category: &lt;/span&gt;&lt;span class="s2"&gt;"featured"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;or&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;Post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;promoted: &lt;/span&gt;&lt;span class="kp"&gt;true&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here's how to use it:&lt;/p&gt;

&lt;p&gt;We break down our 2 acceptable conditions into individual queries. In this case, we want to fetch all the posts with a &lt;code&gt;category&lt;/code&gt; set to "featured" and then also pull all the posts that have their &lt;code&gt;promoted&lt;/code&gt; field set to true.&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;Post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;category: &lt;/span&gt;&lt;span class="s2"&gt;"featured"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="no"&gt;Post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;promoted: &lt;/span&gt;&lt;span class="kp"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You then call Active Record's &lt;code&gt;.or&lt;/code&gt; method on the first query, and pass it the second query as an argument.&lt;/p&gt;

&lt;p&gt;Here's the SQL output you would get:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;posts&lt;/span&gt; &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;category&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'featured'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;OR&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;promoted&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's it! You'll get results the match either condition in your query.&lt;/p&gt;

&lt;h3&gt;
  
  
  Using the OR Operator in Rails 4 and Below
&lt;/h3&gt;

&lt;p&gt;Earlier versions of Rails don't have support for &lt;code&gt;OR&lt;/code&gt; queries in Active Record, but you can still pass raw SQL to your where conditions.&lt;/p&gt;

&lt;p&gt;Here's how that would look:&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;Post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"category = ? or promoted = ?"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"featured"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kp"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you're curious about the &lt;code&gt;?&lt;/code&gt; syntax above, this is a technique to protect your database against SQL injection attacks. More on that next.&lt;/p&gt;




&lt;h2&gt;
  
  
  Preventing SQL Injection Attacks
&lt;/h2&gt;

&lt;p&gt;It would be irresponsible to not give a quick overview of how you might expose yourself to SQL injection attacks.&lt;/p&gt;

&lt;p&gt;If you're not familiar, it's a vulnerability where user input is passed directly into your database queries. If you unintentionally allow this, the user can purposely input malicious SQL code into the input. And that SQL will be run on your database.&lt;/p&gt;

&lt;p&gt;If we don't substitute variables in our query and instead pass them directly, we might expose our entire database to the user.&lt;/p&gt;

&lt;p&gt;It works like this.&lt;/p&gt;

&lt;p&gt;When you pass a variable to a &lt;code&gt;where&lt;/code&gt; clause directly, it will pass the variable to the database as-is.&lt;br&gt;
If the user has malicious intent, they can pass unescaped strings directly to your database and wreak havoc.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Don't do this:&lt;/strong&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="no"&gt;Post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"category = &lt;/span&gt;&lt;span class="si"&gt;#{&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;:category&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can't guarantee the input you get from &lt;code&gt;params[:category]&lt;/code&gt; is safe for your database.&lt;/p&gt;

&lt;p&gt;When you pass strings as the second argument in the &lt;code&gt;where&lt;/code&gt; method, Active Record does the proper escaping needed to protect your database.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Better example:&lt;/strong&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="no"&gt;Post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"category = ?"&lt;/span&gt;&lt;span class="p"&gt;,&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;:featured&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Final Words
&lt;/h2&gt;

&lt;p&gt;Active Record is super powerful and gives you multiple ways to construct your OR query.&lt;/p&gt;

&lt;p&gt;A quick note on the SQL outputs though - what you see here should be similar to what your Rails app generates, but it will depend on the database adapter your app is using. Different databases have subtle differences and unfortunately, they aren't all exactly the same. But this is why we have Active Record! It abstracts away that complexity and gives a simple way to interface with any database.&lt;/p&gt;

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