Turns out the documentation for CarrierWave is slightly wrong. There is a more up to date piece of code in the README at the GitHub repository for the project.
In a nutshell, though:
pi = ProductImage.create!(:product => product)
pi.image.store!(File.open(File.join(Rails.root, 'test.jpg')))
product.product_images << pi
product.save!