Created
July 24, 2008 15:14
-
-
Save boffbowsh/2172 to your computer and use it in GitHub Desktop.
Put has_metadata.rb in lib, then use has_metadata :os in your model
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class CreateMetaKeys < ActiveRecord::Migration | |
def self.up | |
create_table :meta_meta_key do |t| | |
t.integer :data_type, :limit => 1 | |
t.string :object_type, :associated_type, :key, :description | |
t.timestamps | |
end | |
MetaKey.reset_column_information | |
MetaKey.create! :key => "os", :description => "Operating System", :data_type => :String, | |
:object_type => "File" | |
end | |
end | |
def self.down | |
drop_table :meta_meta_key | |
end | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class CreateMetastores < ActiveRecord::Migration | |
def self.up | |
create_table :meta_metastore do |t| | |
t.integer :key_id, :object_id | |
t.timestamps | |
t.string :value | |
end | |
end | |
def self.down | |
drop_table :meta_metastore | |
end | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
module ActiveRecord | |
module Acts | |
module Metadata | |
def self.included(base) | |
base.extend ClassMethods | |
end | |
module InstanceMethods | |
def find_meta_for_belongs_to key_id, association_class | |
return nil if self.id.nil? | |
assoc = association_class | |
data = assoc.find_by_sql <<-EOF | |
SELECT * FROM #{assoc.table_name} a_t | |
INNER JOIN #{Metastore.table_name} m_t ON m_t.value = a_t.#{assoc.primary_key} | |
WHERE m_t.object_id = #{self.id} | |
AND m_t.key_id = #{key_id} | |
EOF | |
data[0] | |
end | |
def find_meta_for_has_many key_id, association_class | |
return [] if self.id.nil? | |
assoc = association_class | |
assoc.find_by_sql <<-EOF | |
SELECT * FROM #{assoc.table_name} a_t WHERE a_t.#{assoc.primary_key} IN | |
( SELECT value FROM #{Metastore.table_name} m_t | |
WHERE m_t.object_id = #{self.id} | |
AND m_t.key_id = #{key_id} ) | |
EOF | |
end | |
def find_meta_for_scalar key_id, data_type | |
return nil if self.id.nil? | |
metadata = get_meta_for key_id | |
cast_dispatch = {:String => :to_s, :Fixnum => :to_i, :Time => :to_time} | |
metadata.value.send cast_dispatch[data_type.to_sym] | |
end | |
def update_meta_belongs_to key_id, association_class, new_assoc | |
raise ActiveRecord::RecordNotSaved if self.id.nil? | |
raise ActiveRecord::AssociationTypeMismatch unless | |
new_assoc.is_a? association_class | |
metadata = get_meta_for key_id | |
metadata.value = new_assoc.id | |
metadata.save! | |
end | |
def update_meta_has_many key_id, association_class, new_assocs | |
raise ActiveRecord::RecordNotSaved if self.id.nil? | |
new_assocs = [new_assocs] unless new_assocs.is_an? Array | |
raise ActiveRecord::AssociationTypeMismatch unless | |
new_assocs.map {|assoc| assoc.is_a? association_class}.all? | |
metadata = get_meta_for key_id | |
metadata.value = new_assocs.map(&:id).join ',' | |
metadata.save! | |
end | |
def update_meta_scalar key_id, new_value | |
raise ActiveRecord::RecordNotSaved if self.id.nil? | |
metadata = get_meta_for key_id | |
metadata.value = new_value | |
metadata.save! | |
end | |
def get_meta_for key_id | |
meta = Metastore.find :first, | |
:conditions => {:object_id => self.id, | |
:key_id => key_id} | |
meta = !meta.nil? ? meta : (Metastore.new :object_id => self.id, | |
:key_id => key_id) | |
end | |
end | |
module ClassMethods | |
def has_metadata *keys | |
send :include, InstanceMethods | |
class_eval "@@metadata_keys = #{keys.inspect}" | |
class_eval "def self.metadata_keys; @@metadata_keys; end" | |
keys.map(&:to_s).each do |key| | |
meta_key = MetaKey.find :first, | |
:conditions => { :object_type => yaml_tag_class_name, | |
:key => key } | |
raise InvalidMetaKey.new(key) unless meta_key.is_a?(MetaKey) | |
class_eval "attr_protected #{key.inspect}" | |
case meta_key.data_type | |
when :belongs_to | |
class_eval <<-EOF | |
def #{meta_key.key} | |
find_meta_for_belongs_to #{meta_key.id}, #{meta_key.associated_type} | |
end | |
def #{meta_key.key}= value | |
update_meta_belongs_to #{meta_key.id}, #{meta_key.associated_type}, value | |
end | |
EOF | |
when :has_many | |
class_eval <<-EOF | |
def #{meta_key.key} | |
find_meta_for_has_many #{meta_key.id}, #{meta_key.associated_type} | |
end | |
def #{meta_key.key}= value | |
update_meta_has_many #{meta_key.id}, #{meta_key.associated_type}, value | |
end | |
EOF | |
else | |
class_eval <<-EOF | |
def #{meta_key.key} | |
find_meta_for_scalar #{meta_key.id}, #{meta_key.data_type.inspect} | |
end | |
def #{meta_key.key}= value | |
update_meta_scalar #{meta_key.id}, value | |
end | |
EOF | |
end | |
end | |
end | |
end | |
class InvalidMetaKey < Exception | |
attr_reader :key | |
def initialize key | |
@key = key | |
end | |
def message | |
"Invalid key #{key}" | |
end | |
end | |
end | |
end | |
end | |
ActiveRecord::Base.send :include, ActiveRecord::Acts::Metadata |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class MetaKey < ActiveRecord::Base | |
set_table_name "meta_meta_key" | |
validates_uniqueness_of :key, :scope => :object_type | |
acts_as_enum :data_type, [:String, :Fixnum, :Time, :belongs_to, :has_many] | |
has_many :metadatas | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class Metadata < ActiveRecord::Base | |
set_table_name "meta_metadata" | |
belongs_to :meta_object, :polymorphic => true | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment