Upgrading to v1.0

assembler edited this page Sep 11, 2012 · 3 revisions
Clone this wiki locally

Version 1.0 is not backward compatible. Here is what you need to do in order to upgrade.

Little background

Attachinary was initially developed to handle attachments as N-N relations. The idea was that single attachment could be attached to multiple models (if needed). Something like gallery of images where you can just pick the ones you want and attach them to one or more models. I realized that this scenario is rare, and causing performance issues. Even if you use this approach, you will likely need to associate attributes like title and keywords to your files (in order to make your gallery searchable) so you'll end up making your own attachment model with 1-1 relation with attachinary file.

So I decided to drop this and simplify everything. Now, all relations are polymorphic 1-N (model can have zero, one or more attachments). That being said, we only need 1 table to store all attachments.

Step 1: Migrating the database

The first thing is to migrate the database from using 2 tables to using just one. Just create new database migration (e.g. rails generate migration UpgradeAttachinaryToVersionOne) and put the following code inside.

class UpgradeAttachinaryToVersionOne < ActiveRecord::Migration
  def up
    add_column :attachinary_files, :attachinariable_id, :integer
    add_column :attachinary_files, :attachinariable_type, :string
    add_column :attachinary_files, :scope, :string
    add_index  :attachinary_files, [:attachinariable_type, :attachinariable_id, :scope], name: 'by_attachinariable'

    ActiveRecord::Base.connection.execute %{
      UPDATE attachinary_files SET
        attachinariable_id   = (SELECT parent_id FROM attachinary_attachments WHERE file_id = attachinary_files.id),
        attachinariable_type = (SELECT parent_type FROM attachinary_attachments WHERE file_id = attachinary_files.id),
        scope                = (SELECT scope FROM attachinary_attachments WHERE file_id = attachinary_files.id)
    }

    drop_table :attachinary_attachments
  end

  def down
    remove_column :attachinary_files, :attachinariable_id, :attachinariable_type, :scope

    create_table :attachinary_attachments do |t|
      t.belongs_to :parent, polymorphic: true
      t.belongs_to :file
      t.string :scope
      t.timestamps
    end
    add_index :attachinary_attachments, [:parent_type, :parent_id, :scope], name: 'by_scoped_parent'
  end
end

You may want to split this into more migrations if you want to make sure that the given SQL will do the right thing on your database. It is generic, but I have tested it only in sqlite, so be advised!

Step 2: Fixing helper method calls

On older version of attachinary you were supposed to call file input helper method like this:

<%= attachinary_file_field_tag 'user[avatar_id]', user.avatar_id, attachinary: user.avatar_options %>

That has been changed into this:

<%= attachinary_file_field_tag 'user[avatar]', user, :avatar %>

You have to do "search and replace" on your project to fix this, or just run your tests and let them guide you. If you've used simple_form, then you're all good and there is nothing for you to change.

Step 3: Fixing models

Attachinary v1 no longer has methods with _id suffix (like avatar_id). You probably referenced to these when defining validations. So, instead of writing:

validates :avatar_id, presence: true

You'll need to write:

validates :avatar, presence: true