Category Archives: Web Dev

rails generate Could not find <gem> in any of the sources

So with my latest project I am using Rails 4.1 – this is all well and good, but here is a gotcha. there is a thing called spring that is supposed to make things faster – except when it gets in the way!

tl;dr – killall spring

So – here are the symptoms

$ rails g
Could not find bcrypt-3.1.7 in any of the sources
Run `bundle install` to install missing gems.

Now bcrypt is the only thing having the issue (other gems worked) i think this is because it has a compiled binary component to it.

The fix? Kill all the springs!

$ ps aux | grep spring
jason     8361  0.0  0.2 426464 21380 ?        Sl   Apr22   0:01 spring server | wholesale | started 22 hours ago                                                                
jason    11730  1.0  0.2 225632 22276 ?        Ssl  11:46   0:00 spring app    | wholesale | started 55 secs ago | development mode

$ kill 8361

… and now rails generate plays nicely again!

Rails, CanCan and Best In Place editing

So here is a little gotcha and solution when using CanCan and Best In Place. With the default setup, if CanCan auth fails on a best in place edit you get a redirect to your default “Auth Failed” path and that page then tries to render as javascript.

that does not work all that well!

So here is my simple solution, if we get an auth denied on a XHR request, just return a generic error!

class ApplicationController < ActionController::Base
	protect_from_forgery
	check_authorization

	rescue_from CanCan::AccessDenied do |exception|
		if request.xhr?
			render :json => ['You are not authorised to do that.'], :status => :unprocessable_entity
		else
			redirect_to '/', :alert => exception.message
		end
	end
...
end

Adventures with Google Content API and OAuth

So recently I have had the opportunity to play with Google’s Content API and their OAuth API.

I have needed to use it in “offline” mode, as I want to interact with Google when the authorising user is not present (cron jobs and such).

Here are my lessons learnt.

  • You can Indeed use OAuth on a website that wants to use it in the background. You just need to persistently store the tokens (especially the refresh token!)
  • The refresh token ONLY appears when the user is asked for permission. it does *not* appear when access is auto approved. This means when you generate the authorise url – you need to specify the “approval=force” option!
  • Their testing facilities are not that good, trying to sort out a sandbox site is like pulling teeth. Their account signup pages were busted 🙁
  • Their API is pretty good!

Google Content API Class

Below is a simple class stub to interact with Google. The PersistentKeyValueStore class is fairly self explanitory and you can implement your own (I persist my data in a simple table with the columns “key” and “value” with “key” being a primary key).

When implementing this class you will need

  • A user to initially interact with a web page
  • Your code to call the Google_Content_Client->doAuthorise() function so the user can interact with the OAuth page.
  • <?php
    client = new GSC_Client($options->merchantId);
    		$this->options = $options;
    
    		$this->authToken = new GSC_OAuth2Token(
    			$this->options->clientId,
    			$this->options->clientSecret,
    			$this->options->userAgent
    		);
    
    		$token = PersistentKeyValueStore::get(self::TOKEN_KEY);
    		if (!$token) {
    			return false;
    		}
    		$this->authToken->fromBlob($token);
    
    		$this->client->setToken($this->authToken);
    	}
    
    	/**
    	 * handles the user interaction for the authorising
    	 */
    	public function doAuthorise($revoke, $force = false) {
    
    		if ($revoke) {
    			// do we have a refresh token to revoke?
    
    			$bits = explode('|',PersistentKeyValueStore::get(self::TOKEN_KEY));
    			if ($bits[4]) {
    				$this->authToken->revoke();
    			}
    			PersistentKeyValueStore::set(self::TOKEN_KEY,'');
    		} else {
    			$code = @$_GET['code'];
    
    			$approvalPrompt = $force ? 'force' : 'auto';
    			$authorizeUrl = $this->authToken->generateAuthorizeUrl($this->options->redirectUri, $approvalPrompt);
    			if ('' == $code) {
    				header("Location: $authorizeUrl");
    				die;
    			} else {
    				$this->authToken->getAccessToken($_GET['code']);
    				$this->client->setToken($this->authToken);
    				PersistentKeyValueStore::set(self::TOKEN_KEY,$this->authToken->toBlob());
    			}
    		}
    
    	}
    
    	/** your functions to wrap Google's **/
    }

PHP: for vs foreach

So this week I was asked the question on which was quicker in PHP – A for loop or a foreach loop. It turns out that my assertion that they were both about the same performance was about right. Here are my test results

jason@server:~/php$ php speedtest.php
Starting test: Test for loop data length=4000000
     Mem: 795.63MiB Used
Peak Mem: 795.63MiB Used
[xxxxxxxxx ]
Results for test Test for loop data length=4000000
Min   : 0.6085901260376
Max   : 0.61222791671753
Mean  : 0.6110053062439
StdDev: 0.00015155474344889

     Mem: 795.63MiB Used
Peak Mem: 795.64MiB Used
Starting test: Test foreach loop data length=4000000
     Mem: 795.63MiB Used
Peak Mem: 795.64MiB Used
[xxxxxxxxx ]
Results for test Test foreach loop data length=4000000
Min   : 0.41838312149048
Max   : 0.42730903625488
Mean  : 0.42159442901611
StdDev: 0.0010704358418783

     Mem: 795.63MiB Used
Peak Mem: 795.64MiB Used
On average test 2 is faster than test 1 by 1.4493x

And the code I used to run the test is:

<?php

$data_length = 4000000;//rand(10000000,20000000);
for ($i=0; $i<$data_length; $i++) {
        $data[] = $i;
}


$avg1 = run_test("Test for loop data length={$data_length}", "test_for",&$data);
$avg2 = run_test("Test foreach loop data length={$data_length}", "test_foreach",&$data);

print "On average ";
if ($avg1 < $avg2) {
        print "test 1 is faster than test 2 by ";
        printf("%0.4fx\n", $avg2 / $avg1);
} else {
        print "test 2 is faster than test 1 by ";
        printf("%0.4fx\n", $avg1 / $avg2);
}


function test_for(&$data) {
        $max = count(&$data);
        for($i=0; $i<$max; $i++) {$x=&$data[$i];}
}

function test_foreach(&$data) {
        foreach ($data as &$x) {}
}


function run_test($name, $func, &$data) {
        print "Starting test: $name\n";
        printf("     Mem: %3.2fMiB Used\n", memory_get_usage()/1024/1024);
        printf("Peak Mem: %3.2fMiB Used\n", memory_get_peak_usage()/1024/1024);
        $num_runs = 10;

        for($i=0; $i<$num_runs; $i++) {
                print "[" . str_repeat('x',$i) . str_repeat(' ',$num_runs-$i) . "]\r";
                $run_times[] = time_run($func,&$data);
        }

        print "\nResults for test {$name}\n";
        $min = null;
        $max = null;
        $mean = null;
        foreach ($run_times as $run_time) {
                $mean += $run_time;
                $max = (is_null($max) || $run_time > $max) ? $run_time : $max;
                $min = (is_null($min) || $run_time < $min) ? $run_time : $min;
        }
        $mean /= $num_runs;

        // now work out the std deviation aka confidence
        $std_dev_count = 0;
        foreach ($run_times as $run_time) {
                $dev = $run_time - $mean;
                $std_dev_count = $dev * $dev;
        }
        $std_dev = sqrt( $std_dev_count / ($num_runs-1));

        print "Min   : {$min}\n";
        print "Max   : {$max}\n";
        print "Mean  : {$mean}\n";
        print "StdDev: {$std_dev}\n\n";

        printf("     Mem: %3.2fMiB Used\n", memory_get_usage()/1024/1024);
        printf("Peak Mem: %3.2fMiB Used\n", memory_get_peak_usage()/1024/1024);

        return $mean;
}

function time_run($func,&$data) {
        $start = microtime(1);
        $func(&$data);
        $end = microtime(1);
        return $end - $start;
}

WordPress – Stop screwing with the timezone!

So my dates were not displaying correctly and it turns out that WordPress is to blame.

After checking the data and finding that it was correct, I was confused as to why a wordpress page was displaying the wrong date for a correct unix timestamp.

WordPress was screwing with the timezone setting of PHP. This little factoid took a good 30 minutes for my decaffeinated brain to figure out.

So, here is a small function that will help out displaying a date with the correct info:

/**
* Echo's a date with the timezone setting unfuxed
* 
* @param mixed $format
* @param mixed $timestamp
*/
function echo_date($format,$timestamp) {
	$old_tz = date_default_timezone_get();
	date_default_timezone_set(get_option('timezone_string'));
	echo date($format,$timestamp);
	
	date_default_timezone_set($old_tz);
}

HTML5 input type=”number” and step granularity

or how I learnt the hard way about the how the step attribute works.

Being an old (VB4,5,6) windows developer, I mistook the “step” attribute on the <input type=”number”…/> HTML 5 element for what it used to be. It not only controls what the step is if you press the spin control but also defines what numbers are ALLOWED in the field.

For example, with the default step of “1” you are only allowed to enter integers (that is whole numbers). With a step of 2 you are only allowed to enter even integers. With a step of 0.1, you are allowed to enter numbers with a single decimal place, 0.5 means only half integers and integers (…-0.5,0,0.5, 1.0, 1.5…).

So if you find yourself getting errors from your browser when trying to enter 41.2 into a number field, try setting step to either “0.1” or “any”.

More reading over at HTML: The Markup Language on the W3C website.

wpsc_update_custom_meta() nukes my custom post meta data

So today I was rather perplexed as to why my custom meta box on my post edit page was not playing ball. It would be set to a value and always stay at it, delete it from the database and give it a different value – and it would keep that too.St

Since I had used the update_post_meta() function before and it had never behaved this way, I looked through the mysql.log file on my server and saw this

4162 Query SELECT meta_id FROM wp_postmeta WHERE meta_key = 'my-plugin-key' AND post_id = 128
4162 Query UPDATE `wp_postmeta` SET `meta_value` = '0' WHERE `post_id` = 128 AND `meta_key` = 'my-plugin-key'
4162 Query SELECT meta_id FROM wp_postmeta WHERE meta_key = 'my-plugin-key' AND post_id = 128
4162 Query UPDATE `wp_postmeta` SET `meta_value` = '1' WHERE `post_id` = 128 AND `meta_key` = 'my-plugin-key'

What the? my value is set and then set back to what it was!? Time to find out where this was happening. Since I use Nusphere’s PhpEd to develop all my PHP projects, I fired up the trusty debugger and followed the code. Now take a guess where my setting is being undone!

Now I realise that I am playing in WP E-Commerce’s own playgound and that I need to play by their rules – but overwriting my changes – that’s just not cool!

The Fix

Go Last. Well, have wordpress call your save function after wp e-commerce. It’s rather simple actually – but a gotcha that cost me a couple of hours!

add_action( 'save_post', 'MyPluginHandleMetaBoxSaveData', 99);

WordPress, WP E-Commerce and the lack of ASYNC AJAX

Now Normally the A in AJAX means Asynchronous, meaning you can have several requests going at once, so it was very confused as to why my AJAX wasn’t. My WordPress plugin is a long running import process and I decided to use AJAX so that I can provide timely feedback to the user as to how far the import had gotten.

But these status updates were not working. I would get the entire output at the end of the process.

Then it dawned on me. WP E-Commerce is a pig and assumes that you want a session started all the time (even if you do not need it – which is rather bad for varnish caching), and PHP sessions are blocking, so that only one call with the same session id is handled at a time. AJAX sends cookies, and therefore WP E-Commerce starts the same session for all session requests.

So remember, if you are writing a long running plugin with lots of AJAX requests and you are not getting async output, check to see if there is a session cookie being sent!

The way I solved this problem is to use this code at the top and bottom of your plugin!

if ($_COOKIE['PHPSESSID']) {
	session_write_close();
}

if ($_COOKIE['PHPSESSID']) {
	session_start();
}