Use “rails” instead of “rake” in Rails 5

A pain point for new Rails developers is learning which command goes after the “rails” keyword and which go after the “rake” keyword. In Rails 5, just use “rails”.

The source of this issue in previous versions of Rails is the fact that some commands make sense to be rails commands, such as rails server, and are not implemented as rake tasks, but the rest are implemented as rake tasks and are therefore called using rake. If you implement your own rake tasks, you would have had to also call them using rake.

In Rails 5, code has been added to import all rake tasks and make them accessible using the rails keyword. Say you had the following rake task:

desc '####################### custom task'
task custom_task: :environment do
  puts 'Executing the custom task...'
end

You can now access it using rails:

$ rails custom_task
Executing the custom task...
$

You can see how all the rake tasks are included in the rails help message:

$ rails --help
Usage: rails COMMAND [ARGS]

The most common rails commands are:
 generate    Generate new code (short-cut alias: "g")
 console     Start the Rails console (short-cut alias: "c")
 server      Start the Rails server (short-cut alias: "s")
 test        Run tests (short-cut alias: "t")
 dbconsole   Start a console for the database specified in config/database.yml
             (short-cut alias: "db")
 new         Create a new Rails application. "rails new my_app" creates a
             new application called MyApp in "./my_app"

All commands can be run with -h (or --help) for more information.

In addition to those commands, there are:
 destroy                             Undo code generated with "generate" (short-cut alias: "d")
 plugin new                          Generates skeleton for developing a Rails plugin
 runner                              Run a piece of code in the application environment (short-cut alias: "r")
 about                               List versions of all Rails frameworks and the environment
 assets:clean[keep]                  Remove old compiled assets
 assets:clobber                      Remove compiled assets
 assets:environment                  Load asset compile environment
 assets:precompile                   Compile all the assets named in config.assets.precompile
 cache_digests:dependencies          Lookup first-level dependencies for TEMPLATE (like messages/show or comments/_comment.html)
 cache_digests:nested_dependencies   Lookup nested dependencies for TEMPLATE (like messages/show or comments/_comment.html)
 custom_task                         ####################### custom task
 db:create                           Creates the database from DATABASE_URL or config/database.yml for the current RAILS_ENV (use db:create:all to create all databases in the config)
 db:drop                             Drops the database from DATABASE_URL or config/database.yml for the current RAILS_ENV (use db:drop:all to drop all databases in the config)
 db:fixtures:load                    Loads fixtures into the current environment's database
 db:migrate                          Migrate the database (options: VERSION=x, VERBOSE=false, SCOPE=blog)
 db:migrate:status                   Display status of migrations
 db:rollback                         Rolls the schema back to the previous version (specify steps w/ STEP=n)
 db:schema:cache:clear               Clears a db/schema_cache.dump file
 db:schema:cache:dump                Creates a db/schema_cache.dump file
 db:schema:dump                      Creates a db/schema.rb file that is portable against any DB supported by Active Record
 db:schema:load                      Loads a schema.rb file into the database
 db:seed                             Loads the seed data from db/seeds.rb
 db:setup                            Creates the database, loads the schema, and initializes with the seed data (use db:reset to also drop the database first)
 db:structure:dump                   Dumps the database structure to db/structure.sql
 db:structure:load                   Recreates the databases from the structure.sql file
 db:version                          Retrieves the current schema version number
 initializers                        Print out all defined initializers in the order they are invoked by Rails
 log:clear                           Truncates all *.log files in log/ to zero bytes (specify which logs with LOGS=test,development)
 middleware                          Prints out your Rack middleware stack
 notes                               Enumerate all annotations (use notes:optimize, :fixme, :todo for focus)
 notes:custom                        Enumerate a custom annotation, specify with ANNOTATION=CUSTOM
 rails:template                      Applies the template supplied by LOCATION=(/path/to/template) or URL
 rails:update                        Update configs and some other initially generated files (or use just update:configs or update:bin)
 restart                             Restart app by touching tmp/restart.txt
 routes                              Print out all defined routes in match order, with names
 secret                              Generate a cryptographically secure secret key (this is typically used to generate a secret for cookie sessions)
 stats                               Report code statistics (KLOCs, etc) from the application or engine
 test                                Runs all tests in test folder
 test:db                             Run tests quickly, but also reset db
 time:zones:all                      Displays all time zones, also available: time:zones:us, time:zones:local -- filter with OFFSET parameter, e.g., OFFSET=-6
 tmp:clear                           Clear cache and socket files from tmp/ (narrow w/ tmp:cache:clear, tmp:sockets:clear)
 tmp:create                          Creates tmp directories for cache, sockets, and pids
$

Compare that to the output of rake -T:

$ rake -T
rake about                              # List versions of all Rails frameworks and the environment
rake assets:clean[keep]                 # Remove old compiled assets
rake assets:clobber                     # Remove compiled assets
rake assets:environment                 # Load asset compile environment
rake assets:precompile                  # Compile all the assets named in config.assets.precompile
rake cache_digests:dependencies         # Lookup first-level dependencies for TEMPLATE (like messages/show or comments/_comment.html)
rake cache_digests:nested_dependencies  # Lookup nested dependencies for TEMPLATE (like messages/show or comments/_comment.html)
rake custom_task                        # ####################### custom task
rake db:create                          # Creates the database from DATABASE_URL or config/database.yml for the current RAILS_ENV (use db:create:all to create all databases in the config)
rake db:drop                            # Drops the database from DATABASE_URL or config/database.yml for the current RAILS_ENV (use db:drop:all to drop all databases in the config)
rake db:fixtures:load                   # Loads fixtures into the current environment's database
rake db:migrate                         # Migrate the database (options: VERSION=x, VERBOSE=false, SCOPE=blog)
rake db:migrate:status                  # Display status of migrations
rake db:rollback                        # Rolls the schema back to the previous version (specify steps w/ STEP=n)
rake db:schema:cache:clear              # Clears a db/schema_cache.dump file
rake db:schema:cache:dump               # Creates a db/schema_cache.dump file
rake db:schema:dump                     # Creates a db/schema.rb file that is portable against any DB supported by Active Record
rake db:schema:load                     # Loads a schema.rb file into the database
rake db:seed                            # Loads the seed data from db/seeds.rb
rake db:setup                           # Creates the database, loads the schema, and initializes with the seed data (use db:reset to also drop the database first)
rake db:structure:dump                  # Dumps the database structure to db/structure.sql
rake db:structure:load                  # Recreates the databases from the structure.sql file
rake db:version                         # Retrieves the current schema version number
rake initializers                       # Print out all defined initializers in the order they are invoked by Rails
rake log:clear                          # Truncates all *.log files in log/ to zero bytes (specify which logs with LOGS=test,development)
rake middleware                         # Prints out your Rack middleware stack
rake notes                              # Enumerate all annotations (use notes:optimize, :fixme, :todo for focus)
rake notes:custom                       # Enumerate a custom annotation, specify with ANNOTATION=CUSTOM
rake rails:template                     # Applies the template supplied by LOCATION=(/path/to/template) or URL
rake rails:update                       # Update configs and some other initially generated files (or use just update:configs or update:bin)
rake restart                            # Restart app by touching tmp/restart.txt
rake routes                             # Print out all defined routes in match order, with names
rake secret                             # Generate a cryptographically secure secret key (this is typically used to generate a secret for cookie sessions)
rake stats                              # Report code statistics (KLOCs, etc) from the application or engine
rake test                               # Runs all tests in test folder
rake test:db                            # Run tests quickly, but also reset db
rake time:zones:all                     # Displays all time zones, also available: time:zones:us, time:zones:local -- filter with OFFSET parameter, e.g., OFFSET=-6
rake tmp:clear                          # Clear cache and socket files from tmp/ (narrow w/ tmp:cache:clear, tmp:sockets:clear)
rake tmp:create                         # Creates tmp directories for cache, sockets, and pids
$

You’ll see that rails has several tasks that aren’t rake tasks, but then after those it includes all the rake tasks and their descriptions.

You can read more about the motivations behind this feature in the issue tracker: https://github.com/rails/rails/issues/18878

There’s a Pull Request with most of the changes here: https://github.com/rails/rails/pull/21254/files but other fixes are being added so it may be better to just browse the latest code if you need to see what’s happening under the hood.

Posted in Technology | Tagged , , | Leave a comment

Rails 5 adds method source

Here is an example of the Rails team making it easier for developers to access much needed tools: you can now inspect the source code for a method right from irb. Say you had the following source code:

class Flower < ApplicationRecord
  # opens the flower
  def bud
    puts 'budding'
  end
end

In irb you can do:

Flower.instance_method(:bud).source

=> "  def bud\n    puts 'budding'\n  end\n"

Flower.instance_method(:bud).comment

=> "# opens the flower\n"

This functionality is from a gem called method_source, which is one component of a developer console (alternative to irb) called pry. The method_source gem is now included in the development section of the Gemfile generated by Rails when you create a new application. This makes it easier for developers to quickly access this bit of functionality without having to switch to using pry.

The tests for this gem show all the ins and outs of using it:
https://github.com/banister/method_source/blob/master/test/test.rb

You can read more about the motivations and discussion around this feature on the PR:
https://github.com/rails/rails/issues/18473

Posted in Technology | Tagged , | Leave a comment

Rails 5 adds ActiveRecord or

Here’s a long awaited feature that is added in Rails 5: ActiveRecord or.

Previously you had to use ARel or resort to a SQL snippet:

Flower.where('smell = ? OR color = ?', 'nice', 'bright')

# => SELECT "flowers".* FROM "flowers" WHERE (smell = 'nice' OR color = 'bright')

Now you can do:

Flower.where(smell: 'nice').or(Flower.where(color: 'bright'))

# => SELECT "flowers".* FROM "flowers" WHERE ("flowers"."smell" = ? OR "flowers"."color" = ?)  [["smell", "nice"], ["color", "bright"]]

In other words: you first build a relation, then use the or method on it passing in as an argument another relation. These two relations must be “structurally compatible”: scoped on the same model, and not using limit, offset or uniq. You can see what you can and can’t do with this in more detail by looking at the test cases.

More details at the commit or the PR.

Posted in Technology | Tagged , , | Leave a comment

Using wrap_parameters to allow a non-ActiveRecord parameter

Rails 4 introduced strong parameters:

With strong parameters, Action Controller parameters are forbidden to be used in Active Model mass assignments until they have been whitelisted. This means that you’ll have to make a conscious decision about which attributes to allow for mass update. This is a better security practice to help prevent accidentally allowing users to update sensitive model attributes.

There are some caveats to using them, and I found this article helpful in understanding what’s going on behind the scenes: http://patshaughnessy.net/2014/6/16/a-rule-of-thumb-for-strong-parameters

One issue I have come across a couple of times now, which I would like to describe here, concerns explicitly permitting a parameter in addition to the attributes of an ActiveRecord model.

In one case, my model included a field, let’s call it code, composed of two parts: ABC.123. It was convenient to store this as one field in the database, but I wanted to separate it into two input fields in the UI, only one of which could be modified. So to handle this I wrote two readers and a setter on the model. Here’s what I mean (leaving out handling of edge cases):

def code_letters
  code.split('.').first()          # e.g. ABC
end

def code_numbers
  code.split('.').last()           # e.g. 123
end

def code_numbers=(value)
  write_attribute(:code, "#{code_letters}.#{value}")
end

Next, I added an entry to the parameter whitelisting in the controller:

def model_params
  params.require(:account).permit(:other_fields, :code_numbers)
end

This, however, was not enough. The value was POSTed fine, but was not available in the controller after calling model_params. There was no easy way of figuring out what to do, but I eventually came across a solution: wrap_parameters.

This takes the form of either an :include list, or an :exclude list; I couldn’t just specify one additional parameter to be let through. So I specified them all:

class AccountsController < ApplicationController
  wrap_parameters include: Account.attribute_names + [:code_numbers]
end

ParamsWrapper actually uses the model’s attribute_names method by default, so I simply specified the default and tacked on what I needed to add.

Of course, there are always better solutions, and if this type of abstraction becomes more common I would introduce a layer around the model which would be the subject of the form’s POST, then translate each attribute onto the model as needed.

Posted in Technology | Leave a comment

Using a period in YAML tokens

While working on an internationalized Rails application, I came across a case where the names of countries were being translated through the YAML locale configuration files. While a valid short-term measure, I would prefer using a gem like Globalize and storing the translations in a Country model, for example.

But in the meanwhile, I was asked to update some of the translations, and quickly discovered that you can’t use a period (a.k.a full-stop) in the token names. I tried surrounding them with quotes: "St. Lucia": St. Lucia, escaping them with a slash "St\. Lucia": St. Lucia, looking up the documentation, to no avail. I finally realized I could just break them into parent and child level tokens, like a period is meant to do:

period-in-yaml

Horrible, but works. If you use t("St. Lucia") in your code you get a valid result!

Posted in Technology | Leave a comment

How to clear the Clipboard when exiting Microsoft Word

This week a colleague approached me to consult about a problem he had encountered, where it was necessary to ensure that the Clipboard was empty when Microsoft Word exits. It was part of a legacy Word automation solution that he wasn’t in a position to change just yet, and it would crash if there was anything left on the clipboard.

Two approaches came to mind, one using a Word VBA Macro, the other using a VSTO add-in. Here is an attempt at a solution for the first approach – let’s hope it fixes the problem.

You can hook into events using Word VBA quite easily, either by creating a macro with a special name (reference: http://msdn.microsoft.com/en-us/library/bb208800.aspx), or by setting up event handlers. In this case, we will use a macro called AutoExit which is invoked “when you exit Word or unload a global template”. We’ll save the macro in a template file and have it loaded as a global template, so this event should be ideal for our purposes.

The first step is to load Word and get to the Visual Basic editor (press Alt-F11). Here, double-click on the ThisDocument entry in the project explorer to open up a code window:

Then, copy and paste the following code (which I will explain soon) into the code window you just opened:

'Events: http://msdn.microsoft.com/en-us/library/bb208800.aspx
Sub AutoExit()
    ClearClipboard
End Sub

Sub ClearClipboard()
    Dim MyData As Object
    ' source: http://akihitoyamashiro.com/en/VBA/LateBindingDataObject.htm
    Set MyData = CreateObject(&quot;new:{1C3B4210-F441-11CE-B9EA-00AA006B1A69}&quot;)
    MyData.SetText &quot;&quot;
    MyData.PutInClipboard
    Set MyData = Nothing
End Sub

Now save the document as a Word Macro-Enabled Document Template (.dotm) with a name such as ClearClipboardOnWordExit.dotm:

Place this document in the Word Startup folder. By default, it should be %appdata%\Microsoft\Word\Startup, but you can find out where it really is by going to Word Options, Advanced, scrolling to the bottom and clicking on File Locations:

Word will load any templates in this folder as global templates when it starts.

That’s about it! Now to test it, open Word afresh, type something and copy it to the clipboard. Then exit Word and check to confirm that the clipboard no longer has the text you just copied.

Explanation of the code

  • The name of the macro, AutoExit, makes it get called when Word is closing:
    Sub AutoExit()
        ClearClipboard
    End Sub
    
  • Then we create a DataObject, which is part of the Microsoft Forms 2.0 Object Library. However, instead of adding a reference to it, I prefer using late binding so I found this page that describes how to do it using the clsid: http://akihitoyamashiro.com/en/VBA/LateBindingDataObject.htm

        Dim MyData As Object
        Set MyData = CreateObject(&quot;new:{1C3B4210-F441-11CE-B9EA-00AA006B1A69}&quot;)
    
  • Using this object, we set a blank string to the clipboard, effectively clearing it:
        MyData.SetText &quot;&quot;
        MyData.PutInClipboard
    
Posted in Technology | Tagged , , , | 1 Response

Get email Headers from an Outlook MailItem

While working on a VSTO add-in for Microsoft Outlook, I came across the need to access the headers of an email, to parse out X-CustomProperty tags that were put in by an application that sent the emails. However, I couldn’t find a Headers property in the Outlook object model, so below is an attempt to create one.

The Regex used is courtesy of John Gietzen’s answer on this stackoverflow question.

using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using Microsoft.Office.Interop.Outlook;

public static class MailItemExtensions
{
    private const string HeaderRegex =
        @"^(?<header_key>[-A-Za-z0-9]+)(?<seperator>:[ \t]*)" +
            "(?<header_value>([^\r\n]|\r\n[ \t]+)*)(?<terminator>\r\n)";
    private const string TransportMessageHeadersSchema =
        "http://schemas.microsoft.com/mapi/proptag/0x007D001E";

    public static string[] Headers(this MailItem mailItem, string name)
    {
        var headers = mailItem.HeaderLookup();
        if (headers.Contains(name))
            return headers[name].ToArray();
        return new string[0];
    }

    public static ILookup<string, string> HeaderLookup(this MailItem mailItem)
    {
        var headerString = mailItem.HeaderString();
        var headerMatches = Regex.Matches
            (headerString, HeaderRegex, RegexOptions.Multiline).Cast<Match>();
        return headerMatches.ToLookup(
            h => h.Groups["header_key"].Value,
            h => h.Groups["header_value"].Value);
    }

    public static string HeaderString(this MailItem mailItem)
    {
        return (string)mailItem.PropertyAccessor
            .GetProperty(TransportMessageHeadersSchema);
    }
}

Sample usage:

string[] preparedByArray = mailItem.Headers("X-PreparedBy");
string preparedBy;
if (preparedByArray.Length == 1)
    preparedBy = preparedByArray[0];
else 
    preparedBy = "";

string allHeaders = mailItem.HeaderString();

Edit 2011/08/05:
Thanks to Rob for the heads-up. I updated the code to return a Lookup instead of a Dictionary – this handles the case of multiple headers with the same name.

Posted in Technology | Tagged , , , , , , | 4 Responses

How to filter select list options

Here’s a jQuery extension method to filter the elements of a select list (option tags). It binds to a textbox, and as you type in the textbox the select list gets filtered to match what you are typing.

jQuery.fn.filterByText = function(textbox, selectSingleMatch) {
  return this.each(function() {
    var select = this;
    var options = [];
    $(select).find('option').each(function() {
      options.push({value: $(this).val(), text: $(this).text()});
    });
    $(select).data('options', options);
    $(textbox).bind('change keyup', function() {
      var options = $(select).empty().scrollTop(0).data('options');
      var search = $.trim($(this).val());
      var regex = new RegExp(search,'gi');

      $.each(options, function(i) {
        var option = options[i];
        if(option.text.match(regex) !== null) {
          $(select).append(
             $('<option>').text(option.text).val(option.value)
          );
        }
      });
      if (selectSingleMatch === true && 
          $(select).children().length === 1) {
        $(select).children().get(0).selected = true;
      }
    });
  });
};

Parameters:

  • textbox
    This could be a jQuery selector, a jQuery object, or a DOM object.
  • selectSingleMatch
    This is optional, if you set it to true, when the filtered list includes only one item, that item will be automatically selected.

For example:

$(function() {
  $('#select').filterByText($('#textbox'), true);
});  

Live example (or in a new window):

You can play around with it on jsbin: http://jsbin.com/egogeh/edit

What it does:

When you invoke the function on a select object, it finds all child option tags and saves their text and values into an array. This array is saved to the select object itself as a HTML5 custom data attribute, called data-options. Then, when a change or keyup event fires on the associated textbox, the select list is emptied, and for any entries in the array that match the search text a new option element is created.

Edit 2012-10-15: Added ScrollTop(0) to improve the way it works with long lists, thanks to a comment by xarel below.

Posted in Technology | Tagged | 55 Responses

Using Open XML SDK to get Custom Properties from a Word document

I stumbled across a library that I didn’t realize was out there, for working with Microsoft Office documents. It only works with the newer Office 2007 and 2010 files (and 2003 with a compatibility pack), i.e. those using the Open XML standard.

Download and install the Open XML SDK 2.0 for Microsoft Office: http://www.microsoft.com/download/en/details.aspx?displaylang=en&id=5124.

I got the second, smaller file:

Open XML SDK 2.0 for Microsoft Office

Add a reference to DocumentFormat.OpenXml and WindowsBase to your project:

You can now programmatically access Office documents, without the need to have Microsoft Office installed or any Interop DLLs. This works with Word, Excel and PowerPoint (using the OpenXML WordprocessingML, SpreadsheetML and PresentationML).

For example, to get the custom properties of a Word document:

public static Dictionary<string, string> GetCustomPropertiesOfWordDocument
                                                  (string filename)
{
    using (var package = WordprocessingDocument.Open(filename, false))
    {
        var properties = new Dictionary<string, string>();
        foreach (var property in package.CustomFilePropertiesPart
            .Properties.Elements<CustomDocumentProperty>())
        {
            properties.Add(property.Name, property.VTLPWSTR.Text);
        }
        return properties;
    }
}

In this example, you would need to add some error handling around line 9 (property.VTLPWSTR.Text) as your property may be a different type or null.

When deploying your solution, you need to include DocumentFormat.OpenXml.dll with your application. You can set Copy Local to True in the properties for the reference, and it will be copied to your output folder when you compile the project:

Download a sample project here.

Posted in Technology | Tagged , , | Leave a comment

How to hide the dotted border outline on focused elements in HTML, using CSS

While working on a web application for data entry, I had to scour the net for a way to hide the dotted border that appears when an element is focused on a web page. Here are my findings.

First, the obligatory disclaimer – I do understand that the dotted border is for accessibility purposes and should be left in place under normal circumstances. However, in this case we already had a replacement in place – when an element receives focus it is styled differently, using a very distinct background color. And this applies to all elements, regardless of whether they were selected by mouse or keyboard. So the dotted border is redundant, and somewhat distracting.

To further clarify the question, these are the dotted borders I refer to:
save-outline and cancel-outline

While the solution needed to be usable across browsers, the target browsers where well defined – modern versions of Firefox and Chrome, and IE 7 or newer. I first came across this question on stackoverflow.com which pointed me to using outline:none. Then this one helped with Firefox compatibility. And then I saw this post which provides a number of different techniques.

I ended up using the following CSS, which seems to cover most bases. As I didn’t see this combination on other sites I thought I would post it myself. It doesn’t apply to the select element in Firefox and IE7. Testing was done on Windows XP.

/* hide the dotted lines around an element when it receives focus */
* { _noFocusLine: expression(this.hideFocus=true); } /* ie7 */
::-moz-focus-inner {border:0;}	                     /* firefox */
:focus {outline:none;}                               /* ie8, chrome, etc */
Posted in Technology | Tagged , , , | 4 Responses