Archive for the ‘Uncategorized’ Category

Drupal Camp NJ 2013

Wednesday, February 6th, 2013

Thanks to everyone who came out to my talk at Drupal Camp NJ, “Drupal Coding Patterns.” Got a lot of really nice feedback, and met a lot of really great people in the community. Slides and code have been posted on the official Drupal Camp NJ website: http://www.drupalcampnj.org/content/drupal-coding-patterns

Posted in Uncategorized | No Comments »

Before Type Cast

Saturday, November 13th, 2010

While working on Kludge, I ran into a bit of a gotcha that I thought I’d share with everyone.

In our invoicing system, we have a Invoice model that has many LineItems. These line items, have a quantity attribute, and a quantity_type. This way, your line item can say “10 hours”, or “5 products”. When storing a quantity of hours, we wanted to actually store minutes (like 150), and then do some work on the reader when accessing that value (like 1.5) only when the quantity_type was :hour.

The Code

We thought it would be best to run a simple before_validation that checks whether or not the quantity being saved was to be saved in hours, and if so, convert it to minutes. Something like this:

1
2
3
4
5
6
class LineItemTest < ActiveSupport::TestCase
  def test_quantities_change_based_on_quantity_type_when_read
    @li = LineItem.create(:quantity => 0.5, :quantity_type => :hour)
    assert_equal(30, @li.read_attribute(:quantity))
  end
end

Our before validation looks like this:

1
2
3
4
5
6
7
8
9
10
11
class LineItem < ActiveRecord::Base

  before_validation :convert_quantity


private
  def convert_quantity
    logger.warn("-----#{quantity}")
    self.quantity = (quantity_type.to_sym == :hour) ? (quantity * 60).to_i : quantity
  end
end

This code was failing, and looking at our logs showed something strange:

1
2
-----0
  SQL (0.4ms)  INSERT INTO "line_items" ("created_at", "description", "invoice_id", "price_in_cents", "quantity", "quantity_type", "updated_at") VALUES ('2010-11-13 19:04:25.813989', NULL, NULL, NULL, 0, 'hour', '2010-11-13 19:04:25.813989')

Note the “—–0″: that zero is the value we are getting for quantity, before we even run any code. So what’s wrong?

Typecasting and *_before_type_cast

As it turns out, ActiveRecord will typecast your data before you get to it, and since our quantity column is an integer, the value of 0.5 was cast into 0. To correct this error, you can use the dynamic method *_before_type_cast to get the value …. well …. before type casting.

Updating the validation to:

1
2
3
4
private
  def convert_quantity
    self.quantity = (quantity_type.to_sym == :hour) ? (quantity_before_type_cast * 60).to_i : quantity
  end

… gave us our passing results. Hope this helps!

Tags:
Posted in Uncategorized | No Comments »

Concerning Yourself with ActiveSupport::Concern

Monday, September 20th, 2010

Picking up on our last talk about working with the Rails core, I wanted to take some time to introduce you to the internals of Rails 3, in hopes to break down any fears about hacking around in Rails. We are going to talk today about ActiveSupport::Concern.

Preface

For those of you new to ActiveSupport, let’s take a step back. Have you ever worked on a codebase and had to constantly do some utility work, like encoding or decoding JSON, generate a random number, or encrypt data? Of course, we all have, and the Rails core developers are no different. ActiveSupport is a library of such utilities that you are free to use not only in Rails, but in your own standalone Ruby project! I feel that ActiveSupport is the best place to start learning Rails core code: in core libraries, it takes multiple classes and modules to see a functionality come to life. Compounded by your unfamiliarity with the idioms that the core developers use, you may quickly find yourself getting lost. In ActiveSupport, most of the modules standalone, so you can look at the one file to find out what it’s doing (many helper modules are < 200 lines of code with comments). Also, it gives you small doses of such idioms, so you can get comfortable with core design patterns before diving into heavy lifting code.

::Concern

So now that you know about ActiveSupport, you won’t be surprised to learn that ActiveSupport::Concern is just another helpful utility module. But you might not understand what it’s useful for until you learn a little bit about a common Rails metaprogramming design pattern.

Mixing Class and Instance methods into your classes

Commonly in Rails, we use 3rd-party gems to add certain functionality to our classes; most commonly of which is ActiveRecord::Base. These gems usually add methods to instances of AR::Base, and to the class itself. For example, a tagging library might add an instance method @blog.tags, and a class method Blog.find_by_tags. If you’ve never looked under the hood to see how libraries do this, it may be look a little roundabout:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
module TagLib
 
  module ClassMethods
    def find_by_tags()
      # ...
    end
  end
 
  module InstanceMethods
    def tags()
      # ...
    end
  end
 
  def self.included(base)
    base.send :include, InstanceMethods
    base.send :extend, ClassMethods
  end
 
end

class ActiveRecord::Base
  include TagLib
end

This is a common Rails idiom that many developers are used to seeing. The system breaks down like this:

  1. Start on line 1, where we create a module, ours is TagLib, which will provide tagging functionality
  2. On line 23, we open up ActiveRecord::Base (AR::Base) and include our module. This will make the TagLib library available to all AR::Base classes. Note: this code that opens AR::Base is not inside of our module
  3. On line 15, we override the
    1
    self.included()

    method.

    1
    self.included()

    is a special “callback” method that gets automatically called when ever the module is included into something. In our case, we included TagLib into AR::Base, so this method will be called. self.included() takes a parameter, which is a reference to the class that included in it, in our case AR::Base. We can now take that reference, and use it to add methods to it. Note: we use

    1
    base.send :extend

    , instead of the basic

    1
    extend

    , to get around private method hiding.

  4. By calling self.included() in your class, it will include all of the instance methods of the class with the methods in the InstanceMethods module, giving your @blog.tags, and it will add all of the methods in the ClassMethods module to the class, so you can do Blog.find_by_tags.

There are many reasons why this system is a little bit hacky, and more will become apparent when you dive deepy into the Ruby language and metaprogramming. A couple standouts are:

  • You are overriding the
    1
    self.included()

    method to act like an extend method

  • When you include a method into a class, the methods automatically become apart of all instances in the class. It is not always necessary to have an InstanceMethods module to include another module.
  • It’s not readable, people have to struggle just to figure out this whole bootstrapping process.

Note: Smarter people have explained this way better than me

ActiveSupport::Concern to the rescue

Looking for a way to keep the same design pattern, but abstract the complexities out of the code, Josh Peek wrote ActiveSupport::Concern, which allows you to pull off our same TagLib module by doing something like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
module TagLib
  extend ActiveSupport::Concern

  module ClassMethods
    def find_by_tags()
      # ...
    end
  end
 
  module InstanceMethods
    def tags()
      # ...
    end
  end
end

class ActiveRecord::Base
  include TagLib
end

AS::Concern will look for modules named ClassMethods and InstanceMethods and bootstrap them as you normally would like. The module has some other nice benefits, for instance, sometimes you want to add other code in the

1
self.included()

method, such as logging:

1
2
3
def self.included(base)
  logger.warn("Adding TabLib - this will make you class awesome. Proceed with awesomeness")
  #...

Since AS::Concern removes the need for that call, it also provides you with an

1
included()

method that takes a block, so now you can do:

1
2
3
included do
  logger.warn ...
end

Hopefully, you’ve gotten a taste of some Rails idioms, Rails core code, and an explanation of a core module. I assure you, there are many more in ActiveSupport that are equally as straightforward to follow, so get hacking! (check out GZip, Buffered Logger, and Message Encryptor)

Posted in Uncategorized | 11 Comments »

Why does my autospec keep looping?

Sunday, January 17th, 2010

After following all of the most up-to-date tutorials I could find, making sure I installed all of the latest gem releases, and just trying to be diligent overall, I couldn’t figure out why my autospec kept looping. In particular, it loops when there are Cucumber features being run ( by setting AUTOFEATURE=true before running autospec ). If you search around on Google, you will find a whole mess of articles with other people having the same issue, and all solutions seemed to come from this one article: http://www.ruby-forum.com/topic/183578 . After reading that, life was glourious for all, David Chelimsky to the rescue! From his life-saving post…

If you use Autotest with Ruby on Rails, be sure to gem install autotest-rails when you upgrade to ZenTest-4.1.0.

Without that gem, when you run the autospec command that ships with RSpec, Autotest won’t won’t have any way of knowing it’s in a Rails app and it will load up rspec’s autotest/rspec.rb instead of rspec-rails‘ autotest/rails_rspec.rb.

Absolutely brilliant! I run to my console, upgrade my gems … and it still loops! Determined not to give up, I did what any smart person would do, ask someone else.

After about a half-hour of frustration of wheel-spinning, Steve Walker and I were finally able to bang out a solution that just may work for you.

About half way down the github wiki for Cucumber, you will see a section titled “Other ways of running features” in which they advise you to put this in your cucumber.yml file

autotest-all: --require features --require lib --format progress features
autotest: --require features --require lib features
default: --format pretty
html: --format html --out features.html

This is a little out of date, most likely written before RSpec moved to autospec, and all hell breaks loose presumably because we are still configuring it to point to autotest.

In conclusion, drop in this …

autospec-all: --require features --require lib --format progress features
autospec: --require features --require lib features
default: --format pretty
html: --format html --out features.html

…and let me know if it fixes it.

Happy red/green/re-factor-ing!

Posted in Uncategorized | 1 Comment »

Ruby on Rails May Become Really Popular Soon.

Saturday, December 5th, 2009

I found this and I just thought it was too adorable not to repost: http://37signals.com/svn/archives/000606.php

Tags: ,
Posted in Uncategorized | No Comments »

I’m a big deal on ITNewb

Saturday, May 16th, 2009

The good folk over at ITNewb have honored me with their first round of featured authors in their new “Author Spotlight” area. It’s been really great working with the ITNewb community, so if you’re in the information technology field and haven’t checked out that site yet, you really should get on that.

Posted in Uncategorized | No Comments »

ITNewb Hookup

Friday, April 24th, 2009

Andrew Johnson, owner and lead developer for ITNewb, a social network of volunteer tech authors, gave me an awesome shout out on the company’s blog. I’ve been a huge supporter of ITNewb since Andrew introduced me to the project. I’ve had the opportunity to collaborate with Andrew on a number of interface strategies and mock-ups to help increase the sites usability and he’s been doing an incredible job.

ITNewb offers a genuine platform for members of the Information Technology field to go beyond simply reading tutorials reviewed by a handful of private editors. Articles are submitted, reviewed and critiqued by members of the network before being submitted to the archives. Critiques are carefully broken down with specific categories and a sophisticated rating system. The site also offers a variety of useful tools for all ITers, such as an Open Source software library and an RFC database. Make sure you check out ITNewb, wish Andrew all the best, and friend me, of couse.

Tags:
Posted in Uncategorized | 2 Comments »