Sequel Polymorphic

A simple plugin for Sequel::Model’s that lets you easily create polymorphic associations.

ActiveRecord Style


class Asset < ActiveRecord::Base

belongs_to :attachable, :polymorphic => true

end

class Post < ActiveRecord::Base

has_many :assets, :as => :attachable

end

class Note < ActiveRecord::Base

has_many :assets, :as => :attachable

end

@asset.attachable = @post @asset.attachable = @note

In Sequel you would do the following:

class Asset < Sequel::Model

many_to_one :attachable, :reciprocal=>:assets, \
  :dataset=>(proc do
    klass = attachable_type.constantize
    klass.filter(klass.primary_key=>attachable_id)
  end), \
  :eager_loader=>(proc do |key_hash, assets, associations|
    id_map = {}
    assets.each do |asset|
      asset.associations[:attachable] = nil
      ((id_map[asset.attachable_type] ||= {})[asset.attachable_id] ||= []) << asset
    end
    id_map.each do |klass_name, id_map|
      klass = klass_name.constantize
      klass.filter(klass.primary_key=>id_map.keys).all do |attach|
        id_map[attach.pk].each do |asset|
          asset.associations[:attachable] = attach
        end
      end
    end
  end)

private

def _attachable=(attachable)
  self[:attachable_id] = (attachable.pk if attachable)
  self[:attachable_type] = (attachable.class.name if attachable)
end

end

class Post < Sequel::Model

one_to_many :assets, :key=>:attachable_id do |ds|
  ds.filter(:attachable_type=>'Post')
end

private

def _add_asset(asset)
  asset.attachable_id = pk
  asset.attachable_type = 'Post'
  asset.save
end
def _remove_asset(asset)
  asset.attachable_id = nil
  asset.attachable_type = nil
  asset.save
end
def _remove_all_assets
  Asset.filter(:attachable_id=>pk, :attachable_type=>'Post')\
    .update(:attachable_id=>nil, :attachable_type=>nil)
end

end

class Note < Sequel::Model

one_to_many :assets, :key=>:attachable_id do |ds|
  ds.filter(:attachable_type=>'Note')
end

private

def _add_asset(asset)
  asset.attachable_id = pk
  asset.attachable_type = 'Note'
  asset.save
end
def _remove_asset(asset)
  asset.attachable_id = nil
  asset.attachable_type = nil
  asset.save
end
def _remove_all_assets
  Asset.filter(:attachable_id=>pk, :attachable_type=>'Note')\
    .update(:attachable_id=>nil, :attachable_type=>nil)
end

end

@asset.attachable = @post @asset.attachable = @note

Thats quite a bit of code. With sequel_polymorphic you can now do:

class Note < Sequel::Model

is :polymorphic, :as => :attachable

end

voila!