The Data Asylum

Programming, Databases and People

Css Margin and Padding Shorthand

Css provides short hand properties for margin and padding which let you define multiple properties at once. For example:-

1
2
3
4
5
6
7
8
9
10
p {
  /* Shorthand */
  margin: 20px 5px 5px 10px;

  /* The Long Equivalent */
  margin-top: 20px;
  margin-right: 5px;
  margin-bottom: 5px;
  margin-left: 10px;
}

There are four variations of the shorthand property. You can specify 1, 2, 3 or 4 values, which are applied to the top, bottom, left and right margins. The problem that I had was trying to determine which value is applied to which side, especially if there are 2 or 3 values. There is an easy way to remember however.

Start at the top and go clockwise. If you run out of values, use the value already set for that axis.

So for example…

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
p {
  margin: 20px   5px      5px       10px;
  /*      top -> right -> bottom -> left    */

  margin: 20px   5px      5px;
  /*      top -> right -> bottom
                 left                       */

  margin: 20px   5px;
  /*      top -> right
          bottom left                       */

  /* the expection is for a single value. This applies to all sides. */
  margin: 20px;
  /*      all (top, right, bottom and left) */
}

How Rails, Nginx and X-Accel-Redirect Work Together

TL;DR - To use X-Accel-Redirect to serve static files from e.g /mnt/filestorage using send_file, put this in your nginx server configuration.

1
2
3
4
5
6
proxy_set_header  X-Accel-Mapping       /mnt/filestorage/=/private_files/;

location /private_files/ {
  internal;
  alias   /mnt/filestorage/;
}

The need for X-Accel-Redirect (and it’s sibling X-Sendfile) comes from two distinct requirements

  • The need to deliver large files.
  • The need for those files to not be available to the public.

Here we are going to see how to set up X-Accel-Redirect and Rails. This is a bit complex so I’m going to run through a specific example of downloading a file. Along the way we’ll see the configuration, code and HTTP headers that are used. This assumes you already have Rails and Nginx installed and working.

1. Browser makes a request for a file

1
2
# HTTP Headers
GET /download/SecretSquirrel.zip HTTP/1.1

2. Nginx receives this request. It adds on a header with configuration data that will be required by rails.

1
2
3
4
5
6
#Nginx configuration
proxy_set_header   X-Accel-Mapping       /mnt/filestorage/=/private_files/;

# Example HTTP Headers with additional header added by nginx
GET /download/SecretSquirrel.zip HTTP/1.1
X-Accel-Mapping: /mnt/filestorage/=/private_files/

3. Nginx passes the request onto Rails and it invokes the relevant controller.

4. The controller makes its authorization checks and calls send_file. Use the absolute path to the file.

1
2
# controller code (e.g. app/controllers/downloads_controller.rb)
send_file('/mnt/filestorage/SecretSquirrel.zip')

5. Rails (Rack to be precise) then decides what to with the file. We need to tell rails to use X-Accel-Redirect in its configuration as shown below. Instead of using the file as the body of the request, it will add a header to the response. It uses the X-Accel-Mapping that nginx added earlier to change the file path.

1
2
3
4
5
6
7
8
9
10
# Rails configuration (e.g. config/environments/production.rb)
config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect'

# HTTP Response
HTTP/1.1 200 OK
X-Accel-Redirect: /private_files/SecretSquirrel.zip
Content-Type: application/octet-stream
Content-length: ...
Content-Disposition: attachment; filename="SecretSquirrel.zip"
<empty body>

6. Nginx receives this header from rails and interprets it. It finds the location directive and reverses the changes to the path that rails made in step 5.

1
2
3
4
5
6
7
8
9
10
11
12
#Nginx configuration
    location /private_files/ {
    internal;
        alias   /mnt/filestorage/;
    }

# HTTP Response
HTTP/1.1 200 OK
Content-Type: application/octet-stream
Content-Length: ...
Content-Disposition: attachment; filename="SecretSquirrel.zip"
<contents of /mnt/filestorage/SecretSquirrel.zip>

7. Browser receives the file as if it was a normal download.

Also, if you have compiled passenger into nginx, remember to use passenger_set_cgi_param instead of proxy_set_header

Software Versions used

  • Rails 3.0.7
  • Passenger 3.0.5
  • Nginx 0.8.54
  • on Ubuntu 10.04.2 LTS

Resources

Adding Headers to Requests Using Nginx and Passenger

TL;DR If you have compiled Passenger into Nginx, use passenger_set_cgi_param instead of proxy_set_header to set HTTP headers required by the rails process.

There are two ways of using Passenger and Nginx together. The first is when the two are compiled into one daemon that creates many processes as required. The second is using Nginx as a proxy in front of Passenger/Apache/Nginx processes running either on the same machine or on a different server altogether.

When using Nginx as a proxy, it can be configured to add or redefine http headers in the request. This is done using the proxy_set_header directive.

1
proxy_set_header X-Forwarded-For 127.0.0.1;

If you have compiled Passenger into Nginx, the above configuration will have no effect. This is because the request is not considered to be proxied by Nginx. To have the same effect you need to use the passenger_set_cgi_param directive.

1
passenger_set_cgi_param HTTP_X_FORWARDED_FOR 127.0.0.1;

Notice that the header name is all upper case, and has HTTP_ prefixed.

Differences Between PHP Arrays and Ruby Hashes

We've looked at the differences between Ruby and PHP arrays before. Now lets compare PHP arrays and Ruby hashes. They should be similar as all PHP arrays are implemented as hashes. There is however a crucial difference that can trip you up if you are switching from one language to another.

Referencing an index that hasn't been set is an error in PHP, but not in Ruby.

In PHP, retrieving a value for an index that you haven't used is a warning. Although warnings can be turned off it is best practice to develop with them turned on.

1
2
3
4
5
6
7
8
9
10
11
<?php

$a['key1'] = 'value1';
$a['key2'] = 'value2';

print $a['key5'];
/*
lang@virtualbox1:~/$ php hash.php
PHP Notice: Undefined index: key5 in /home/lang/hash.php on line 6
*/
?>

In Ruby you can set a default value for all keys that have not set a value. By default this value is nil.

1
2
3
4
5
6
7
8
9
10
a = Hash.new

a['key1'] = 'value1'
a['key2'] = 'value2'

puts a['key5']
=begin
lang@virtualbox1:~/$ ruby hash.rb
nil
=end

Ruby hashes are unordered (up to version 1.8). PHP arrays have an internal order seperate from their index.

When you loop through a PHP array, the values will be returned in the order they were added.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?php

$a['key1'] = 'one';
$a['key0'] = 'zero';

foreach($a as $value) {
        print $value . "\n";
}
/*
lang@virtualbox1:~/$ php hash.php
one
zero
*/
?>

In Ruby 1.8 hashes are unordered, they could be retreived in any order that ruby decides is best. Ruby 1.9 changes this so that it works in the same way as the PHP example above.

1
2
3
4
5
6
7
8
9
10
11
12
13
a = Hash.new

a['key1'] = 'one'
a['key0'] = 'zero'

a.each_value do |value|
        puts value
end
=begin
lang@virtualbox1:~/$ ruby hash.rb
zero
one
=end

Is there anything that has been missed? Add a comment below.

Major Differences Between PHP and Ruby Arrays

PHP has a single array type, where as Ruby has Array and Hash, which covers the same functionality. In this article i'll go though the three major logical differences between PHPs array type and Rubys Array class. We compare PHP arrays and Ruby Hashes in separate post.

Firstly,

PHP arrays have an internal order separate from their index.

Lets look at a simple example. In php the order you insert values into an array determines the order that php will return them using foreach.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?php
$a[1] = 'one';
$a[0] = 'zero';

foreach($a as $value) {
        print $value . "\n";
}

/*
lang@virtualbox1:~/arrays$ php array.php
one
zero
*/
>?

Ruby on the other hand uses the key or index of the array to determine the order, regardless of order in which the values are inserted.

1
2
3
4
5
6
7
8
9
10
11
12
13
a = Array.new

a[1] = 'one'
a[0] = 'zero'

a.each do |value|
        puts value
end
=begin
lang@virtualbox1:~/arrays$ ruby array.rb
zero
one
=end

Secondly,

Ruby arrays always start at 0 and end at the highest index. PHP arrays only contain the keys that have been entered.

In the example below, PHP will output the two array values that are set.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?php
$a[2] = 'two';
$a[4] = 'four';

foreach($a as $value) {
        print $value . "\n";
}

/*
lang@virtualbox1:~/arrays$ php array.php
two
four
*/
?>

In the ruby example, not only are the two values output, but an attempt is made to get the value from every index between 0 and the highest index set.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
a = Array.new

a[2] = 'two'
a[4] = 'four'

a.each do |value|
        puts value
end
=begin
lang@virtualbox1:~/arrays$ ruby array.rb
nil
nil
two
nil
four
=end

This leads to another difference…

Referencing an array index that hasn't been set is an error in PHP, but not in Ruby.

The following code produces a PHP notice. Notices are a low severity error, and are usually turned off on production servers. However it is considered good practice to develop with notices turned on.

1
2
3
4
5
6
7
8
9
10
11
12
<?php

$a[2] = 'two';
$a[4] = 'four';

print $a[5];

/*
lang@virtualbox1:~/arrays$ php array.php
PHP Notice: Undefined offset: 5 in /home/lang/arrays/array.php on line 6
*/
?>

Ruby on the other hand does not consider this an error. It will return the nil value which is 'kind of' like PHPs null.

1
2
3
4
5
6
7
8
9
10
a = Array.new

a[2] = 'two'
a[4] = 'four'

puts a[5]
=begin
lang@virtualbox1:~/arrays$ ruby array3.rb
nil
=end

So what are your experiences switching between PHP and Ruby. Let me know in the comments below.

7 Habits of Highly Ineffective People

My Secret Santa decided to treat me to a copy of Stephen Covey’s The Seven Habits of Highly Effective People. Presumably because I’m ineffective in some way, which is completely true. Here then is my list of how to be a highly ineffective person.

  1. Social Networking. Check Twitter/Facebook every 5 minutes. Someone might upload a photo of you at any minute. You must know ASAP.
  2. MSN. Having personal conversations on MSN can sap anything from 10 minutes up to an hour or two from your day.
  3. Hangovers. Nothing keeps you alert like having a late night the night before. Especially if you are a "2 pint screamer" like myself.
  4. Wikiwalk. Do a Google search on how to open a file in ruby. An hour later your reading about the Boer War in South Africa. You have no idea how this happened.
  5. News feeds. Keeping up with the world and what is happening in your industry is important. Reading every article from the 200 feeds you are subscribed too isn’t.
  6. Coffee Time. Making a cup of tea/coffee is a great little stretch for you. To really be ineffective, make a cup for the rest of the office as well.
  7. Unread books. Buying books and not reading them is a surefire way to feel smart. I currently have The Passionate Programmer, Linchpin and the 7 habits book waiting to be read/finished.

Is there anything missing. Do you have a favourite time waster? Let everyone know with a comment.

The Best Feature of VIM Not in IDE’s

Insertion mode keyword completion

Ctrl-P and Ctrl-N in insert mode to search through the text to try and complete whatever variable name you are typing. I’ve never seen this in any other IDE and I really miss it. Code completion in IDE’s just isn’t the same.

Speak the Truth

Improper uses of Booleans causes headaches for people who are reviewing your code. Lets take a look at some good, and not so good uses.

Don’t be negative

1
if $notLoggedIn then

Looks simple and readable right? Wrong. It's one step away from being misused.

1
if ! $notLoggedin then

Not not logged in. Double negatives are a gotcha in language and coding and should be avoided. Fortunately the solution is an easy one. Remove the negative prefix (such as not, doNot, dont) from the variable name.

1
2
3
if $loggedIn then

if ! $loggedIn then

Hide Literals

1
if $hidden == false then

Is it really necessary to compare the variable to false? Imagine this conversation.

You are at Subway and they ask you
'Would you like your sandwich toasted?'
Would you reply with
'Toasted equals false'
    Or
'Not Toasted'

Avoid comparing with a literal true or false. The correct way to express this is :-

1
if ! $hidden then

A Boolean Flag?

1
if $reportFlag then

$reportFlag is a little vague. In this case it is determining if an object is included in a report. So if $reportFlag is true, does that mean that the object is included or excluded? If you have to ask yourself the question then you have already failed and need to rethink what this variable should be called.

1
if $report then

This is okay as long we are using the word ‘report’ as a verb. ‘If we report this then’ is how you would read this. Some people may not be able to make that leap so if you want to be more precise you could make it :-

1
if $includeInReport then

Summary

So to sum up, these three things will go a long way to making your code readable.

  • Remove the negative prefix (such as not, doNot, dont) from variable names.
  • Avoid comparing with a literal true or false.
  • Avoid vague terms like flag for Boolean values.

Consider these ideas when choosing

  • Variable names
  • Object properties
  • Database field names
  • Method or function parameter names

Anything Else?

Is there something i’ve missed? A hole you could drive a double-decker bus through? Leave a comment below.

Ctrl-A Delete

Usually a last resort. Often the best thing to do.