Dennis' Blog http://denniskuczynski.posterous.com Most recent posts at Dennis' Blog posterous.com Fri, 11 May 2012 06:56:00 -0700 How to share common attributes and validations between Rails ActiveRecord models http://denniskuczynski.posterous.com/how-to-share-common-attributes-and-validation http://denniskuczynski.posterous.com/how-to-share-common-attributes-and-validation

I had a domain model that included a staging object and a real object that had lots of duplicate attributes.  But I wanted to leave them in different tables, and not put them in a shared table.

Here's a detailed posting about how this type of thing is usually implemented in Ruby (polymorphism, abstract classes, acts_as idiom, etc.) on thoughtbot's blog:

http://robots.thoughtbot.com/post/159808315/a-compromise

Below is some example Ruby code of what I ended up using:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# Sharing common attributes and validations in Rails ActiveRecord to stay DRY
module CommonData
  
  def self.included(clazz)
    clazz.class_eval do
      validates :duplicate_field, presence: true, length: { maximum: 255 }

      attr_accessible :duplicate_field
    end
  end
end

class StagingRecord < ActiveRecord::Base
  include CommonData
end

class RealRecord < ActiveRecord::Base
  include CommonData
end

Note, that if I was doing this in a gem, I'd probably use the acts_as idiom, instead of the include.

But the include seems simpler if its isolated to a small domain.

Permalink | Leave a comment  »

]]>
http://files.posterous.com/user_profile_pics/1758519/footer_image.jpg http://posterous.com/users/egP0wV08A70Lw Dennis Kuczynski denniskuczynski Dennis Kuczynski
Wed, 09 May 2012 08:15:00 -0700 Be careful updating Rails' ActiveRecord Model attributes in-place http://denniskuczynski.posterous.com/be-careful-updating-rails-activerecord-model http://denniskuczynski.posterous.com/be-careful-updating-rails-activerecord-model

I just spent a couple minutes debugging a simple method that was updating a string in my database.

The column in the database was initialized to empty string.  I had a method which would pull that record from the database, reinitialize the value to empty string, and then append to it using the << operator.  However, after calling save!, the record was not updated.  This had me grumbling, "Why isn't ActiveRecord updating my attribute!"

It was due to my misunderstanding of how the ActiveRecord Dirty flag works in cases of in place attribute updating.

Below is an example that shows how this works and the use of the <attribute_name>_will_change! method:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
it "tries to update a Model's string attribute in place" do
  person = Person.new
  person.name = ""
  person.save!
  person.reload
      
  person.name = ""
  person.name << "TEST"
  person.save!
  person.reload
  person.name.should eq("")
      
  person.name = ""
  person.name_will_change!
  person.name << "TEST"
  person.save!
  person.reload
  person.name.should eq("TEST")
end

For more info, checkout:

Permalink | Leave a comment  »

]]>
http://files.posterous.com/user_profile_pics/1758519/footer_image.jpg http://posterous.com/users/egP0wV08A70Lw Dennis Kuczynski denniskuczynski Dennis Kuczynski
Sat, 05 May 2012 12:21:00 -0700 Check out my post on beanstalkd_view on the 9mmedia blog http://denniskuczynski.posterous.com/check-out-my-post-on-beanstalkdview-on-the-9m http://denniskuczynski.posterous.com/check-out-my-post-on-beanstalkdview-on-the-9m

Simple Ruby Monitoring and Management Interface For beanstalkd, beanstalkd_view

Permalink | Leave a comment  »

]]>
http://files.posterous.com/user_profile_pics/1758519/footer_image.jpg http://posterous.com/users/egP0wV08A70Lw Dennis Kuczynski denniskuczynski Dennis Kuczynski
Tue, 03 Apr 2012 13:03:00 -0700 A Basic Helper to Test Your Backbone JS Route Matching http://denniskuczynski.posterous.com/a-basic-helper-to-test-your-backbone-js-route http://denniskuczynski.posterous.com/a-basic-helper-to-test-your-backbone-js-route

Below is some source code for a basic helper method that can be used to test that your Backbone JS routes are correctly matching url fragments to your intended handlers.

This will just test the route regular expression matching, so something more rigorous would be required for full integration tests.


If you have a Router with the following routes:

1
2
3
4
5
6
class Example.Routers.TestRouter extends Backbone.Router

  routes:
    "index" : "index"
    "example/:example_num" : "example"
    ".*" : "index"

You can add the following to your Jasmine spec_helper.coffee file:

1
2
3
4
5
6
7
8
9
10
11
12
window.RouteHelpers = {
  getRouteHandlerMethod: (router, url_fragment) ->
    routeStripper = /^[#\/]/;
    url_fragment = url_fragment.replace(routeStripper, '')
    routes = Object.keys(router.routes)
    return _.find routes, (route) =>
      regexp = router._routeToRegExp(route)
      if (regexp.test(url_fragment))
        return true
      else
        return false
}

Which can then be used like:

1
2
3
4
5
6
7
8
9
10
11
12
13
describe 'Example.Routers.TestRouter:', ->
  beforeEach ->
    @router = new Example.Routers.TestRouter()

  it "check index route", ->
    url_fragment = '#'
    method = RouteHelpers.getRouteHandlerMethod(@router, url_fragment)
    expect(@router.routes[method]).toEqual('index')
    
  it "check example/1 route", ->
    url_fragment = '#example/1'
    method = RouteHelpers.getRouteHandlerMethod(@router, url_fragment)
    expect(@router.routes[method]).toEqual('example')

Permalink | Leave a comment  »

]]>
http://files.posterous.com/user_profile_pics/1758519/footer_image.jpg http://posterous.com/users/egP0wV08A70Lw Dennis Kuczynski denniskuczynski Dennis Kuczynski
Wed, 14 Mar 2012 16:00:00 -0700 Testing Stalker (Beanstalkd) Jobs with RSpec in Rails http://denniskuczynski.posterous.com/testing-stalker-beanstalkd-jobs-with-rspec-in http://denniskuczynski.posterous.com/testing-stalker-beanstalkd-jobs-with-rspec-in

Stalker https://github.com/han/stalker is a nice gem for running Beanstalkd background jobs in Rails.

But it took me a bit of Google-ing to figure out how to write tests for those jobs.  Here's what I learned:

Below is an example of a "basic_job" that puts "second_job" on the queue when run:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# lib/jobs/stalker_example.rb with Full Rails Environment -- This should be stripped down to the bare essentials needed to run...
require File.expand_path("../../../config/environment", __FILE__)

module Stalker
  
  PROCESSING_DELAY = 5
  
  job "basic_job" do |args|
    log "Running (basic_job), Args: #{args.inspect}"
    Stalker.enqueue("second_job", { :id => args["id"] }, { :delay => PROCESSING_DELAY })
    log "Enqueued (second-job) with delay of #{PROCESSING_DELAY} seconds"
  end

  job "second_job" do |args|
    log "Running (second_job), Args: #{args.inspect}"
    log "Test Finished"
  end

  error do |exception|
    log "Exception running job #{exception.inspect}"
  end
end

And here's the corresponding RSpec test

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
require "spec_helper"

describe Stalker, "/jobs/stalker_example.rb" do
  
  before :all do
    # Make sure beanstalkd is running
    if `pgrep beanstalkd` == ""
      raise "PRECONDITION NOT MET: beanstalkd not running"
    end
    
    # Turn off all log output
    module Stalker
      def log(msg); end
      def log_error(msg); end
    end
  end

  before :each do
    @entered_error_handler = false
    # Clears all job, before, and error handlers
    Stalker.clear!
    # Load all jobs in our jobs file
    require File.dirname(__FILE__) + "/../../../lib/jobs/stalker_example"
  end

  it "enqueue and work (basic_job) ensuring that (second_job) is placed on the queue" do
    #Redefine the error handler
    Stalker.error { |e| @entered_error_handler = true }

    id = "test"
    Stalker.enqueue('basic_job', {:id => id})
    Stalker.prep
    Stalker.work_one_job
    @entered_error_handler.should eq(false)

    # Work (second_job)
    Stalker.work_one_job
    @entered_error_handler.should eq(false)
    # Check that (second_job) did what it was supposed to (TODO: example doesn't do anything)
  end
end

Note that the Stalker jobs file was wrapped with "module Stalker".  This is necesseary so that when we load the jobs file in our RSpec test the job method is called in the correct Object space.

Note that you'll need to install pgrep on OS X for the precondition check to run.  You can do that with Homebrew, see Best Unix Shell Tools

 

Check out the Stalker source code to see all available methods of Stalker at your disposal:  https://github.com/han/stalker/blob/master/lib/stalker.rb

For example:

  • prep:  Ensures all handlers and beanstalk-client are setup correctly
  • work_one_job:  Works a single job in the queue

 

References:

 

Permalink | Leave a comment  »

]]>
http://files.posterous.com/user_profile_pics/1758519/footer_image.jpg http://posterous.com/users/egP0wV08A70Lw Dennis Kuczynski denniskuczynski Dennis Kuczynski
Sat, 10 Mar 2012 11:27:53 -0800 A trip to the New York Botanical Gardens http://denniskuczynski.posterous.com/a-trip-to-the-new-york-botanical-gardens http://denniskuczynski.posterous.com/a-trip-to-the-new-york-botanical-gardens

Permalink | Leave a comment  »

]]>
http://files.posterous.com/user_profile_pics/1758519/footer_image.jpg http://posterous.com/users/egP0wV08A70Lw Dennis Kuczynski denniskuczynski Dennis Kuczynski
Mon, 05 Mar 2012 07:18:00 -0800 Setting Up Evergreen in a Rails 3.2 application to unit test your coffeescript Backbone.js models http://denniskuczynski.posterous.com/setting-up-evergreen-in-a-rails-32-applicatio http://denniskuczynski.posterous.com/setting-up-evergreen-in-a-rails-32-applicatio

Evergreen (https://github.com/jnicklas) is a nice wrapper for the Jasmine javascript testing framework, and it's very easy to use in a Rails app to test Backbone.js models.  (Note: I'm using https://github.com/codebrew/backbone-rails as well.)

Simply require the gem in your Gemfile's development/test environments:

1
2
3
4
5
6
7
8
9
10
group :development, :test do
  gem 'rspec-rails'
  gem 'capybara'
  gem 'capybara-webkit'
  
  ...
  
  # Javascript Testing Engine
  gem 'evergreen', :require => 'evergreen/rails'
end

And add an Evergreen configuration file: evergreen.rb in your config directory:

1
2
3
4
5
6
7
8
require 'capybara-webkit'

Evergreen.configure do |config|
  config.driver = :webkit
  config.public_dir = 'public'
  config.spec_dir = 'spec/javascripts'
  config.template_dir = 'spec/javascripts/templates'
end

Then create a folder in your project: /spec/javascripts

You can add a spec_helper.coffee file here that will automatically loaded, in which you can require the necessary javascript files from the asset path, e.g.:

1
2
3
4
5
6
7
8
9
10
11
require "/assets/jquery.js"
require "/assets/jquery_ujs.js"
require "/assets/underscore.js"
require "/assets/backbone.js"
require "/assets/backbone_rails_sync.js"
require "/assets/backbone_datalink.js"
require "/assets/backbone/project-name.js"
require "/assets/backbone/models/test_model.js"
require "/assets/test_model.js"

window.CoffeeSpecHelper = { coffee: 'script' }

Then write your model tests:

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

describe 'ProjectName.Models.TestModel:', ->
  describe 'ProjectName.Models.TestModelTest:', ->
    beforeEach ->
      @model = new ProjectName.Models.TestModel({test_string: "Hello World"})
      
    it "should load spec helper file", ->
      expect(CoffeeSpecHelper.coffee).toEqual('script')

    it 'Example Model Test', ->
      test_string = @model.get("test_string")
      expect(test_string).toEqual("Hello World")

Then just start your rails app, and browse to http://localhost:3000/evergreen to see the results of your tests, or run rake spec:javascripts

Permalink | Leave a comment  »

]]>
http://files.posterous.com/user_profile_pics/1758519/footer_image.jpg http://posterous.com/users/egP0wV08A70Lw Dennis Kuczynski denniskuczynski Dennis Kuczynski
Fri, 24 Feb 2012 06:06:13 -0800 Meatball Shop Veggie Balls http://denniskuczynski.posterous.com/meatball-shop-veggie-balls http://denniskuczynski.posterous.com/meatball-shop-veggie-balls

Lentil and veggie balls

Permalink | Leave a comment  »

]]>
http://files.posterous.com/user_profile_pics/1758519/footer_image.jpg http://posterous.com/users/egP0wV08A70Lw Dennis Kuczynski denniskuczynski Dennis Kuczynski
Tue, 14 Feb 2012 12:40:00 -0800 Generating a Trample configuration file from a Rails server log http://denniskuczynski.posterous.com/generating-a-trample-configuration-file-from http://denniskuczynski.posterous.com/generating-a-trample-configuration-file-from

Below is a Rake Task to parse a Rails server log using Timber to generate a Trample configuration file for load testing.

Just download Timber from https://github.com/cainlevy/timber and copy it into your rails app's: /vender/plugins/cainlevy-timber

Then copy this task into: /lib/tasks

Then run with: rake trample:generate LOG=log/development.log"

(Don't forget to convert any filtered parameters like passwords from [FILTERED] to the actual value.)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37

namespace :trample do
  desc 'Generate Trample config file from Rails log file'
  task :generate do
    input = ENV['LOG']
    if input.empty?
      puts "ERROR: No log specified!"
      puts "Run like: rake trample:generate LOG=log/development.log"
      exit
    end
    
    require File.dirname(__FILE__) + '/../../vendor/plugins/cainlevy-timber/lib/timber'
    
    # add to Request
    Timber::Request.class_eval {include Timber::Plugins::Rails30}
    
    puts "Trample.configure do"
    puts " concurrency 1"
    puts " iterations 1"
    puts " login do"
    puts " end"
    logfile = Timber::Log.new(input)
    while request = logfile.shift
      method = request.http_method
      url = request.url
      request_string = " #{method.downcase} \"#{url}\""
      has_params = request.instance_variables.find_index(:@params).present?
      if has_params and method != "GET"
        parameters = request.params
        parameters = parameters.inject({}){|memo,(k,v)| memo[k.to_sym] = v; memo} #Convert string keys to symbols
        request_string << " do\n #{parameters.inspect} \n end"
      end
      puts request_string
    end
    puts "end"
  end
end

Permalink | Leave a comment  »

]]>
http://files.posterous.com/user_profile_pics/1758519/footer_image.jpg http://posterous.com/users/egP0wV08A70Lw Dennis Kuczynski denniskuczynski Dennis Kuczynski
Thu, 09 Feb 2012 17:48:00 -0800 Heather Bought Me a "Chopped" Mystery Basket Cooking Class http://denniskuczynski.posterous.com/heather-bought-me-a-chopped-mystery-basket-co http://denniskuczynski.posterous.com/heather-bought-me-a-chopped-mystery-basket-co

Alle Cuisine!

From the Brooklyn Kitchen

Permalink | Leave a comment  »

]]>
http://files.posterous.com/user_profile_pics/1758519/footer_image.jpg http://posterous.com/users/egP0wV08A70Lw Dennis Kuczynski denniskuczynski Dennis Kuczynski
Thu, 09 Feb 2012 11:20:00 -0800 Generating httperf wsesslog data from a Rails server log http://denniskuczynski.posterous.com/generating-httperf-wsesslog-data-from-a-rails http://denniskuczynski.posterous.com/generating-httperf-wsesslog-data-from-a-rails

Below is a Rake Task to parse a Rails server log using Timber to generate httperf wsesslog formatted data for load testing.

Just download Timber from https://github.com/cainlevy/timber and copy it into your rails app's: /vender/plugins/cainlevy-timber

Then copy this task into: /lib/tasks

Then run with: rake wsesslog:generate LOG=log/development.log"

(Don't forget to convert any filtered parameters like passwords from [FILTERED] to the actual value.)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
namespace :wsesslog do
  desc 'Generate httperf wsesslog file from Rails log file'
  task :generate do
    input = ENV['LOG']
    if input.empty?
      puts "ERROR: No log specified!"
      puts "Run like: rake wsesslog:generate LOG=log/development.log"
      exit
    end
    
    require File.dirname(__FILE__) + '/../../vendor/plugins/cainlevy-timber/lib/timber'
    
    # add to Request
    Timber::Request.class_eval {include Timber::Plugins::Rails30}
    
    logfile = Timber::Log.new(input)
    while request = logfile.shift
      method = request.http_method
      url = request.url
      wsesslog_string = "#{url} method=#{method}"
      has_params = request.instance_variables.find_index(:@params).present?
      if has_params
        parameters = request.params
        wsesslog_string << " contents='#{parameters.to_query}'"
      end
      puts wsesslog_string
    end
  end
end

 

Permalink | Leave a comment  »

]]>
http://files.posterous.com/user_profile_pics/1758519/footer_image.jpg http://posterous.com/users/egP0wV08A70Lw Dennis Kuczynski denniskuczynski Dennis Kuczynski
Wed, 01 Feb 2012 09:35:00 -0800 Hmm, the iPad doesn't seem to handle overflow scrolling nicely... http://denniskuczynski.posterous.com/hmm-the-ipad-doesnt-seem-to-handle-overflow-s http://denniskuczynski.posterous.com/hmm-the-ipad-doesnt-seem-to-handle-overflow-s

Just tried to render a web page with overflow: scroll components for touch scrolling on an iPad.  Awful performance.  At least this seems to make it better:

http://mobile.tutsplus.com/tutorials/mobile-web-apps/ios-5-fixed-positioning-and-content-scrolling/

 

Here's a quick example, I wired up in Rails.

If you browse to the following links on an iPad, the scrolling performance is bad:

http://denniskuczynski.com/tests/mobile_tables/table_style

http://denniskuczynski.com/tests/mobile_tables/ul_style

However, once -webkit-overflow-scrolling : touch, is added to the scrolling container, performance is much better.

 

http://denniskuczynski.com/tests/mobile_tables/table_style?overflow=true

http://denniskuczynski.com/tests/mobile_tables/ul_style?overflow=true

See the source here:

https://gist.github.com/1888038 (Using tables)

https://gist.github.com/1888047 (Using unordered list items)

 

Note that, adding complicated HTML and CSS within these scrolling tables will start to degrade the scrolling performance, so the table HTML should be kept as simple as possible.

 

Permalink | Leave a comment  »

]]>
http://files.posterous.com/user_profile_pics/1758519/footer_image.jpg http://posterous.com/users/egP0wV08A70Lw Dennis Kuczynski denniskuczynski Dennis Kuczynski
Sat, 28 Jan 2012 14:12:59 -0800 Mark and Jamie put on a nice cheese spread http://denniskuczynski.posterous.com/mark-and-jamie-put-on-a-nice-cheese-spread http://denniskuczynski.posterous.com/mark-and-jamie-put-on-a-nice-cheese-spread

Permalink | Leave a comment  »

]]>
http://files.posterous.com/user_profile_pics/1758519/footer_image.jpg http://posterous.com/users/egP0wV08A70Lw Dennis Kuczynski denniskuczynski Dennis Kuczynski
Thu, 26 Jan 2012 19:30:34 -0800 Buffalo Chicken Meatballs (or Mark's balls) http://denniskuczynski.posterous.com/buffalo-chicken-meatballs-or-marks-balls http://denniskuczynski.posterous.com/buffalo-chicken-meatballs-or-marks-balls

Pre-making my appetizer for Mark's wine and cheese night!

Permalink | Leave a comment  »

]]>
http://files.posterous.com/user_profile_pics/1758519/footer_image.jpg http://posterous.com/users/egP0wV08A70Lw Dennis Kuczynski denniskuczynski Dennis Kuczynski
Thu, 12 Jan 2012 19:35:00 -0800 Cooking the Meatball Shop Cookbook, or Dennis' Balls http://denniskuczynski.posterous.com/cooking-the-meatball-shop-cookbook-or-dennis http://denniskuczynski.posterous.com/cooking-the-meatball-shop-cookbook-or-dennis

We've started meatball night.  Cooking our way through the book like Julie and Julia

To start: Classic Beef Meatballs with Classic Red Sauce

Permalink | Leave a comment  »

]]>
http://files.posterous.com/user_profile_pics/1758519/footer_image.jpg http://posterous.com/users/egP0wV08A70Lw Dennis Kuczynski denniskuczynski Dennis Kuczynski
Thu, 12 Jan 2012 08:03:00 -0800 Installing CakePHP 1.3 on OS X Snow Leopard http://denniskuczynski.posterous.com/installing-cakephp-13-on-os-x-snow-leopard http://denniskuczynski.posterous.com/installing-cakephp-13-on-os-x-snow-leopard

I recently had to get some CakePHP code running on my local OS X environment.

CakePHP requires

  • an HTTP Server --Snow Leopard includes Apache that can use mod_rewrite
  • PHP 4.3.2 or greater -- Snow Leopard includes PHP 5.3
  • a database -- It's easy to install MySQL on OS X

Here's a great blog post to get all this setup:

Install Apache/PHP/MySQL on Snow Leopard

 

Next you just need to install CakePHP so it is visible in Apache's Document Root.

I created a new project folder on my hard drive's root, /cake_project and extracted the CakePHP 1.3 files downloaded from the website there.

Then updated the Apache httpd.conf file to setup the appropriate mod_rewrite and Document Root settings.

sudo vi /etc/apache2/httpd.conf

Editing:

DocumentRoot "/cake_project/app/webroot"

and

<Directory "/cake_project/app/webroot">

...

    AllowOverride All

Now just restart apache:
sudo apachectl restart

Ensure that /cake_project and it's underlying files have the correct permissions set.  (Remember that apache runs as the www user.)

And setup your cake config to point to your MySQL database.  (You will have to create a new database and users.)

Also, not that CakePHP 1.3 requires you to modify your /app/config/core.php file since you are using PHP 5.3.  Just uncomment this line:

/**
 * If you are on PHP 5.3 uncomment this line and correct your server timezone
 * to fix the date & time related errors.
 */
       //date_default_timezone_set('UTC');

And your CakePHP application should be visible by browsing to http://localhost

Let me know if it works!

Permalink | Leave a comment  »

]]>
http://files.posterous.com/user_profile_pics/1758519/footer_image.jpg http://posterous.com/users/egP0wV08A70Lw Dennis Kuczynski denniskuczynski Dennis Kuczynski