I Build At Night

Bootstrapping = Development + Marketing

Installing the mysql2 gem on Windows

I recently upgraded to Ruby 2.1 via Rails Installer. After doing that I needed to install all of my gems again. Most installed correctly by mysql2 was painful. If you get stuck then these instructions might help

1. Download the MySQL C Connector. You need to make sure you get the Win32 version. I grabbed version 6.1.5 from the zip file here.

2. Uncompress the zip file into C:\ so that the connector is in C:\mysql-connector-c-6.1.5-win32

3. Install the mysql2 gem manually using the comment

C:\Sites>gem install mysql2 -- --with-mysql-lib=C:\mysql-connector-c-6.1.5-win32\lib --with-mysql-include=C:\mysql-connector-c-6.1.5-win32\include
Temporarily enhancing PATH to include DevKit...
Building native extensions with: '--with-mysql-lib=C:\mysql-connector-c-6.1.5-win32\lib --with-mysql-include=C:\mysql-connector-c-6.1.5-win32\include'
This could take a while...
Successfully installed mysql2-0.3.17
Parsing documentation for mysql2-0.3.17
Installing ri documentation for mysql2-0.3.17
Done installing documentation for mysql2 after 0 seconds
1 gem installed

Running bundle install or bundle update should now work correctly. If you need a specific version of the mysql2 gem then add the --version 0.3.7 option when running gem install.

The ultimate list of podcasts for bootstrappers

Are you looking for some inspiration to keep you going while you bootstrap your latest product? Below is my ultimate list of bootstrap related podcasts to keep you going during your late nights.
Continue reading

54 Great Bootstrap Examples

I’ve recently started mocking up the screens for Campaign Panel using the Bootstrap framework. As I’m not a designer I started by looking for Bootstrap examples to inspire me. During that search I came across Bootsnip. Below are 54 great bootstrap examples from that site broken up by category.
Continue reading

Rails SaaS Starter App

I love building SaaS products but I hate all of the time that gets wasted building the same basic infrastructure over and over and over and … Every time I build a SaaS application I have to build account/user/plan administration, multi-tenant support, permissions, payment processing, etc. Instead of continuing the cycle I’ve decided to build a SaaS starter app using Ruby on Rails that I’ll use for Campaign Panel.

Continue reading

Using Twitter Bootstrap with standard Ruby on Rails form helpers

I’ve been using Rails and Bootstrap for a while now. To make them play happy I’ve previously used simple_form which made life easy. For a recent project I wanted to see how far I could get using the standard Rails form helpers. It turns out that with a little custom CSS you can get a long way.

div.field_with_errors {
    display: inline;
}
.field_with_errors + .help-block,
.field_with_errors .control-label,
.field_with_errors .radio,
.field_with_errors .checkbox,
.field_with_errors .radio-inline,
.field_with_errors .checkbox-inline {
    color: #a94442;
}
.field_with_errors .form-control {
    border-color: #a94442;
    -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);
    box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);
}
.field_with_errors .form-control:focus {
    border-color: #843534;
    -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 6px #ce8483;
    box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 6px #ce8483;
}
.field_with_errors + .input-group-addon {
    color: #a94442;
    background-color: #f2dede;
    border-color: #a94442;
}
.field_with_errors + .form-control-feedback {
    color: #a94442;
}

This solution hasn’t been fully tested but for most form inputs it seems to work correctly. The only major issue is that it won’t highlight prefixed add on’s. If you’re using those then I would recommend removing the css for .field_with_errors + .input-group-addon so that suffixed add on’s also don’t highlight.

jQuery UI sortable

Recently I’ve been playing with a list of lists using the jQuery UI sortable component. Graphically it looks something like:

  • List 1
    • Item 1
    • Item 2
    • Item 3
  • List 2
    • Item 5
    • Item 6
    • Item 7
  • List 3
    • Item 7
    • Item 8
    • Item 9

The HTML for this is pretty simple

<ul  class="lists">
    <li>
        <h1>List 1</h1>
        <ul id="list_1" class="list">
            <li id="item_1">Item 1</li>
            <li id="item_2">Item 2</li>
           <li id="item_3">Item 3</li>
        </ul>
    </li>
    <li>
        <h1>List 2</h1>
        <ul id="list_2" class="list">
            <li id="item_4">Item 4</li>
            <li id="item_5">Item 5</li>
            <li id="item_6">Item 6</li>
        </ul>
    </li>
    <li>
        <h1>List 3</h1>
        <ul id="list_3" class="list">
            <li id="item_7">Item 7</li>
            <li id="item_8">Item 8</li>
            <li id="item_9">Item 9</li>
        </ul>
    </li>
</ul>

I want the user to be able to re-order the lists, the items in each list and move items from one list to another. 18 lines of Javascript later I had it handling this perfectly and displaying alerts telling me where items were moved to, the list they were in and if the lists were re-ordered.

$(function() {
    $(".lists").sortable({
        forcePlaceholderSized: true,
        stop: function(event, ui) {
            var list = ui.item.children('ul').attr('id').replace('list_', '');
            window.alert('Moving list ' + list + ' to position ' + ui.item.index());
        },
    });
    $(".list").sortable({
        connectWith: ".list",
        forcePlaceholderSized: true,
        stop: function(event, ui) {
            var item = ui.item.attr('id').replace('item_', '');
            var list = ui.item.parent().attr('id').replace('list_', '');
            window.alert('Moving item ' + item + ' to list ' + list + ' position ' + ui.item.index());
        },
    });
});

I love jQuery and jQuery UI.

Auto Increment in SugarCRM

Earlier today I posted about creating a DateTime Picker in SugarCRM. A second problem I had was creating an auto increment field. This turned out to be slightly more difficult than the datetime picker. Again you need to edit your vardefs.php but this time you add the following to your field.

'auto_increment' => true,

You then need to manually alter the table structure so the id field is a unique index instead of a primary key then add your new column to the database as an auto_increment field and the tables primary key. I also found that if you try to install the module on another system it will fail because it can’t create the table properly. You can solve that by creating the table then installing the module.

Date/Time Picker in SugarCRM

Recently I needed to add a date/time field to a custom SugarCRM module. Sadly the module builder doesn’t include support this and the documentation is pretty bad. Eventually I managed to solve my problem and the solution is suprisingly simple.

After adding a date field to the form I edited my vardefs.php file. You’ll find the file in custom/modulebuilder/packages/package_name/modules/module_name/. Find the field and change it’s type to datetime.

Next you need to change your views. They’re located in custom/modulebuilder/packages/package_name/modules/module_name/metadata. In my case I wanted to the edit view to show a datepicker plus a time combo. I found the field and added

'type' => 'Datetimecombo'

After that I deployed the package and my module was now saving as a date/time and in the edit view I could set both the date (using a date picker) and time (using drop down lists).

Dynamic forms using Zend_Form

While most forms contain fixed fields there are occasions when you need a form to be dynamic and adjust itself based on user input. The adjustment could be as simple as altering the options in a drop down list or as complex as adding/removing fields. In this post I’m going to cover how to create a dynamic form using Zend_Form and jQuery. I’ll use the example of a registration form that prompts the user for their country and state. The requirements are pretty simple:

  1. It should only prompt for a state if the country has states.
  2. The state list should only show states for the selected country.
  3. The form should degrade gracefully so it works without Javascript

To start I’m going to create a World class. This class has two functions. The first returns a list of countries. The second returns a list of states for a specified country or a list of all countries that have states plus the states in those countries. You might like to retrieve this information from a database but for simplicity I’ll hard code the information into the class.

class World
{
    static private $_countries = array(
                       "AU" => "Australia",
                       "NZ" => "New Zealand");

    static private $_states = array(
		        "AU" => array(
		            "ACT" => "Australian Capital Territory",
		            "NSW" => "New South Wales",
		            "NT" => "Northern Territory",
		            "QLD" => "Queensland",
		            "SA" => "South Australia",
		            "TAS" => "Tasmania",
		            "VIC" => "Victoria"));

    public function getCountries()
    {
        return self::$_countries;
    }

    public function getStates($country = null)
    {
        if ($country === null) {
            return self::$_states;
        }
        if (array_key_exists($country, self::$_states)) {
            return self::$_states[$country];
        }
        return null;
    }
}

Next I’ll create a class for the form (RegForm) by extending Zend_Form. This gives our registration form all of the advantages you get from Zend_Form including input filtering and validation. The form elements will be added in the constructor so that creating a new form is all you need to do to use it.

As our form needs to adapt based on user input the constructor needs to accept the user input as one of its parameters. This allows us to adjust the form elements based on the user input. All code using these parameters needs to be extremely careful as the user input has not been filtered or validated yet.

class RegForm extends Zend_Form
{
    public function __construct($world, $params)
    {
        parent::__construct();

        $countries = $world->getCountries();
        $countryKeys = array_keys($countries);
        $thisCountry = isset($params['country']) ? $params['country'] : $countryKeys[0];
        $states = $world->getStates($thisCountry);

        $country = new Zend_Form_Element_Select('country');
        $country->setLabel('Country')
                ->setMultiOptions($countries)
                ->setValue($thisCountry)
                ->setRequired(true);
        $this->addElement($country);

        $state = new Zend_Form_Element_Select('state');
        $state->setLabel('State');
        if ($states !== null) {
            $state->setMultiOptions($states)
                  ->setRequired(true);
        } else {
            $state->setRegisterInArrayValidator(false);
        }
        $this->addElement($state);

        $submit = new Zend_Form_Element_Submit('submit');
        $submit->setValue('Add User')
               ->setRequired(false);
        $this->addElement($submit);
    }
}

There are two important things that RegForm does:

  1. The state options are adjusted to match the selected country.
  2. The state is not validated if the country does not contain states.

This means that our form will work exactly the way you expect Zend_Form to work. Without Javascript if you select a country and submit the form then the state list will adjust and display an error that the previously selected state was invalid. After you select a valid country and state the form will validate. If the selected country does not have states then the form with validate regardless of the selected state (providing there are no other errors).

I then need to create the controller.

class AccountController extends Zend_Controller_Action
{
    public function indexAction()
    {
        $params = $this->_getAllParams();
        $world = new World();
        $form = new RegForm($world, $params);
        if ($this->_request->isPost() && $form->isValid($params)) {
            // The form was valid!!
        }
        $this->view = $form;
    }
}

Finally we can add Javascript to alter the form in browser. If you’re using the forms render() function then the Javascript will look something like this.

    var countries = <?php echo json_encode($this->world->getCountries()); ?>;

    var states = <?php echo json_encode($this->world->getStates()); ?>

    function updateStates() {
        var state = $("#state");
        var country = $("#country");
        var hasStates = false;
        jQuery.each(states, function (cc, slist) {
            if (cc == country.val()) {
                hasStates = true;
                state.html('');
                jQuery.each(slist, function (code, name) {
                    state.append('<option value="' +  code + '">' + name + '</option>');
                });
            }
        });
        if (hasStates) {
            $("#state-label").css("display", "block");
            $("#state-element").css("display", "block");
        } else {
            $("#state-label").css("display", "none");
            $("#state-element").css("display", "none");
        }
    }
    $().ready(function () {
        $("#country").change(function () {
            updateStates();
        });
        var state = $("#state");
        if (state.val() == null) {
            $("#state-label").css("display", "none");
            $("#state-element").css("display", "none");
        }
    });

This code takes care of hiding the states if they are not required and adjusting the states based on the selected country without needing to submit the form. With minimal effort I’ve been able to create a dynamic form using Zend_Form to do most of the hard work. Users with Javascript enabled get an A grade experience while those without Javascript can still use the form.

© 2015 I Build At Night

Theme by Anders NorenUp ↑