Category: Ruby on Rails

  • Web Application 101

    I often see questions on Stack Overflow that show an inherent misunderstanding of how web applications, and more specifically, ruby on rails, work. It usually involves some form of, “How do I run ruby code on a button click” or “How can I get these javascript variables to the parameters of this ruby function?”

    The problem here is one of not understanding where certain code is executed in the cycle of a web app, so let’s review. In a nutshell:

    Request Cycle Where it happens Primary language
    Form Submission or Ajax request Browser html/css/javascript
    GET/POST Network HTTP
    Controller Server ruby
    View erb/html/css (javascript set up but not executed)
    HTML Response or JSON/XML Network HTTP
    Render page or response Browser html/javascript

    Anything that needs to be run in ruby has to be done so on the server, and anything done in javascript is done on the web browser. Thus, if you need to have some data in the browser, whether in a form or in javascript, interact with ruby code, you have to begin the whole cycle from the start. Bundle the data up into a form or an ajax request and send the request to the server. Have a rails controller/view respond to it. This can be a whole page, or it can be a JSON or XML response, whatever. Then the browser handles the response by rendering a new page or dynamically handling the response.

    When you need data to cross from one environment to the other, you have to do it through a HTTP request. That is the core of web application technology!

    Of course, the tricky part comes when the view is writing javascript that is going to be run in the browser. The key to remember is execution time, and when the data is available. You can put variables into javascript code to be run if you know it ahead of time:

    [sourcecode language=”html”]
    <script type="text/javascript">
    alert("here is a ruby variable: <%= @foo %>");
    </script>
    [/sourcecode]

    However, if the data is going to be decided by the actual execution of the javascript, it is too late to access it from ruby in this request cycle; time to generate a new request cycle!

    Advanced solutions include sending along partials hidden in the page or javascript and then rendering them with javascript, such as with handlebars. That is a big enough subject for a future post.

  • SCSS and Compass put the “Zen” back into grid layouts

    When I started a particular auction application in Rails 3.0, I took the time to try out a grid layout library.  There are a number of them out there, and for unknown reasons to me now, I chose Blueprint.  It worked well, and I quickly had a usable site with much less hassle on the layout side of things.  However, the hassle proved to be greater on the print media. No surprise; printing from HTML has always been a painful ordeal.

    Recently during a site update, I realized what the biggest problem was:   I still had the same ‘span-4’  type classes in the html, but was setting a ‘display: none’ on some columns like navigation sidebars.  This resulted in a 4 column wasted whitespace that I couldn’t easily get rid of.  As a result, my printing was always off center, and restricted in space.

    [sourcecode language=”html”]
    <div class="container">
    <div id="header" class="span-24">
    This header goes across the whole screen
    </div>
    <div id="nav" class="span-4">
    Navigation stuff
    </div>
    <div id="maincontent" class="span-20 last">
    Main content
    </div>
    </div>
    [/sourcecode]

    As you can see, the layout is very straight forward, but rigid; the content section is 20 columns whether you show the nav section or not. That’s the problem with grid layouts – you end up  putting non-semantic markup in your html.   Then your design is stuck, and other media types are in pain.

    Enter rails 3.2 and the asset pipeline.  I discovered that Compass, a set of SASS mixins, also bundled Blueprint, making it a no-brainer to upgrade to SCSS and Compass.    I was able to remove the Blueprint css files from the project and replace them with few simple calls like `@import “blueprint”`. This allowed me to delete several css files from my own source code management, as they are bundled in the compass-rails gem.

    Then the real magic begins.  Instead of specifying ‘span-4’ in the nav section, I include the styles into a semantic name. The same is true for the main content areas, in an easy to read form that makes it clear what is happening:

    [sourcecode language=”css”]
    .container {
    @include container;
    #nav {
    @include column(4);
    }
    #header {
    @include column(24);
    @include last();
    }
    #maincontent {
    @include column(20);
    @include last();
    }
    }
    [/sourcecode]

    The styles that define a column are inserted directly into the nav styling.  The magic of SCSS transforms that into normal CSS for us. I won’t go into the details of SCSS features here, but you if you are familiar with CSS, you may notice this looks like CSS, but also has nesting and includes. The generated CSS has all of the formatting integrated into the semantic names. Here’s an example of what it turned into.

    The html can now be simplified down to:

    [sourcecode language=”html”]
    <div class="container">
    <div id="header">
    This header goes across the whole screen
    </div>
    <div id="nav">
    Navigation stuff
    </div>
    <div id="maincontent">
    Main content
    </div>
    </div>
    [/sourcecode]

    Why is this important?  First, the html itself is much cleaner, with meaningful names and no explicit formatting, making it much more readable. But look what happens in the print media css:

    [sourcecode language=”css”]
    header, nav {
    display: none;
    }
    .container {
    @include container;

    #maincontent {
    @include column(24);
    @include last();
    }
    }
    [/sourcecode]

    The nav and header sections are hidden, and the content section now has a full 24 columns, instead of 19!  Sweet zen! The page now uses the full size of the page, without needing any changes to the html.

    There were many other benefits to using SASS and Compass, such as variables, and mixins for advanced features such as drop shadows and rounded corners, but that was just icing on the cake.

    Having converted my layout, the print stylesheets worked much better, and I was able to get all the forms printed for this year’s event. However, web browsers still often don’t handle things consistently, and where page breaks and margins worked for me, they didn’t always work for others. So I am preparing to ditch printing from the web browser and instead, render straight to pdf for more precise printouts. I’ll save that for another post.

  • Converting a php page to Ruby on Rails

    Today I converted a partial page from PHP and Smarty into Ruby on Rails, part of a major rewrite of Maia Mailguard.
    The information for this screen come from one database table, though some elements do not map one to one to the inputs seen one the screen. Here’s the basic form, sans I18N translations:

    The original PHP page can be found on the maiamailguard.com website.

    My thoughts about that code? It violates the “Don’t Repeat Yourself” (DRY) principle. There is a lot of repetition of elements, both syntactical and semantic. For example a quick scan shows repetitions of input type=”radio” name=“*_destiny” ; just one of many. It is simply tiresome to read and understand.

    Changing gears to Ruby on Rails, my first thought was that a plugin called Formtastic has the ability to make a collection of radio buttons all from one input helper call, a clear improvement to repeating nearly the same code for each radio input. I soon had that included in the project and it works as advertised… except it put the radio in a vertical line rather than a horizontal line.

    The solution to this was to extend formtastic to add my own control. Rather than include all of the code here, I’ll just link the github changeset where you can view it. Essentially, I created a control named “radio_group”, based on the original radio_input control, but with a few changes to the html it generated. Once this was done, I was able to produce an entire row like this:

    <%= f.input :banned_files_destiny, :as=>:radio_group,
        :label => t(:text_mail_with_attachments),
        :collection=>[[ t(:text_labeled),     'label'],
                                  [ t(:text_quarantined), 'quarantine'],
                                  [ t(:text_discarded),   'discard']
                                ],
         :wrapper_html => { :class => "banned_filebody2" }
    %>

    This cut down a lot of repeated html, though one may argue that it is in fact a few lines longer that the plain html. Nevertheless I think the rails version at this point is already far more readable. However, I didn’t stop there.

    After finishing with that conversion, I noticed again that there is a lot of repetition. Four destiny lines, four bypass lines and three threshold inputs each share a lot of code. I refactored these into four helper methods, with parameters for all the essential bits of information. The end result is a stunning improvement.

    This creates a one to one mapping of each visible row to a single statement such as:

    <%= destiny_input(  f,  :banned_files_destiny,    :text_mail_with_attachments,   "banned_filebody2") %>

    Some other minor notes about the code you see: The t(:text) is a helper function built into rails to look up keys in a I18N (Internationalization) dictionary to translate the text. At the point of the screenshot above, I hadn’t entered those translations into the dictionary, so it shows placeholders. The good news is that those translations don’t impeded the code process in this page.

    Also, if you really dig deep you may discover that the policies table does not in fact have any column named *_destiny, yet the first parameter to f.input is supposed to be the name of a database column. Actually, it is the name of a method on the Policy class. The database schema used by amavisd-new has two sets of columns of interest here, *_lover and discard_*. If *_lover is true it will allow the message through regardless of of its status, and if discard_* is true, it discards it. One wonders what happens if both are set to true!

    In the previous versions of Maia, we worked around this by instead asking for a designation of “label”, “quarantine”, or “discard” – and set the real database columns accordingly. To manage this in rails was actually quite easy, easier to read than the php version. I added a set of functions to the Policy class:

    def virus_destiny=(destiny)
      self.virus_lover     = (destiny == "label"   ? "Y" : "N");
      self.discard_viruses = (destiny == "discard" ? "Y" : "N");
    end
    
    def virus_destiny
      return 'label'      if self.virus_lover
      return 'discard'    if self.discard_viruses
      return 'quarantine'
    end

    Short and sweet, it accesses and sets the two columns according to the choice made from the form. The form simply sees the virus_destiny methods and doesn’t know that it really represents two columns in the model.

    While porting a project like this is never fast and easy, the improvements made to this one little corner of Maia Mailguard make for a beautiful example of the power and readability of Ruby on Rails, and has me quite excited to continue working on “Maia on Rails”.