Painfully Hellish Plaintext and WordPress

No Comments »

I'm working on a Wordpress site for a general contractor friend of mine and we wanted to make something really easy for him to use to show before/after pictures. Now after a bout of hacking on Wordpress - be it plugins, theme changes, or just reading the API documents - I typically have to delude myself into believing that Wordpress was written in some sensible language, like Perl, so I can sleep that night. Tonight the healing process will have to begin a bit later than usual.

I settled on a Before/After plugin but not one of the jQuery slider-type plugins. The jQuery-based ones use a slider to show two pictures that pretty much have to be taken from the same angle/same scene/etc. to get a really good effect. Our needs were for a before/after in a room to display tile work or anything else that might come up. This plugin got me about 90% of the way. Its one of those plugins where it has pretty good admin integration - not the greatest, except when you post its dead simple (drag two images from your media gallery into a Before/After columns) - but fails on executing the full deal. The author suggests you edit your theme's template files to add some PHP to see if the current post has a before/after gallery associated with it and then make the call for the appropriate image. You'd likely have to do this in your single post and index templates. This just felt dirty to me.

The plugin is contained a single file beforeafter.php which makes our job all the easier.

Around line 30, prior to the declaration of $beforeafter we add an action:

#./wp-content/plugins/beforeafter/beforeafter.php
⋮
add_action('the_content', 'before_after_content_action', 5, 1);
⋮

So what's that 5 and 1 in there for? Glad you asked. So the five is somewhat sensible, its the priority in which your action will be executed when considered against the other actions registered for the "the_content" action. The 1? Well that is the number of arguments your function accepts. Uh, come again? Yeah. Exactly. You'll note that we cannot just pass arguments to this function, Wordpress will take care of that for us. And how do we know what arguments we're going to get? I wasn't able to find a definitive list and a lot of answers out there suggest just reading the Wordpress source code, so I guessed, and I guessed right.

After the $beforeafter I added our action:

#./wp-content/plugins/beforeafter/beforeafter.php
⋮
function before_after_content_action($content) {
        global $beforeafter;
        global $post;

        if (!($beforeafter->is_gallery($post->ID)))
                return $content;

?>
<table class="center" width="100%">
        <tr>
                <td class="center">
                        <?php $beforeafter->gallery('before', $post->ID, 'thumb', true, false, 'shadowbox'); ?>
                        <br />Before
                </td>
                <td>
                        <?php $beforeafter->gallery('after', $post->ID, 'thumb', true, false, 'shadowbox'); ?>
                        <br />After
                </td>
        </tr>
</table>
<?php
        return $content;
}
⋮

Those global declarations cause me to dry heave.

So it turns out that your action method should accept one parameter $content and return that value almost like a filter. The good news is that in an action method you can just, you know, throw up all over inside your editor with <?php ?> interspersed with code and that stuff will be output during execution as you would expect.

(That final argument, the 'shadowbox', lets you integrate the Wordpress 'shadowbox' incredibly easily. I was impressed.)

If I can manage it I'll try to put a better admin UI on this stuff and get the plugin out on Github and register it with Wordpress so the manual editing nonsense isn't necessary. I know there has to be at least another person out there who wants easy before/after functionality in their blog.

And the good news: I learned a lot about using vim during this process.


haml and haml-rails

No Comments »

Yes its 2011 and Rails 3 has been out for a year but as far as I can tell, and many git reset --hard HEAD attempts later, haml requires the gem haml-rails to generate views. Even though Google may show results from 2010 they are still relevant. But haml --rails isn't what you want.

So Haml configuration in my Rails 3.0.9 project looks like (only relevant parts shown)...

#Gemfile
⋮
gem 'haml'
group :development do
  gem 'haml-rails'
  ⋮
end
#./config/application.rb
⋮
module IlkContent
  class Application < Rails::Application
  ⋮
  config.generators do |g|
    g.template_engine :haml
    ⋮
  end
end
⋮

Surprise! “MySQL server has gone away” during a Rake task

No Comments »

Suppose you're generating some sample data for your project as part of your `db:populate` rake task and part of that generation involves creating one hundred or so user records with varying bits of generated data. Then you want to associate each of these user records with other users so you execute an innocent `User.all` - its okay, this is a rake task we're only going to run in development.

Except you start getting error messages like `You have a nil object when you didn't expect it!` on `User.all.each do |user|`. Hopping into `rails c` and running `User.all` gives you a dump of the user table. Placing a `pp "User count #{User.count}"` right before the `User.all` returns 100, and looking in the logs you're even seeing the `SELECT` statement executing.

So what gives?

After a bit of debugging I was able to discern a hidden error message in all of this: "MySQL server has gone away." Oh, how kind of it to simply go away. There a number of reasons for this and in this particular case I am going to guess - and yes this is most definitely a guess - that its the packet too large problem. (And the more I think about this, the more I think that it cannot be this problem because the entire table size is 64KB. But I'm going to go with this for now.)

My brew installed MySQL server isn't running with a set `max_allowed_packet` value, so it defaults to 1MB. I'm theorizing that the returned data exceeded 1MB so the connection was dropped. This can be configured around by running `mysql max_allowed_packet=16M` or setting it in an option file but I don't like that approach. I went for chunking the result set up into smaller pieces - which is okay, this is a rake utility task after all - and it ended up looking like this:

#./lib/tasks/populate.rake
# before
User.all.each do |user|
  ⋮
end
#./lib/tasks/populate.rake
# after
users = []
10.times { |n| users.concat User.where("id % 10 = #{n}") }
users.each do |user|
  ⋮
end

The above after code works for this project; YMMV so smaller chunks may be necessary.

If someone has a better grasp on what's really going on here, please do enlighten me.


RSpec-ing a rake task

No Comments »

I have a couple rake tasks and I want to write specs for them. Yes, I should extract the programming logic from the rake tasks and encapsulate that logic into appropriate class methods. However this doesn't mean that I shouldn't be able to RSpec rake tasks.

I found an older post that got me 90% of the way to what I needed. The problem is that I suspect some sort of static file name caching is going on behind the scenes in rake so using `#rake_require` in an RSpec context isn't performing the functionality I was expecting. I tried moving between `before :all do` and `before` blocks, nesting `describe` blocks and all sorts of other craziness. I had 3 different specs and the first spec would always pass and the other two would fail; I could freely re-arrange the spec order and always the spec defined first would pass. This was maddening.

Turns out I just had to use `load` instead of `#rake_require`.

Here's what my now working spec ended up looking like, for the curious:

#./spec/lib/tasks/rake_tasks_spec.rb
require 'spec_helper'
require 'rake'

describe "rake" do
  before do
    @rake = Rake::Application.new
    Rake.application = @rake
    # previously was trying
    # Rake.application.rake_require "tasks/get_comic"
    load Rails.root + 'lib/tasks/get_comic.rake'
    Rake::Task.define_task(:environment)
  end

  describe "task get_comic" do
    it "should have 'environment' as a prerequisite" do
      @rake['get_comic'].prerequisites.should include("environment")
    end
    it "works when expected input is received" do
      comic = Comic.new {|c| c.comic_id = 12}
      comic.should_receive(:save).and_return(true)

      result = Ilk::Parser::Result.new { |r| r.comic_id = 12 }
      result.should_receive(:to_model).and_return(comic)

      Ilk::Parser.should_receive(:parse).with(Ilk::Constants::COMIC_URL + '12').and_return(result)
      Comic.should_receive(:find_by_comic_id).with(12).and_return(nil)

      @rake['get_comic'].invoke('12')
    end
    it "raises an error when there was a problem parsing" do
      Ilk::Parser.should_receive(:parse).with(Ilk::Constants::COMIC_URL + '12').and_return(nil)
      -> { @rake['get_comic'].invoke('12') }.should raise_error
    end
  end
end

GrowlApplicationBridgePathway error message

No Comments »

If you're wondering why your growlnotify isn't working and you see this error message:

#console
... could not find local GrowlApplicationBridgePathway, falling back to NSDNC

Its because Growl isn't running. (System Preferences > Growl, check "Start Growl at login".

Whoops.