Railscasts are a Rails developers wet-dream.

Since Ryan created the site, it has been a fount of knowledge for anyone wishing to learn about the latest and greatest tips and tricks. To make things even better, they are free, though PeepCode is also very much worth a look for those of us wanting to glean a little (or a lot) of in-depth knowledge; $9 is a menial sum to pay for what amounts to a full-on lecture!

If you haven’t done already, go take a look – there is even a bunch of screencasts dedicated to Rails 2.0!

Given that the back button has been around for many years, and users have grown accustomed to it’s use, it’s a shame to see so many web applications neglecting this feature. As an example, I’ll pick on Lightbox, a tool that I like, yet one that is flawed in it’s disregard for the back button. For example:

  1. You navigate to a page that contains a thumbnailed image
  2. You click the image, and Lightbox shows it centered in your browser, full size
  3. You click back, press the back button on your mouse or whatever

Now, I realise that Lightbox has a close button in the image dialog box, but I’m not looking at the box, I’m looking at the image, and furthermore, my natural path back to the originating page is to press the back button, not to close the Lightbox. I therefore end up at the page I was on before I saw the thumbnail.

I’ve seen this with many users – the back button has been scarred into our mind, and to break it now is frivolous, and will ultimately lead to frustration, and lost users.

It’s with relief therefore, that I found Really Simple History, a JavaScript library for dealing with this exact problem – to create a JS history system that can run across many browsers, and provide developers with a little hope that our apps will no longer break the most fundamental user assumptions.

We tried to get the browser history working in Bouldr, and to an extent, we succeeded. The difference between coding something proprietary, and using an open source solution, though is very great indeed, so without doubt, we’ll be refactoring to use this library in the future.

From a business standpoint, Facebook’s killer feature is it’s Social Network, which gives even none-techies the ability to share nuggets of information found both on Facebook and the web at large with their friends.

What I didn’t realise until recently is that Facebook also allows businesses to set up pages inside the walled garden, that gives FB’s users the opportunity to show their support of your business by becoming ‘Fans’.

It doesn’t cost anything to set up a business page, which comes with a reporting tool that shows you just how many visits / page views / fans you’re getting per day, an update tool that allows you to send news items to your fans, and a bunch of advertising tools that you can use to promote your business page.

I set Bouldr up on the 21st November 2007 (check it out!), and already I have around 15 fans, with a slew of visitors coming from Facebook over to Bouldr’s main site. If you have a website that could benefit from a little social promotion, I’d suggest taking a look at Facebook’s business listing service – it’s free, so there is very little risk, really.

Symptoms

  • rake wouldn’t work
  • script/server wouldn’t run
# Logfile created on Wed Nov 21 13:39:25 +0000 2007 by /
DEPRECATION WARNING: observer is deprecated and will be removed from Rails 2.0  See http://www.rubyonrails.org/deprecation for details. (called from ./script/../config/../app/controllers/account_controller.rb:3)
DEPRECATION WARNING: depend_on is deprecated and will be removed from Rails 2.0  See http://www.rubyonrails.org/deprecation for details. (called from observer_without_deprecation at ./script/../config/../vendor/rails/actionpack/lib/action_controller/deprecated_dependencies.rb:29)
wrong number of arguments (1 for 0)
./script/../config/../vendor/rails/activerecord/lib/active_record/vendor/mysql.rb:566:in `initialize'
./script/../config/../vendor/rails/activerecord/lib/active_record/vendor/mysql.rb:566:in `new'
./script/../config/../vendor/rails/activerecord/lib/active_record/vendor/mysql.rb:566:in `scramble41'
./script/../config/../vendor/rails/activerecord/lib/active_record/vendor/mysql.rb:144:in `real_connect'
./script/../config/../vendor/rails/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb:389:in `connect'
./script/../config/../vendor/rails/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb:152:in `initialize'
./script/../config/../vendor/rails/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb:82:in `new'
./script/../config/../vendor/rails/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb:82:in `mysql_connection'
./script/../config/../vendor/rails/activerecord/lib/active_record/connection_adapters/abstact/connection_specification.rb:262:in `send'
./script/../config/../vendor/rails/activerecord/lib/active_record/connection_adapters/abstrct/connection_specification.rb:262:in `connection_without_query_cache='
./script/../config/../vendor/rails/activerecord/lib/active_record/query_cache.rb:54:in `connection='
./script/../config/../vendor/rails/activerecord/lib/active_record/connection_adapters/abstrat/connection_specification.rb:230:in `retrieve_connection'
./script/../config/../vendor/rails/activerecord/lib/active_record/connection_adapters/abstrac/connection_specification.rb:78:in `connection'
./script/../config/../vendor/rails/activerecord/lib/active_record/base.rb:760:in `columns'
./script/../config/../vendor/rails/activerecord/lib/active_record/base.rb:768:in `columns_hash'
./script/../config/../vendor/rails/actionpack/lib/action_controller/session/active_record_store.rb:105:in `setup_sessid_compatibility!'
./script/../config/../vendor/rails/actionpack/lib/action_controller/session/active_record_store.rb:79:in `find_by_session_id'
./script/../config/../vendor/rails/actionpack/lib/action_controller/session/active_record_store.rb:283:in `initialize'
./script/../config/../vendor/rails/activerecord/lib/active_record/base.rb:864:in `silence'
./script/../config/../vendor/rails/actionpack/lib/action_controller/session/active_record_store.rb:283:in `initialize'
c:/ruby/lib/ruby/1.8/cgi/session.rb:273:in `new'
c:/ruby/lib/ruby/1.8/cgi/session.rb:273:in `initialize'
./script/../config/../vendor/rails/actionpack/lib/action_controller/cgi_process.rb:122:in `new'
./script/../config/../vendor/rails/actionpack/lib/action_controller/cgi_process.rb:122:in `session'
./script/../config/../vendor/rails/actionpack/lib/action_controller/cgi_process.rb:154:in `stale_session_check!'
./script/../config/../vendor/rails/actionpack/lib/action_controller/cgi_process.rb:109:in `session'
./script/../config/../vendor/rails/actionpack/lib/action_controller/base.rb:1052:in `assign_shortcuts_without_flash'
./script/../config/../vendor/rails/actionpack/lib/action_controller/flash.rb:140:in `assign_shortcuts'
./script/../config/../vendor/rails/actionpack/lib/action_controller/base.rb:424:in `process_without_filters'
./script/../config/../vendor/rails/actionpack/lib/action_controller/filters.rb:624:in `process_without_session_management_support'
./script/../config/../vendor/rails/actionpack/lib/action_controller/session_management.rb:114:in `process'
./script/../config/../vendor/rails/actionpack/lib/action_controller/base.rb:330:in `process'
./script/../config/../vendor/rails/railties/lib/dispatcher.rb:41:in `dispatch'
./script/../config/../vendor/rails/railties/lib/webrick_server.rb:113:in `handle_dispatch'
./script/../config/../vendor/rails/railties/lib/webrick_server.rb:79:in `service'
c:/ruby/lib/ruby/1.8/webrick/httpserver.rb:104:in `service'
c:/ruby/lib/ruby/1.8/webrick/httpserver.rb:65:in `run'
c:/ruby/lib/ruby/1.8/webrick/server.rb:173:in `start_thread'
c:/ruby/lib/ruby/1.8/webrick/server.rb:162:in `start'
c:/ruby/lib/ruby/1.8/webrick/server.rb:162:in `start_thread'
c:/ruby/lib/ruby/1.8/webrick/server.rb:95:in `start'
c:/ruby/lib/ruby/1.8/webrick/server.rb:92:in `each'
c:/ruby/lib/ruby/1.8/webrick/server.rb:92:in `start'
c:/ruby/lib/ruby/1.8/webrick/server.rb:23:in `start'
c:/ruby/lib/ruby/1.8/webrick/server.rb:82:in `start'
./script/../config/../vendor/rails/railties/lib/webrick_server.rb:63:in `dispatch'
./script/../config/../vendor/rails/railties/lib/commands/servers/webrick.rb:59
c:/ruby/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:27:in `gem_original_require'
c:/ruby/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:27:in `require'
./script/../config/../vendor/rails/activesupport/lib/active_support/dependencies.rb:496:in `require'
./script/../config/../vendor/rails/activesupport/lib/active_support/dependencies.rb:343:in `new_constants_in'
./script/../config/../vendor/rails/activesupport/lib/active_support/dependencies.rb:496:in `require'
./script/../config/../vendor/rails/railties/lib/commands/server.rb:39
script/server:3:in `require'
script/server:3

Solution

Very simple – the machine that was running this app hadn’t got the mysql gem installed, therefore, simply running:

gem install mysql

sorted the problem out.

In protest at Total’s involvement in Burma, Mike Robertson solos the Eiffel Tower. (via)

Andrew Earl sends this Highball problem with perfect style – Amazing to watch!

Just Awesome.

Here’s a little snippet that I use to quickly form tests to ensure that my models validation is working correctly from within unit tests:

  # In test_helper.rb
  # Give this function an array of invalid values, an array of valid values, the object and
  # attribute name to test, and it will ensure that only valid values are allowed
  def validation_tester ( valid_values, invalid_values, attribute_name, test_object )
    valid_values.each do |val|
      test_object.[]=(attribute_name, val)
      assert test_object.save, "#{attribute_name} should be valid: #{test_object.[](attribute_name)}"
      assert test_object.valid?
      assert !test_object.errors.invalid?(attribute_name)
    end

    invalid_values.each do |val|
      test_object.[]=(attribute_name, val)
      assert !test_object.save, "#{attribute_name} should NOT be valid: #{val}"
      assert !test_object.valid?
      assert test_object.errors.invalid?(attribute_name)
    end
  end

Then, use it as follows in your unit tests:

  def test_email_validation
    valid_emails = ['matt@test.com', 'matt.hall@test.com', 'matt@test.ing.com', 'matt.hall@test.ing.com']
    invalid_emails = ['@test.com', 'test.com', 'matt@', 'matt.hall@com', '.matt@test.ing.co.uk', 'matt@@test.com', '', '.@.']

    u = create_user
    validation_tester( valid_emails, invalid_emails, 'email', u)
  end

Can anyone suggest any improvements?


Creative Commons License


This work is licensed under a
Creative Commons Attribution 2.0 UK: England & Wales License.

I first noticed that I was a slave to Facebook when I was talking to a friend of a friend. We talked casually for a while, in the normal ‘getting to know you’ way, eventually touching on whether each other has a Facebook account. This seemed perfectly natural, however, on reflection, I could see that I had actually been working towards this question for the entire conversation; I wanted to breech The Facebook Threshold, and add this person as a friend.

This was not the first time I had considered the possibility that I have been trawling my friends friend lists just to increase the friend count on my own profile, rather the first time I have accepted this seemingly innocuous yet worrying prospect.

Speaking to my own friends, I find that this trend continues: many of those with more than fifty friends have actually collected people that they don’t consider to be friends with any more – people from their pre-school days that are now 25 years old or more, and that they haven’t spoken to or seen in the intervening period.

Maybe it’s just our social vanity getting the best of us, but escaping from this arms race feels almost impossible from the inside.

The problem is simple; I wanted a method by which a model in my app could use a table from another MySQL Database (on the same server). The solution is equally simple:

  class MyModel < ActiveRecord::Base
    set_table_name "other_db.table_name"
  end

Where other_db is the database name, and table_name is the table you want to use.