Freelancing Gods 2014

God
04 Dec 2007

validates_uniqueness_of_set

Rails code snippet for the day: validates_uniqueness_of_set. Useful for making sure each specific combination of the specified attributes is unique. Example from the pastie:

validates_uniqueness_of_set :first_name, :last_name

Just like the options it accepts, the code is very similar to validates_uniqueness_of – and the few tests I’ve thrown at it are handled without any problems.

03 Dec 2007

Link: :: GIANT ROBOTS SMASHING INTO OTHER GIANT ROBOTS :: save bang your head, active record will drive you mad

"exceptions should not be expected"

02 Dec 2007

Sphinx-related Updates

Two Sphinx-related tidbits:

Riddle

Riddle now has a tag in SVN for the 0.9.8-r909 release of Sphinx – not that there were really any functional changes compared to r871, besides the two extra match modes (Full Scan and Extended 2 – the latter isn’t going to hang around for long anyway).

Thinking Sphinx

As well as supporting the above version of Sphinx, I’ve now added some brief documentation to Thinking Sphinx that discusses attributes, sorting and delta indexes. To summarise kinda-briefly:

Attributes

Attributes are defined in the define_index block as follows:

define_index do |index|
  index.has.created_at
  index.has.updated_at
  # Field definitions go here
end

They can only be from the indexed model (not associations), and in line with Sphinx’s limitations, must be either integers, floats or timestamps.

Sorting

Ties in closely with attributes – as that’s all Sphinx will let you order by. Use it in the same way as you would in a find call:

Invoice.search :conditions => "expensive", :order => "created_at DESC"

Same approach works for the :include parameter (although this has nothing to do with Sphinx itself).

Delta Indexes

Delta indexes track changes to model records between proper indexes (ie: from the rake task thinking_sphinx:index) – all they require is a boolean field in the model’s table called delta, and for delta indexing to be enabled as follows:

define_index do |index|
  index.delta = true
  # Fields and attributes go here
end

The one catch – at this point, delta indexes are one step off current, as they get indexed before the current transaction to the database is committed. This will get better soon, thanks to some help from Joost Hietbrink and his colleagues at YelloYello – once I find some free time, I’ll get that working much more neatly.

26 Nov 2007

Link: Eli Miller: Proper cache expiry with after_commit

Can use this for any actions after transactions are committed - ie: Thinking Sphinx's delta indexing

26 Nov 2007

RailsCamp Wrap-up

RailsCamp 2.0 finished earlier today – and I think it’s safe to declare it a fantastic success (even given my bias).

Massive thanks to Ben and Karen for their hard work getting everyone fed and co-ordinating people in the kitchen (and the RailsCamp bus from Melbourne to Sunnystones). Thanks too to everyone who helped at various points – both in the organising and over the weekend.

Finally, thank you to everyone who came along – these camps are so much fun because of the calibre of people who attend, and their willingness to share ideas, code and laughs.

Will be posting a version of my talk at some point soon… once I’ve recovered from the weekend.

14 Nov 2007

Sphinx's Riddle

Edit: I’ve changed the Subversion reference to Github, and it’s worth noting that Riddle works with Sphinx 0.9.8, 0.9.9 and 1.10-beta at the time of writing (January 2011). Original post continues below:

Built out of the work I’ve done for Thinking Sphinx (which has just got basic support for delta indexes, attributes and sorting – although the documentation doesn’t reflect that), I’ve extracted a new Ruby client that communicates with Sphinx, which I’ve named Riddle.

I’m not going to delve into the code here – because I’m not expecting it to be that useful to many people (and I just wrote examples in the documentation – go read that instead!) – but I’m very happy with how it’s ended up, and it’s got some level of specs to give it a thorough test. It’s also compatible with the most recent release of Sphinx (0.9.8 r871). Should you wish to poke around with it, just clone it from Github:

git clone \
  git://github.com/freelancing-god/riddle.git

It’s also being used in Evan Weaver’s UltraSphinx plugin, which I’m pretty pleased about.

05 Nov 2007

Aliasing Actions in Rails

Tags:

Code snippet for application.rb that makes life just a little easier if multiple actions are doing exactly the same thing (both in the controller and the view):

def self.alias_action(existing, aliased)
  define_method(aliased.to_sym) do
    send(existing.to_sym)
    render :action => existing.to_s
  end
end

And then in the appropriate controller (where edit is an existing action, and show needs to be exactly the same):

alias_action :edit, :show

I know this is a specialised use – but perhaps someone else out there is doing something similar.

30 Oct 2007

RailsCamp Reminder

In case the few readers of this blog are not aware, there’s a RailsCamp happening just outside of Melbourne, from the 23rd-26th November (not far away at all). It will be a weekend of hacking, chatting, food & drink, and very likely some gaming (along the lines of GuitarHero and WiiSports), taking a similar approach to barcamps. The first one, back in June near Sydney, was a fantastic success, and judging by the current list of attendees, I’m expecting it to be much the same.

We’re edging closer and closer to being sold out, so if you’re considering coming along, I recommend signing up as soon as possible. Day passes for the Saturday and Sunday are also available.

23 Oct 2007

Request for Caching Questions

The monthly Melbourne Ruby meeting is happening this Thursday, and I’ll be presenting about Rails’ caching (of the page, action and fragment varieties). Just wondering if any of the few readers of this blog had either suggestions for content, or, especially, questions they’d like to see addressed in such a talk?

Slides will, of course, be posted after the meeting.

21 Oct 2007

Link: James on Software: Introducing resource_controller: Focus on what makes your controller special.

21 Oct 2007

Link: rubymatt's mailtrap-0.2.1 Documentation

A mock SMTP server for use in development environments.

18 Oct 2007

Link: ar-backup - Google Code

"Active Record backup is a Rails plugin which lets you backup your database schema and content in a schema.rb file and fixtures."

09 Oct 2007

Link: Hivelogic: Enkoder Rails Plugin

Plugin that encodes email links (and other content)

09 Oct 2007

Link: ActiveWarehouse: Let's Get Analytical

A library that looks really useful for when you're dealing with data to report on, as opposed to ActiveRecord models.

03 Oct 2007

A Thoughtful Sphinx

In one of the projects I’ve been working on lately, I’ve needed to implement a decent search – and so I looked at both Ferret and Sphinx. I ended up choosing the latter, although I’m not sure why – perhaps just to be different (most people I spoke to are using ferret), or perhaps because the setup seemed easier.

The next step was to pick a Sphinx plugin to work with. Ultrasphinx seemed to have a good set of features (particularly pagination), and supported fields from associations within indexes – something critical for what we were doing.

Unfortunately, grabbing fields from associations wasn’t that easy – and the SQL generated for the Sphinx configuration file was overly complex. I could (and did) change the config file manually, but that makes half the usefulness of the plugin worthless.

So, since I had some spare time, I wrote my own plugin. Much like Rails, it favours convention over configuration – perhaps a little too much so at this point, but I do plan to make it more flexible at some point. Installation is the same as any other plugin:

script/plugin install
  http://rails-oceania.googlecode.com/svn/patallan/thinking_sphinx

An example of defining indexes (within a model class):

define_index do |index|
  index.includes.email
  index.includes(:first_name, :last_name).as.name
  index.includes.tags.key.as.tags
  index.includes.articles.content.as.article_content
end

To index the data, just use the thinkingsphinx:index rake task (aliased to ts:in) – which will also generate the configuration file on the fly. My goal is to make changing the configuration file manually unnecessary – making the index task build the configuration file helps enforce this.

And to search:

# Searching particular fields
User.search(:conditions => {:name => "Pat"})
# Or searching all fields
User.search("Pat")
# Pagination is built in
User.search("Pat", :page => (params[:page] || 1))

Paginated results can also be used by the will_paginate helper from the plugin of the same name. Current documentation can be found on this site.

I managed to use ActiveRecord’s join and associations code, which kept my plugin reasonably lean. For interactions with Sphinx’s searchd daemon, I did look at Dmytro Shteflyuk’s Ruby Sphinx Client API, but the non-ruby-like syntax irritated me, so again, I coded my own – heavily influenced by the original though (ie: he did all the hard work, not me).

There’s no support for some way to update the index pseudo-incrementally (something that is a limitation of Sphinx). If I don’t feel like the incremental updating works well enough, then I may switch to Ferret – which might lead to a Thinking Ferret plugin, perhaps. We’ll just have to wait and see.

Nov 14th 2007 – Update: I’ve just released the internal Sphinx client as its own library – Riddle.

01 Oct 2007

Conditional Caching

Whenever I’ve described caching in Rails to anyone who isn’t familiar with it, I have made clear the limitations of each method:

  • Page caching is only useful when the output is exactly the same for every visitor, and you don’t need to confirm user authentication
  • Action caching allows you to run filters for every request – thus can be used to check if users are authenticated – but the rendered output has the same limitations as page caching
  • Fragment caching, while flexible, is definitely slower than the other two options.

Obviously, it’s best to use the fastest caching possible that fits your pages. That’s rarely page caching for the sites I code. Even action caching hasn’t been viable too often. Or so I thought.

I used to use fragment caching in most of my views – generally with extra parameters to indicate user role, so it would store different versions of the fragment for each role (ie: admin user, normal user, no user). This worked reasonably well, but often I was wrapping an entire view in a <% cache do %> block – almost action caching!

In the site I was coding at the time, ausdwcon.org, I realised the best time to cache would be when no user was logged in – as that would cover the majority of requests. So, to simplify: what I wanted was caching only when a certain condition was true.

Getting methods coded for conditional caching at a fragment level was a piece of cake. At the action caching level? Well, that was trickier, but with some help from the RORO crew I got it working, and into a plugin. You can find the code in the RORO svn repository and the documentation on this site. To install:

script/plugin install
  http://rails-oceania.googlecode.com/svn/patallan/conditional_caching

One brief example so you know what to expect:

# a controller
caches_action :index, :if => :no_user?

# application.rb
def no_user?
  session[:user_id].empty?
end

Obviously the :if parameter is the key – it can be a symbol pointer to an instance method on the controller, or it can be a Proc which is evaluated in the scope of the controller.

Now, the no-user condition is the only example I can think of where my plugin is useful – if you think of others, please let me know. Keep reading though, because I’ve got another helpful hint or two to share.

I mentioned above my usual method of using fragment caching – liberal use of extra parameters. It’s actually possible to do this with action caching too – which I only found out recently, so I’m assuming there are other people out there who aren’t aware of it either.

It’s not quite as easy as the equivalent fragment caching code, as you’re using both class and object level methods, but here’s an example:

# a controller
caches_action :index, :show, :cache_path => cache_params

# application.rb
def self.cache_params
  @cache_params ||= Proc.new { |controller|
    controller.params.merge(:role => controller.current_role)
  }
end

This has actually made me cut back on usage of my plugin – because most of my pages don’t have user-specific content.

Oh, and one more thing – to cut down on user-specific content in my views, I’ve been mapping my users controller as both a normal resource and a singleton resource. This means instead of a “Your Profile” link being /users/34, it’s just /user. Makes the controller code a little tricky, and the named routes get confused, but nothing a few clever helper methods can’t fix.

29 Aug 2007

Link: smartbomb - Hornsby

Scenario-focused spec'ing, instead of fixtures

09 Aug 2007

Link: PdfWriter and RailsPdf - RailsOnWave Ruby on Rails web 2.0 Ajax

Jim - is this something new?

03 Aug 2007

Link: SpinBits // Services

30 Jul 2007

Link: Client HTTP Caching in Rails - igvita.com

RssSubscribe to the RSS feed

About Freelancing Gods

Freelancing Gods is written by , who works on the web as a web developer in Melbourne, Australia, specialising in Ruby on Rails.

In case you're wondering what the likely content here will be about (besides code), keep in mind that Pat is passionate about the internet, music, politics, comedy, bringing people together, and making a difference. And pancakes.

His ego isn't as bad as you may think. Honest.

Here's more than you ever wanted to know.

Ruby on Rails Projects

Other Sites

Creative Commons Logo All original content on this site is available through a Creative Commons by-nc-sa licence.