module RedisOrm::Associations::BelongsTo

Public Instance Methods

belongs_to(foreign_model, options = {}) click to toggle source

class Avatar < RedisOrm::Base

belongs_to :user

end

class User < RedisOrm::Base

has_many :avatars

end

avatar.user => avatar:234:user => 1 => User.find(1)

    # File lib/redis_orm/associations/belongs_to.rb
 13 def belongs_to(foreign_model, options = {})
 14   class_associations = class_variable_get(:"@@associations")
 15   class_variable_get(:"@@associations")[model_name] << {:type => :belongs_to, :foreign_model => foreign_model, :options => options}
 16 
 17   foreign_model_name = options[:as] ? options[:as].to_sym : foreign_model.to_sym
 18   
 19   if options[:index]
 20     class_variable_get(:"@@indices")[model_name] << {:name => foreign_model_name, :options => {:reference => true}}
 21   end
 22   
 23   define_method foreign_model_name do
 24     if options[:polymorphic]
 25       model_type = $redis.get("#{model_name}:#{id}:#{foreign_model_name}_type")
 26       if model_type
 27         model_type.to_s.camelize.constantize.find($redis.get "#{model_name}:#{@id}:#{foreign_model_name}_id")
 28       end
 29     else
 30       # find model even if it's in some module
 31       full_model_scope = RedisOrm::Base.descendants.detect{|desc| desc.to_s.split('::').include?(foreign_model.to_s.camelize) }
 32       if full_model_scope
 33         full_model_scope.find($redis.get "#{model_name}:#{@id}:#{foreign_model_name}")
 34       else
 35         foreign_model.to_s.camelize.constantize.find($redis.get "#{model_name}:#{@id}:#{foreign_model_name}")
 36       end
 37     end
 38   end
 39   
 40   # look = Look.create :title => 'test'
 41   # look.user = User.find(1) => look:23:user => 1
 42   define_method "#{foreign_model_name}=" do |assoc_with_record|
 43     # we need to store this to clear old association later
 44     old_assoc = self.send(foreign_model_name)
 45 
 46     # find model even if it's in some module
 47     full_model_scope = RedisOrm::Base.descendants.detect{|desc| desc.to_s.split('::').include?(foreign_model.to_s.camelize) }
 48     
 49     if options[:polymorphic]
 50       $redis.set("#{model_name}:#{id}:#{foreign_model_name}_type", assoc_with_record.model_name)
 51       $redis.set("#{model_name}:#{id}:#{foreign_model_name}_id", assoc_with_record.id)
 52     else
 53       if assoc_with_record.nil?
 54         $redis.del("#{model_name}:#{id}:#{foreign_model_name}")
 55       elsif [foreign_model.to_s, full_model_scope.model_name].include?(assoc_with_record.model_name)
 56         $redis.set("#{model_name}:#{id}:#{foreign_model_name}", assoc_with_record.id)
 57       else
 58         raise TypeMismatchError
 59       end
 60     end
 61 
 62     # handle indices for references
 63     self.get_indices.select{|index| index[:options][:reference]}.each do |index|
 64       # delete old reference that points to the old associated record
 65       if !old_assoc.nil?
 66         prepared_index = [self.model_name, index[:name], old_assoc.id].join(':')
 67         prepared_index.downcase! if index[:options][:case_insensitive]
 68 
 69         if index[:options][:unique]
 70           $redis.del(prepared_index, id)
 71         else
 72           $redis.zrem(prepared_index, id)
 73         end
 74       end
 75       
 76       # if new associated record is nil then skip to next index (since old associated record was already unreferenced)
 77       next if assoc_with_record.nil?
 78       
 79       prepared_index = [self.model_name, index[:name], assoc_with_record.id].join(':')
 80 
 81       prepared_index.downcase! if index[:options][:case_insensitive]
 82 
 83       if index[:options][:unique]
 84         $redis.set(prepared_index, id)
 85       else
 86         $redis.zadd(prepared_index, Time.now.to_f, id)
 87       end
 88     end
 89     
 90     # we should have an option to delete created earlier associasion (like 'node.owner = nil')
 91     if assoc_with_record.nil?
 92       # remove old assoc
 93       $redis.zrem("#{old_assoc.model_name}:#{old_assoc.id}:#{model_name.to_s.pluralize}", self.id) if old_assoc
 94     else
 95       # check whether *assoc_with_record* object has *has_many* declaration and TODO it states *self.model_name* in plural and there is no record yet from the *assoc_with_record*'s side (in order not to provoke recursion)
 96       if class_associations[assoc_with_record.model_name].detect{|h| h[:type] == :has_many && h[:foreign_models] == model_name.pluralize.to_sym} && !$redis.zrank("#{assoc_with_record.model_name}:#{assoc_with_record.id}:#{model_name.pluralize}", self.id)
 97         # remove old assoc
 98         $redis.zrem("#{old_assoc.model_name}:#{old_assoc.id}:#{model_name.to_s.pluralize}", self.id) if old_assoc
 99         assoc_with_record.send(model_name.pluralize.to_sym).send(:"<<", self)
100 
101       # check whether *assoc_with_record* object has *has_one* declaration and TODO it states *self.model_name* and there is no record yet from the *assoc_with_record*'s side (in order not to provoke recursion)
102       elsif class_associations[assoc_with_record.model_name].detect{|h| h[:type] == :has_one && h[:foreign_model] == model_name.to_sym} && assoc_with_record.send(model_name.to_sym).nil?
103         # old association is being rewritten here automatically so we don't have to worry about it
104         assoc_with_record.send("#{model_name}=", self)
105       end
106     end
107   end
108 end