Episode 14: Performing Calculations on Models

Posted about 7 years back at Railscasts

Did you know ActiveRecord provides class methods for performing calculations on models? You can even use these methods through associations.

Go get scope_out - it should be in core!

Posted about 7 years back at The Hobo Blog

The scope_out plugin is such a great extension to ActiveRecord I can’t imagine any non-trivial app not benefiting from it.

I have just two reservations: I would have thought it could be named better (OK that’s a niggle), and the customised with_scope methods it creates (e.g. with_active), should really be protected. Why? See this thread.

Go get scope_out - it should be in core!

Posted about 7 years back at The Hobo Blog

The scope_out plugin is such a great extension to ActiveRecord I can’t imagine any non-trivial app not benefiting from it.

I have just two reservations: I would have thought it could be named better (OK that’s a niggle), and the customised with_scope methods it creates (e.g. with_active), should really be protected. Why? See this thread.

I'm in a Magazine!

Posted about 7 years back at Cody Fauser

2 Magazine March 2007 Cover

Back in January my wife Maria and I were lucky enough to go on an all expenses paid vacation to Club Med Cancún Yucután. What was the catch? Well, the entire trip was a makeover for a magazine in Toronto called 2 Magazine.

The trip was a blast and we were fortunate enough to be photographed for the magazine by the incredible Toronto based photographer James Pattyn. The entire week was also documented on video by Mark and Evan from Viral Media Group

Special thanks to the entire 2Magazine crew including Diane, Beth, Margo, Jamie, Keri, Mark, and Evan. It was an awesome experience that we will never forget.

2 Magazine Cancun 2007 Makeover Video

Episode 13: Dangers of Model in Session

Posted about 7 years back at Railscasts

Be careful when storing a model in a session. It will behave differently than you expect and can easily get out of sync with the database. Instead of storing the model directly in the session, store the id to the model and use that to fetch it from the database.

Relaunched, Realigned

Posted about 7 years back at Sporkmonger

If you can see this, apparently everything is working.

Update:

Ok, so there were some bugs. Incorrect permissions and such, not-quite-right Apache settings. But it’s likely to be more functional now.

After several weeks of work on the site, I’ve finally gotten everything moved off Typo, redesigned, and generally just looking a thousand times better than before. I also hosed out all of the accumulated spam. It wasn’t easy.

At Aristotle’s request, I made sure to modify the Typo conversion script (as well as Mephisto itself) to allow the feed entry GUIDs to remain the same. I wasn’t particularly pleased to discover that Mephisto doesn’t actually store its entry GUIDs in the database—it generates them each time the feed is requested, which in my humble opinion is a terrible idea, since the information it uses to generate the IDs might change. The change I made added a “guid” column to the database and uses UUIDTools to generate unique ids instead.

I also deleted a bunch of entries that I no longer felt were relevant to the site. I know a lot of people in the pro-standards crowd don’t like it when people do this, but I did anyways. I also tried to set up redirects for all of the old resources to the equivalent URIs in Mephisto, but I’m sure I missed a couple. If you bump into a 404 that you think is a mistake on my part, I’ll try to get it fixed as quickly as possible.

In addition to the switch to Mephisto, obviously I also took the time to redesign the site. I figured I should construct the design entirely from scratch this time instead of simply altering the default Typo theme. I gotta say, I really, really, really like the new look. I haven’t bothered testing and seeing how it looks in Internet Explorer. I really just don’t care that much about IE anymore. But I didn’t do anything particularly tricky with the design either, so it’ll probably look mostly OK. If you’re reading this in IE, stop, go install some other browser (preferably Firefox), and then come back. Web developers everywhere will thank you for it. And you’ll feel better about yourself. I promise.

I released a new library the other day called Squish. Admittedly, in its current state, it’s really effectively useless. I’ve never been particularly good at optimizing for performance, and while I did manage to improve the speed of the library (with the help of people in #ruby-lang) by at least an order of magnitude, it’s still way too slow to be useful. In retrospect, I’m not really sure why I even tried to write it in Ruby—I really should have known that a compression-based text classifier would need to be written in C. But hey, at least I know the basic idea works now.

Oh, and you may also notice that the site is faster and less error-prone now. You can thank Slicehost for that. I can’t recommend them highly enough if you’re in the market for a Rails-friendly VPS host.

Rake: Ant Be Gone!

Posted about 7 years back at zerosum dirt(nap) - Home

I spent the better part of my morning today writing some code to do sample data generation within the framework we’re building. I’d originally packaged it as a standalone utility class to be run with the script/runner facility until I realized that it was a perfect candidate for a custom Rake task. And a perfect topic for a blog entry — two for the win!

If you’ve never written a Rake task before and are a Ruby pseudo-noob, fear not. If you’ve written Ant or Make scripts before, and have the requisite passing familiarity with Ruby, it’ll be old hat. Of course, the big win with Rake is that you get to write your tasks in Ruby. Sweet, sweet Ruby. No crufty XML here.

What follows is pretty minimalist, but I wanted to record it for posterity. Also, many of the tutorials I looked at didn’t deal with handling parameters, so I figured it might be useful to someone else out there…

namespace :foo do
  desc "Generate sample data for the app"
  task :sample_data => [:environment] do |t|
    require 'db/script/sample_data.rb'

    num_users = ENV.include?('NUM_USERS') ? ENV['NUM_USERS'] : 5
    SampleData.generate(num_users.to_i)
  end
end

What we’re doing here is defining a task named sample_data within the foo namespace. We declare a dependency on the Rails :environment, which is a little gift from the Rails team allowing you to write code in your tasks that lives within your app’s pre-existing environment. The desc line serves as a comment about what the task does, and will appear alongside the task name when you query it with the —tasks parameter.

Within the body of the task we simply require the script we’re going to run, in this case my virtually unmodified utility class, and then we check to see if a parameter named NUM_USERS was passed in. If it was, we use that value to determine the number of users to create. If it wasn’t, we default to 5.

Because Rails is smart, and talented in the mystical arts, it auto-loads any files in lib/tasks that have a .rake extension. So just plop this file in that directory and you can then check the available Rake tasks from the top level of your project. You should see our new task definition there:

$ rake --tasks | grep sample
rake foo:sample_data              # Generate sample data for the app

Rockin. So let’s run it. As you can see from the output below, it calls the utility calss, creating 10 sample users (and a bunch of other stuff I’ve excluded). Couldn’t be easier.

rake foo:sample_data NUM_USERS=10
SampleData: generating 10 users, blah blah blah...

I hope this has been helpful, and if you’re looking for more information, make sure to check out Martin Fowler’s seemingly definitive reference.

New Railsbench Release (0.9.2)

Posted about 7 years back at RailsExpress.blog

A new version of railsbench has been released. Benchmarking POST requests is now supported, benchmark specific session data can be specified in the benchmark config file and ERB can be used as well.

  • added POST support:
        search:
          uri: /search
          method: post
          post_data: category=dessert
    
    • method defaults to get
    • post_data will be url encoded by railsbench
  •  
  • allow specification of session_data in benchmarks.yml:
        benchmark_name:
          uri: /
          session_data:
             user_id: 1
          post_data: category=dessert
    
  •  
  • load benchmarks.yml using ERB. Example: retrieve login ids using Rails)
        admin_interface:
          uri: /admin
          session_data:
            user_id: <%= User.find_by_name('admin').id %>
    
  •  
  • use benchmark names instead of urls in raw data files, old files can be converted using script convert_raw_data_files. change was required by post support
  •  
  • copy environments/production.rb to environments/benchmarking.rb, instead of providing a fixed one
  •  
  • don’t create a broken benchmarks.yml file when running railsbench install
  •  
  • perf_plot and perf_plot_gc accept -geometry parameter, for exact dimensioning of the produced .png file
  •  
  • use -font_size=12 for setting font size when generating graphs
  •  
  • use ‘perf_plot -colors=color1,color2,...’ to get a different color set
  •  
  • use ‘perf_plot -out=name’ to write graph to file ‘name’
  •  
  • new script perf_table: create a tabular overview of perf data
  •  
  • added -colorize option to perf_html, which results in green and red backgrounds in the factor columns
  •  
  • added -theme option to perf_plot

Happy benchmarking!

Rails 1.2 Performance

Posted about 7 years back at RailsExpress.blog

Rails 1.2-stable is somewhat slower than Rails 1.1-stable, especially on action cached pages. But the slowdown I measured is nowhere near the numbers which have been reported by others. In fact, two recent patches to speed up session creation and pstore session retrieval, have resulted in improved performance for one of the benchmarked actions.

The following performance data table shows the speed difference for the fastest availabe configuration for the tested application.

<style type="text/css"> </style>
page c1 totalc2 total c1 r/sc2 r/s c1 ms/rc2 ms/r c1/c2
empty 11.4403410.91962 437.0457.9 2.292.18 1.05
welcome 13.0464814.29709 383.2349.7 2.612.86 0.91
recipes 10.8361713.51635 461.4369.9 2.172.70 0.80
my_recipes 10.8013713.48035 462.9370.9 2.162.70 0.80
show 24.1672227.37878 206.9182.6 4.835.48 0.88
cat 26.5603829.88683 188.3167.3 5.315.98 0.89
cat_page5 27.2495430.78081 183.5162.4 5.456.16 0.89
letter 26.9906730.17507 185.2165.7 5.406.04 0.89
all requests 151.09216170.43488 264.7234.7 3.784.26 0.89
GC statistics c1 totalc2 total c1 #gcc2 #gc c1 gc%c2 #gc% c1/c2
10.4279012.90426 120.0135.0 6.907.57 0.81

c1: 1.1-stable, c2: 1.2-stable, r/s: requests per second, ms/r: milliseconds per request

Read the full report here.

Episode 12: Refactoring User Name Part 3

Posted about 7 years back at Railscasts

In the final part of this series you will see how to refactor your tests. Keeping tests clean is important because it will make testing easier to do in the future.

Michael Buffington and Stikkit - Ruby on Rails Podcast

Posted about 7 years back at Ruby on Rails Podcast

The serial entrepreneur
talks about his latest startup.
Also mentioned:

New Contact Feedback Plugin

Posted about 7 years back at Mephisto - Home

James Crisp wrote a nifty Contact Feedback plugin for Mephisto for the new Thoughtworks Studios site. The plugin looks nice, and fills a common need in Mephisto. Also, the Thoughtworks Studios site is extremely well-done. I had seen it before, but didn’t realize it used Mephisto. Major kudos to James Crisp and Thoughtworks!

For anyone that asks: it looks like the main difference between this, and my own feedback plugin is that mine doesn’t send emails. It stores them in the DB and lets you browse in the admin. Nice since your inbox doesn’t get the spam, but I’ve been finding that I often forget to check it :)

Customising controllers - new API

Posted about 7 years back at The Hobo Blog

One of the nice things about Hobo is that you never have to write the seven boilerplate actions to get a basic CRUD controller (index, show, new, create, edit, update and destroy). The downside is that if you need to tweak the behaviour of one of those actions, there’s no code in your controller to tweak.

I’ve been addressing that issue by adding hook points, e.g. you can define create_response and invalid_create_response in order to override Hobo’s default responses. I’ve never been totally happy with that approach though - the number of such hooks is bound to grow until there’s a rather complex little API in there, which we certainly don’t want.

Today I’m having a go at a different approach. The index action in Hobo’s model controller is now as follows:

def index
  hobo_index
end

The hobo_index method (which is protected), can also be passed a bunch of parameters, so you could override index in your controller like this:

def index
  hobo_index :page_size => 10
end

Through parameters like that, you can customise pretty much everything. A common requirement is to include some eager loading in the ActiveRecord find:

def index
  hobo_index :items => Post.find(:all, :include => :comments)
end

Another trick - if you pass the items as a proc, the find will happen in a scope that handles pagination for you. (UPDATE: After some digging I’ve come across the idea, which I thoroughly agree with, that this is really an abuse of with_scope)

Baaad idea

def index
  hobo_index :items => proc { Post.find(:all, :include => :comments) }
end

So here’s the new way to achieve the same (and I renamed the :items parameter)

Good idea

def index
  hobo_index :collection => paginated_find(:include => :comments)
end

I think this approach is going to be easier to learn, while giving you a fine-grained choice between having Hobo do things for you, and having custom control.

Customising controllers - new API

Posted about 7 years back at The Hobo Blog

One of the nice things about Hobo is that you never have to write the seven boilerplate actions to get a basic CRUD controller (index, show, new, create, edit, update and destroy). The downside is that if you need to tweak the behaviour of one of those actions, there’s no code in your controller to tweak.

I’ve been addressing that issue by adding hook points, e.g. you can define create_response and invalid_create_response in order to override Hobo’s default responses. I’ve never been totally happy with that approach though - the number of such hooks is bound to grow until there’s a rather complex little API in there, which we certainly don’t want.

Today I’m having a go at a different approach. The index action in Hobo’s model controller is now as follows:

def index
  hobo_index
end

The hobo_index method (which is protected), can also be passed a bunch of parameters, so you could override index in your controller like this:

def index
  hobo_index :page_size => 10
end

Through parameters like that, you can customise pretty much everything. A common requirement is to include some eager loading in the ActiveRecord find:

def index
  hobo_index :items => Post.find(:all, :include => :comments)
end

Another trick - if you pass the items as a proc, the find will happen in a scope that handles pagination for you. (UPDATE: After some digging I’ve come across the idea, which I thoroughly agree with, that this is really an abuse of with_scope)

Baaad idea

def index
  hobo_index :items => proc { Post.find(:all, :include => :comments) }
end

So here’s the new way to achieve the same (and I renamed the :items parameter)

Good idea

def index
  hobo_index :collection => paginated_find(:include => :comments)
end

I think this approach is going to be easier to learn, while giving you a fine-grained choice between having Hobo do things for you, and having custom control.

General Genetic Algorithms for Ruby (gga4r) release 0.9

Posted about 7 years back at Spejman On Rails

General Genetic Algorithms for Ruby (gga4r) is a library for executing generic algorithms easily.

Only 3 steps are needed in order to work with gga4r:

  1. Choose a clase to evolve and define for her the fitness, combine and mutate methods.

  2. With an array of last defined class instances (initial population), create a GeneticAlgorithm object.

  3. Call GeneticAlgorithm's evolve method as many times as you want.


More info: