<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Sam Partington</title>
    <description>The latest articles on Forem by Sam Partington (@sampart).</description>
    <link>https://forem.com/sampart</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%2F129618%2Fb41a92f3-5c12-40f8-b5a5-35dbc240b769.jpeg</url>
      <title>Forem: Sam Partington</title>
      <link>https://forem.com/sampart</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/sampart"/>
    <language>en</language>
    <item>
      <title>How to integrate Brakeman Security Scanner with GitHub Code Scanning</title>
      <dc:creator>Sam Partington</dc:creator>
      <pubDate>Mon, 22 Dec 2025 10:11:50 +0000</pubDate>
      <link>https://forem.com/sampart/how-to-integrate-brakeman-security-scanner-with-github-code-scanning-44an</link>
      <guid>https://forem.com/sampart/how-to-integrate-brakeman-security-scanner-with-github-code-scanning-44an</guid>
      <description>&lt;p&gt;&lt;a href="https://docs.github.com/en/code-security/code-scanning/introduction-to-code-scanning/about-code-scanning" rel="noopener noreferrer"&gt;GitHub Code Scanning&lt;/a&gt; automatically scans your repository for security vulnerabilities and alerts you in Pull Requests and on a dedicated alert backlog accessible via a repository's Security tab.&lt;/p&gt;

&lt;p&gt;Out of the box, GitHub Code Scanning uses a tool called &lt;a href="https://codeql.github.com" rel="noopener noreferrer"&gt;CodeQL&lt;/a&gt;, but you can also display alerts produced by any tool that can output its results in the &lt;a href="https://docs.github.com/en/code-security/code-scanning/integrating-with-code-scanning/sarif-support-for-code-scanning" rel="noopener noreferrer"&gt;SARIF format&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The Rails security scanner &lt;a href="https://brakemanscanner.org" rel="noopener noreferrer"&gt;Brakeman&lt;/a&gt; supports the SARIF format, but I couldn't find any documentation about how to join all the pieces together and see Brakeman results in GitHub Code Scanning. This blog post is my answer to the question of how you do it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pre-requisites
&lt;/h2&gt;

&lt;p&gt;This guide assumes that you already have &lt;a href="https://docs.github.com/en/code-security/code-scanning/enabling-code-scanning" rel="noopener noreferrer"&gt;GitHub Code Scanning turned on&lt;/a&gt; for your repository. Your project will also need to have Brakeman installed. You don't need it running on your local machine - you could do the install explicitly in the Actions workflow you'll be creating, but this guide assumes you instead have something like the following in your &lt;code&gt;Gemfile&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;group&lt;/span&gt; &lt;span class="ss"&gt;:development&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:test&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;gem&lt;/span&gt; &lt;span class="s1"&gt;'brakeman'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;require: &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;
  
  
  Creating a GitHub Actions workflow
&lt;/h2&gt;

&lt;p&gt;To upload results to Code Scanning, you'll need to create an GitHub Actions workflow. &lt;code&gt;rails new&lt;/code&gt; creates an existing workflow which you could modify, but for simplicity I'm showing here a fresh workflow just for Brakeman.&lt;/p&gt;

&lt;p&gt;Here's the full workflow; I'll explain it step-by-step below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Run&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;brakeman&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;and&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;upload&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;results&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;to&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Code&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Scanning"&lt;/span&gt;

&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;main&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
  &lt;span class="na"&gt;pull_request&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;

&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;brakeman&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;

    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v3&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Set up Ruby&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ruby/setup-ruby@v1&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;ruby-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;.ruby-version&lt;/span&gt;
          &lt;span class="na"&gt;bundler-cache&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Run brakeman&lt;/span&gt;
        &lt;span class="c1"&gt;# Without --no-exit-on-warn, brakeman returns a non-zero error code when alerts&lt;/span&gt;
        &lt;span class="c1"&gt;# are found, failing the check. We want the check to pass as results are handled&lt;/span&gt;
        &lt;span class="c1"&gt;# via GitHub Code Scanning's UI.&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;bundle exec brakeman --no-exit-on-warn -f sarif &amp;gt; brakeman-results.sarif&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Upload scan results to GitHub Code Scanning&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;github/codeql-action/upload-sarif@v3&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;sarif_file&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;brakeman-results.sarif"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The workflow begins with metadata - a name, and when it should run (that empty &lt;code&gt;pull_request:&lt;/code&gt; key isn't a typo, despite appearances). We then declare a job and state that it should run on Ubuntu. &lt;a href="https://github.com/actions/runner-images?tab=readme-ov-file#available-images" rel="noopener noreferrer"&gt;Other runner types&lt;/a&gt; are available, or you can &lt;a href="https://docs.github.com/en/actions/how-tos/manage-runners/self-hosted-runners/add-runners" rel="noopener noreferrer"&gt;host your own&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The first step in the job uses &lt;a href="https://github.com/actions/checkout" rel="noopener noreferrer"&gt;&lt;code&gt;actions/checkout&lt;/code&gt;&lt;/a&gt; to clone the repo it runs in. We then run the &lt;a href="https://github.com/ruby/setup-ruby" rel="noopener noreferrer"&gt;&lt;code&gt;ruby/setup-ruby&lt;/code&gt;&lt;/a&gt; action which installs Ruby and runs Bundler. If Brakeman is in your Gemfile (see above), that'll be installed at this stage.&lt;/p&gt;

&lt;p&gt;The next step actually runs Brakeman, using the &lt;code&gt;run&lt;/code&gt; command to run the following terminal command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;bundle exec brakeman --no-exit-on-warn -f sarif &amp;gt; brakeman-results.sarif
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The first part of this command is fairly self-explanatory, we're running Brakeman via Bundler: &lt;code&gt;bundle exec brakeman&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;--no-exit-on-warn&lt;/code&gt; is important. Normally, if Brakeman finds any alerts, it &lt;a href="https://github.com/presidentbeef/brakeman/blob/ccd9e644df1d56895ffd29ce2f6b86cfc89a9e32/lib/brakeman.rb#L8" rel="noopener noreferrer"&gt;will return a non-zero return code&lt;/a&gt;. On UNIX-like systems (including Linux or Mac), that indicates a failure and so the workflow will fail. If you weren't uploading results to Code Scanning, that'd be the correct behaviour -- a failing workflow would indicate problems found. However, that's not what we want here -- we'll be showing alerts through the Code Scanning UI instead.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;-f sarif&lt;/code&gt; tells Brakeman to use the &lt;a href="https://docs.github.com/en/code-security/code-scanning/integrating-with-code-scanning/sarif-support-for-code-scanning" rel="noopener noreferrer"&gt;SARIF format&lt;/a&gt; format, which is what GitHub Code Scanning needs.&lt;/p&gt;

&lt;p&gt;Finally, we &lt;a href="https://en.wikipedia.org/wiki/Redirection_(computing)" rel="noopener noreferrer"&gt;redirect&lt;/a&gt; the output into a file ready for the next step to upload.&lt;/p&gt;

&lt;p&gt;The final step in the workflow &lt;a href="https://docs.github.com/en/code-security/code-scanning/integrating-with-code-scanning/uploading-a-sarif-file-to-github#uploading-a-code-scanning-analysis-with-github-actions" rel="noopener noreferrer"&gt;uploads the results to GitHub Code Scanning&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  What you get
&lt;/h2&gt;

&lt;p&gt;Once this is running, results from Brakeman will appear in the Code Scanning UI:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqer26w7flo6gcm2z0owz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqer26w7flo6gcm2z0owz.png" alt="screenshot of Brakeman alerts in Code Scanning UI" width="800" height="437"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Newly-introduced alerts will also show up as annotations on Pull Requests.&lt;/p&gt;

&lt;p&gt;If you create the new workflow in a Pull Request, you might also see a helpful comment automatically posted on it, like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyytgcab3hd748xgx8j57.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyytgcab3hd748xgx8j57.png" alt="This pull request sets up GitHub code scanning for this repository. Once the scans have completed and the checks have passed, the analysis results for this pull request branch will appear on this overview..." width="800" height="235"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Troubleshooting
&lt;/h2&gt;

&lt;p&gt;Not working? Try these...&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Take a look at the log output from the workflow; chances are, you'll see an error here that helps explain what's wrong.&lt;/li&gt;
&lt;li&gt;Run the Brakeman command locally and see what happens. Take away the redirection if you want to see output, and remove &lt;code&gt;-f sarif&lt;/code&gt; to get results in a more human-readable format. You might not actually have any alerts in your project, of course!&lt;/li&gt;
&lt;li&gt;Look at the Code Scanning results page for your repository (&lt;code&gt;/security/code-scanning&lt;/code&gt;). You should see a "tool status" banner at the top, which will tell you the health of the Code Scanning tools that your repository is using. You might see Brakeman errors or warnings here; if not then press the "Tools" button and see if Brakeman is listed at all. If it's not, then the upload or a previous step is failing.&lt;/li&gt;
&lt;li&gt;You could experiment with uploading results manually using the &lt;a href="https://docs.github.com/en/rest/code-scanning/code-scanning#upload-an-analysis-as-sarif-data" rel="noopener noreferrer"&gt;Code Scanning API&lt;/a&gt;. Run the workflow Brakeman command, upload results and see what status or error you get back.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  See also
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;GitHub's official resource article, &lt;a href="https://resources.github.com/learn/pathways/security/intermediate/third-party-tools-integration-code-scanning/" rel="noopener noreferrer"&gt;Extend your testing with third-party tools with GitHub code scanning&lt;/a&gt;. This isn't Ruby-specific, though.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>security</category>
      <category>cicd</category>
      <category>github</category>
      <category>rails</category>
    </item>
    <item>
      <title>What actually are .tt files in Ruby?</title>
      <dc:creator>Sam Partington</dc:creator>
      <pubDate>Wed, 05 Nov 2025 12:43:48 +0000</pubDate>
      <link>https://forem.com/sampart/what-actually-are-tt-files-in-ruby-2gi1</link>
      <guid>https://forem.com/sampart/what-actually-are-tt-files-in-ruby-2gi1</guid>
      <description>&lt;p&gt;&lt;strong&gt;tl;dr&lt;/strong&gt; &lt;code&gt;.tt&lt;/code&gt; files aren't a special syntax; they're ERB (Embedded Ruby) files. You might see unusual syntax if they're ERB files which generate other ERB files.&lt;/p&gt;

&lt;p&gt;If you're working with Ruby, particularly Rails and its generators, you're likely to come across files with a &lt;code&gt;.tt&lt;/code&gt; extension. But what actually are &lt;code&gt;.tt&lt;/code&gt; files?&lt;/p&gt;

&lt;p&gt;Rails generators use the &lt;a href="https://github.com/rails/thor" rel="noopener noreferrer"&gt;Thor toolkit&lt;/a&gt;&lt;sup id="fnref1"&gt;1&lt;/sup&gt; which helps with building CLIs and manipulating files. So you could think of "tt" as standing for "Thor template".&lt;/p&gt;

&lt;p&gt;If that's the case then you might reasonably ask, "What's Thor template syntax?" It took me a long time to work out that this is the wrong question. We call a tt file a Thor template file not because it's a template using Thor syntax (there's no such thing) but because it's a template used in Thor commands.&lt;/p&gt;

&lt;p&gt;I'll say that again: A "Thor template" means "a template used in a Thor command", not "a template using ‘Thor syntax'".&lt;/p&gt;

&lt;p&gt;The syntax which &lt;code&gt;.tt&lt;/code&gt; files use is actually Embedded Ruby (aka ERB, or eRuby).&lt;/p&gt;

&lt;p&gt;One thing which led me to mistakenly believe that Thor syntax was its own language is the &lt;code&gt;&amp;lt;%%&lt;/code&gt; and &lt;code&gt;%%&amp;gt;&lt;/code&gt; tags I sometimes see in &lt;code&gt;.tt&lt;/code&gt; files. If this is just ERB, what are those?&lt;/p&gt;

&lt;p&gt;To answer that, remember that in Rails generators you'll find &lt;code&gt;.tt&lt;/code&gt; files that are used to generate ERB files. As &lt;a href="https://guides.rubyonrails.org/generators.html#overriding-rails-generator-templates" rel="noopener noreferrer"&gt;the Rails generator docs briefly mention&lt;/a&gt;,&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note that [this example template] is an ERB template that renders &lt;em&gt;another&lt;/em&gt; ERB template. So any &lt;code&gt;&amp;lt;%&lt;/code&gt; that should appear in the &lt;em&gt;resulting&lt;/em&gt; template must be escaped as &lt;code&gt;&amp;lt;%%&lt;/code&gt; in the &lt;em&gt;generator&lt;/em&gt; template.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;(Some &lt;code&gt;.tt&lt;/code&gt; files generate Ruby code, like controllers, so they wouldn't need to use this syntax.)&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&amp;lt;%%&lt;/code&gt; is actually ERB syntax, although &lt;a href="https://stackoverflow.com/a/79810018/328817" rel="noopener noreferrer"&gt;there isn't really canonical documentation for ERB syntax&lt;/a&gt;, and docs on this particular tag are hard to find. I couldn't find anything about it in &lt;a href="https://docs.ruby-lang.org/en/master/ERB.html" rel="noopener noreferrer"&gt;the current rdoc for the ERB class&lt;/a&gt;&lt;sup id="fnref2"&gt;2&lt;/sup&gt;, but in &lt;a href="https://ruby-doc.org/stdlib-2.5.3/libdoc/erb/rdoc/ERB.html#class-ERB-label-Recognized+Tags" rel="noopener noreferrer"&gt;this old version&lt;/a&gt;, we find:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;&amp;lt;%% or %%&amp;gt; -- replace with &amp;lt;% or %&amp;gt; respectively&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;To conclude, then, &lt;code&gt;.tt&lt;/code&gt; files are used by the Thor templating engine, but their syntax is ERB. You might find some odd-looking &lt;code&gt;&amp;lt;%% tags&lt;/code&gt;, but that is also ERB syntax, albeit poorly-documented, and it converts to &lt;code&gt;&amp;lt;%&lt;/code&gt; in the resulting output. This allows you to create ERB templates which themselves produce ERB!&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note: You might also find files with the .tt extension if you're working with &lt;a href="https://learn.microsoft.com/en-us/visualstudio/modeling/design-time-code-generation-by-using-t4-text-templates#create-a-design-time-t4-text-template" rel="noopener noreferrer"&gt;Visual Studio text templates&lt;/a&gt; and their T4 text template language. That looks a bit like ERB, but uses tags like &lt;code&gt;&amp;lt;#&lt;/code&gt; instead. It's nothing to do with Ruby!&lt;/em&gt;&lt;/p&gt;




&lt;ol&gt;

&lt;li id="fn1"&gt;
&lt;p&gt;See also &lt;a href="http://whatisthor.com" rel="noopener noreferrer"&gt;http://whatisthor.com&lt;/a&gt; ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn2"&gt;
&lt;p&gt;Rails actually uses &lt;a href="https://github.com/jeremyevans/erubi" rel="noopener noreferrer"&gt;https://github.com/jeremyevans/erubi&lt;/a&gt; for parsing embedded Ruby rather than the ERB class from the standard library. For an overview of embedded Ruby tools and libraries and their associated documentation, check out &lt;a href="https://stackoverflow.com/a/79810018/328817" rel="noopener noreferrer"&gt;this Stack Overflow answer&lt;/a&gt;. ↩&lt;/p&gt;
&lt;/li&gt;

&lt;/ol&gt;

</description>
      <category>ruby</category>
    </item>
    <item>
      <title>Combining multiple forms in Flask-WTForms but validating independently</title>
      <dc:creator>Sam Partington</dc:creator>
      <pubDate>Thu, 17 Jan 2019 12:07:04 +0000</pubDate>
      <link>https://forem.com/sampart/combining-multiple-forms-in-flask-wtforms-but-validating-independently-cbm</link>
      <guid>https://forem.com/sampart/combining-multiple-forms-in-flask-wtforms-but-validating-independently-cbm</guid>
      <description>&lt;h1&gt;
  
  
  Introduction
&lt;/h1&gt;

&lt;p&gt;We have a Flask project coming up at &lt;a href="https://www.whiteoctober.co.uk/" rel="noopener noreferrer"&gt;White October&lt;/a&gt; which will include a user profile form.  This form can be considered as one big form or as multiple smaller forms and can also be submitted as a whole or section-by-section.&lt;/p&gt;

&lt;p&gt;As part of planning for this work, we did a proof-of-concept around combining multiple subforms together in Flask-WTForms and validating them.&lt;/p&gt;

&lt;p&gt;Note that this is a slightly different pattern to "nested forms".  Nested forms are often used for dynamic repeated elements - like adding multiple addresses to a profile using a single nested address form repeatedly.  But our use case was several forms combined together in a non-dynamic way and potentially processed independently.  This article also doesn't consider the situation of having multiple &lt;em&gt;separate&lt;/em&gt; HTML forms on one page.&lt;/p&gt;

&lt;p&gt;This document explains the key things you need to know to combine forms together in Flask-WTF, whether you're using AJAX or plain postback.&lt;/p&gt;

&lt;h1&gt;
  
  
  Subforms
&lt;/h1&gt;

&lt;p&gt;The first thing to know is how to combine multiple WTForms forms into one.  For that, use the &lt;a href="http://wtforms.simplecodes.com/docs/1.0.1/fields.html#field-enclosures" rel="noopener noreferrer"&gt;FormField&lt;/a&gt; field type (aka "field enclosure").  Here's an example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;from flask_wtf import FlaskForm
import wtforms

class AboutYouForm(FlaskForm):
    first_name = wtforms.StringField(
        label="First name", validators=[wtforms.validators.DataRequired()]
    )
    last_name = wtforms.StringField(label="Last name")

class ContactDetailsForm(FlaskForm):
    address_1 = wtforms.StringField(
        label="Address 1", validators=[wtforms.validators.DataRequired()]
    )
    address_2 = wtforms.StringField(label="Address 2")

class GiantForm(FlaskForm):
    about_you = wtforms.FormField(AboutYouForm)
    contact_details = wtforms.FormField(ContactDetailsForm)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see, the third form here is made by combining the first two.&lt;/p&gt;

&lt;p&gt;You can render these subforms just like any other form field:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{{ form.about_you }}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;(Form rendering is discussed in more detail below.)&lt;/p&gt;

&lt;h1&gt;
  
  
  Validating a subform
&lt;/h1&gt;

&lt;p&gt;Once we'd combined our forms, the second thing we wanted to prove was that they could be validated independently.&lt;/p&gt;

&lt;p&gt;Normally, you'd validate a (whole) form 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;if form.validate_on_submit()
    # do something
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;(&lt;code&gt;validate_on_submit&lt;/code&gt; returns true if the form has been submitted and is valid.)&lt;/p&gt;

&lt;p&gt;It turns out that you can validate an individual form field quite easily.  For our &lt;code&gt;about_you&lt;/code&gt; field (which is a subform), it just looks 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;form.about_you.validate(form)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Determining what to validate
&lt;/h2&gt;

&lt;p&gt;We added multiple submit buttons to the form so that either individual subforms or the whole thing could be processed.  If you give the submit buttons different names, you can easily check which one was pressed and validate and save appropriately (make sure you only save the data you've validated):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;input type="submit" name="submit-about-you" value="Just submit About You subform"&amp;gt;
&amp;lt;input type="submit" name="submit-whole-form" value="Submit whole form"&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And then:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;if "submit-about-you" in request.form and form.about_you.validate(form):
    # save About You data here
elif "submit-whole-form" in request.form and form.validate():
    # save all data here
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you have one route method handling both HTTP GET and POST methods, there's no need to explicitly check whether this is a postback before running the above checks - neither button will be in &lt;code&gt;request.form&lt;/code&gt; if it's not a POST.&lt;/p&gt;

&lt;h3&gt;
  
  
  Alternative approaches
&lt;/h3&gt;

&lt;p&gt;You could alternatively give both submit buttons the same name and differentiate on value.  However, this means that changes to the user-facing wording on your buttons (as this is their value property) may break the if-statements in your code, which isn't ideal, hence why different names is our recommended approach.&lt;/p&gt;

&lt;p&gt;If you want to include your submit buttons in your WTForms form classes themselves rather than hard-coding the HTML, you can check which one was submitted by checking the relevant field's &lt;code&gt;data&lt;/code&gt; property - see &lt;a href="https://stackoverflow.com/a/35776874/328817" rel="noopener noreferrer"&gt;here&lt;/a&gt; for a small worked example of that.&lt;/p&gt;

&lt;h3&gt;
  
  
  Gotcha: Browser-based validation and multiple submit buttons
&lt;/h3&gt;

&lt;p&gt;There's one snag you'll hit if you're using multiple submit buttons to validate/save data from just one subform of a larger form.&lt;/p&gt;

&lt;p&gt;If your form fields have the &lt;code&gt;required&lt;/code&gt; property set (which WTForms will do if you use the &lt;code&gt;DataRequired&lt;/code&gt; validator, for example), then the browser will stop you submitting the form until &lt;em&gt;all&lt;/em&gt; required fields are filled in - it doesn't know that you're only concerned with part of the form (since this partial-submission is implemented server-side).&lt;/p&gt;

&lt;p&gt;Therefore, assuming that you want to keep using the &lt;code&gt;required&lt;/code&gt; property (which you should),  you'll need to add some Javascript to dynamically alter the form field properties on submission.&lt;/p&gt;

&lt;p&gt;This is not a problem if you're using AJAX rather than postbacks for your form submissions; see below how to do that.&lt;/p&gt;

&lt;h1&gt;
  
  
  Rendering subforms in a template
&lt;/h1&gt;

&lt;p&gt;&lt;em&gt;The examples in this section use explicit field names.  In practice, you'll want to create a &lt;a href="http://flask.pocoo.org/docs/1.0/patterns/wtforms/#forms-in-templates" rel="noopener noreferrer"&gt;field-rendering macro&lt;/a&gt; to which you can pass each form field rather than repeating this code for every form field you have.  That link also shows how to render a field's label and widget separately, which gives you more control over your markup.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;As mentioned above, the subforms can be rendered with a single line, just like any other field:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{{ form.about_you }}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you want to render fields from your subforms individually, it'll look 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;&amp;lt;label for="{{ form.about_you.first_name.id }}"&amp;gt;{{ form.about_you.first_name.label }}&amp;lt;/label&amp;gt;
{{ form.about_you.first_name }}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you see, you can't do single-line rendering of form fields and their labels for individual fields within subforms - you have to explicitly render the label.&lt;/p&gt;

&lt;h2&gt;
  
  
  Displaying subform errors
&lt;/h2&gt;

&lt;p&gt;For a normal form field, you can display associated errors by iterating over the &lt;code&gt;errors&lt;/code&gt; property 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;{% if form.your_field_name.errors %}
    &amp;lt;ul class=errors&amp;gt;
        {% for error in field.errors %}
            &amp;lt;li&amp;gt;{{ error }}&amp;lt;/li&amp;gt;
        {% endfor %}
    &amp;lt;/ul&amp;gt;
{% endif %}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this case, &lt;code&gt;errors&lt;/code&gt; is just a &lt;strong&gt;list&lt;/strong&gt; of error strings for the field.&lt;/p&gt;

&lt;p&gt;For a subform where you're using the FormField field type, however, &lt;code&gt;errors&lt;/code&gt; is a &lt;strong&gt;dictionary&lt;/strong&gt; mapping field names to lists of errors.  For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
    'first_name': ['This field is required.'],
    'last_name': ['This field is required.'],
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Therefore, iterating over it in your template is more complicated.  Here's an example which displays errors for all fields in a subform (notice the use of the &lt;code&gt;&lt;a href="https://docs.python.org/3/tutorial/datastructures.html#looping-techniques" rel="noopener noreferrer"&gt;items&lt;/a&gt;&lt;/code&gt; method):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{% if form.about_you.errors %}
    &amp;lt;ul class="errors"&amp;gt;
        {% for error_field, errors in form.about_you.errors.items() %}
            &amp;lt;li&amp;gt;{{ error_field }}: {{ errors|join(', ') }}&amp;lt;/li&amp;gt;
        {% endfor %}
    &amp;lt;/ul&amp;gt;
{% endif %}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Doing it with AJAX
&lt;/h1&gt;

&lt;p&gt;So far, we've considered the case of validating subforms when data is submitted via a full-page postback.  However, you're likely to want to do subform validation using AJAX, asynchronously posting form data back to the Flask application using JavaScript.&lt;/p&gt;

&lt;p&gt;There's already an excellent article by Anthony Plunkett entitled "&lt;a href="https://medium.com/@doobeh/posting-a-wtform-via-ajax-with-flask-b977782edeee" rel="noopener noreferrer"&gt;Posting a WTForm via AJAX with Flask&lt;/a&gt;", which contains almost everything you need to know in order to do this.&lt;/p&gt;

&lt;p&gt;In this article, therefore, I'll just finish by elaborating on the one problem you'll have if doing this with multiple submit buttons - determining the submit button pressed&lt;/p&gt;

&lt;h2&gt;
  
  
  Determining the submit button pressed
&lt;/h2&gt;

&lt;p&gt;When posting data back to the server with JavaScript, you're likely to use a method like jQuery's &lt;a href="https://api.jquery.com/serialize/" rel="noopener noreferrer"&gt;serialize&lt;/a&gt;.  However, the data produced by this method doesn't include details of the button clicked to submit the form.&lt;/p&gt;

&lt;p&gt;There are &lt;a href="https://stackoverflow.com/questions/4007942/jquery-serializearray-doesnt-include-the-submit-button-that-was-clicked" rel="noopener noreferrer"&gt;various ways&lt;/a&gt; you can work around this limitation.  The approach I found most helpful was to dynamically add a hidden field to the form with the same name and value as the submit button (see &lt;a href="https://stackoverflow.com/a/11271850/328817" rel="noopener noreferrer"&gt;here&lt;/a&gt;).  That way, Python code like &lt;code&gt;if "submit-about-you" in request.form&lt;/code&gt; (see above) can remain unchanged whether you're using AJAX or postbacks.&lt;/p&gt;

</description>
      <category>flask</category>
      <category>wtforms</category>
      <category>python</category>
    </item>
  </channel>
</rss>
