VisezTrance

  • January 23, 2011 7:27 PM

    A ruby on rails frontend implementation story

    By Daniel
    For the last year I have been working on a large social network website.
    As I preper to move forward I can't help thinking of the challenges that aroused during this time.
    One in particular stood out. The form fields were heavily customised - every field, be it a simple text or select, even file uploads were all styled.
    The design was less than ideal for a project this size to say the least.

    While I didn't code the html I had to find a solution to integrate it that worked well and wouldn't prove to be time consuming.
    The solution I chose was to extend the default form and use it across the site. Even if these forms were to be styled with javascript it would had just resulted in a poor user experience as each page form would briefly be displayed naked then quickly styled.

    Bear in mind that this code runs under Rails 2. It may require some adjustments to work with 3.

    Firstly I defined my own form builder:

    class CustomFormBuilder < ActionView::Helpers::FormBuilder

      include ActionView::Helpers::TagHelper
      include ActionView::Helpers::AssetTagHelper

      ..

    end

    As it was going to be used sitewise I also made it default in my environment file:

    ActionView::Base.default_form_builder = CustomFormBuilder

    Each text field had to be enclosed in a specific span tag with the class "input_text". Targeting with input[type="text"] would had probably worked just as well if you ignore IE6.

    def text_field(method, wrapper_options = {}, input_options = {})
      wrapper_options[:class] = (wrapper_options[:class].to_s + ' input_text').strip
      wrapper_options.reverse_merge!({ :class => 'input_text' })
      content_tag :span, @template.send(:text_field, @object_name, method, objectify_options(input_options)), wrapper_options
    end

    You can style both the wrapper and the input field with separate option hashes.
    The password, textarea and select fields were similarly styled. The latter was albeit more difficult but I'm not going to post the code as the markup differs significantly from one implementation to another.

    After doing these I received an interesting request of extending the label tag, having many fields that were mandatory and had to be displayed accordingly.

    def label(method, text = nil, options = {})
      if options[:required]
        text = (text || method.to_s.humanize) + ' <span class="highlight">*</span>'
      end
      super
    end

    To do the file uploads (which were surprisingly plentiful) I decided on creating my own helpers, rather than just extending the basic "file". This was mostly because I needed both an actual file upload and a photo upload which had a very different behaviour such a live thumbnails. I used flash (swf upload) because it was the only crossbrowser way of selecting multiple files and styling the actual button.

    def flash_photo_upload(name = 'files', options = {})
      locals = {
        :f => self,
        :name => name.to_s,
        :queue_limit => options['queue_limit']
      }

      @template.render :partial => 'partials/flash_file_upload', :locals => locals
    end

    There's a large amount of code responsible for the entire upload process, that's why I isolated it in a partial. Why so much code you ask, well for instance once one or more photos gets uploaded they're displayed in a carousel; also take into consideration that it had to work seamlessly when editing.

    The final piece was styling the submit buttons (and also some links that needed to look as buttons) - rounded cornered of different size and backgrounds using a beautiful but proprietary font with a text shadow. We had to support IE, so CSS3 was out of the question because we needed the rounded corners which don't degrade very well. Legal font issues aside, normally I would be doing this with the sliding doors css technique. I went the extra mile and generated the images in ruby using the same css technique but with rmagick. The code partially supported some css parameters to make styling easier.
    I extracted that code and made it public as a gem named magic_door. The helpers are packed separately as a plugin.

    I hope this helps anyone who faces a similar situation.

    Tags:

    • frontend implementation,
    • ruby on rails
  • Monthly Archives

    • October 2013 (2)
    • May 2012 (1)
    • October 2011 (1)
    • September 2011 (2)
    • March 2011 (3)
    • February 2011 (1)
    • January 2011 (1)
    • September 2010 (1)
    • August 2010 (1)
    • June 2010 (1)
    • April 2010 (1)
    • December 2009 (1)
    • October 2009 (1)
    • September 2009 (1)
    • August 2009 (1)
    • July 2009 (2)
    • April 2009 (2)
    • February 2009 (1)
    • January 2009 (2)
    • December 2008 (1)
    • October 2008 (1)
  • Pages

    • About / Contact

2008, © Daniel Mircea