module RedisOrm::Associations::HasMany

Public Instance Methods

has_many(foreign_models, options = {}) click to toggle source

user.avatars => user:1:avatars => [1, 22, 234] => Avatar.find([1, 22, 234]) options

*:dependant* key: either *destroy* or *nullify* (default)
   # File lib/redis_orm/associations/has_many.rb
 7 def has_many(foreign_models, options = {})
 8   class_associations = class_variable_get(:"@@associations")
 9   class_associations[model_name] << {:type => :has_many, :foreign_models => foreign_models, :options => options}
10   
11   foreign_models_name = options[:as] ? options[:as].to_sym : foreign_models.to_sym
12 
13   define_method foreign_models_name.to_sym do
14     Associations::HasManyProxy.new(model_name, id, foreign_models, options)
15   end
16 
17   # user = User.find(1)
18   # user.avatars = Avatar.find(23) => user:1:avatars => [23]
19   define_method "#{foreign_models_name}=" do |records|
20     if !options[:as]
21       # clear old assocs from related models side
22       old_records = self.send(foreign_models).to_a
23       if !old_records.empty?
24         # cache here which association with current model have old record's model
25         has_many_assoc = old_records[0].get_associations.detect do |h|
26           h[:type] == :has_many && h[:foreign_models] == model_name.pluralize.to_sym
27         end
28         
29         has_one_or_belongs_to_assoc = old_records[0].get_associations.detect do |h|
30           [:has_one, :belongs_to].include?(h[:type]) && h[:foreign_model] == model_name.to_sym
31         end
32         
33         old_records.each do |record|
34           if has_many_assoc
35             $redis.zrem "#{record.model_name}:#{record.id}:#{model_name.pluralize}", id
36           elsif has_one_or_belongs_to_assoc
37             $redis.del "#{record.model_name}:#{record.id}:#{model_name}"
38           end
39         end
40       end
41       
42       # clear old assocs from this model side
43       $redis.zremrangebyscore "#{model_name}:#{id}:#{foreign_models}", 0, Time.now.to_f
44     end
45 
46     records.to_a.each do |record|
47       # we use here *foreign_models_name* not *record.model_name.pluralize* because of the :as option
48       key = "#{model_name}:#{id}:#{foreign_models_name}"
49       $redis.zadd(key, Time.now.to_f, record.id)
50       set_expire_on_reference_key(key)
51       
52       record.get_indices.each do |index|
53         save_index_for_associated_record(index, record, [model_name, id, record.model_name.pluralize]) # record.model_name.pluralize => foreign_models_name
54       end
55 
56       # article.comments = [comment1, comment2]
57       # iterate through the array of comments and create backlink
58       # check whether *record* object has *has_many* declaration and it states *self.model_name* in plural
59       if assoc = class_associations[record.model_name].detect{|h| h[:type] == :has_many && h[:foreign_models] == model_name.pluralize.to_sym} #&& !$redis.zrank("#{record.model_name}:#{record.id}:#{model_name.pluralize}", id)#record.model_name.to_s.camelize.constantize.find(id).nil?
60         assoc_foreign_models_name = assoc[:options][:as] ? assoc[:options][:as] : model_name.pluralize
61         key = "#{record.model_name}:#{record.id}:#{assoc_foreign_models_name}"
62         $redis.zadd(key, Time.now.to_f, id) if !$redis.zrank(key, id)
63         set_expire_on_reference_key(key)
64       end
65         
66       # check whether *record* object has *has_one* declaration and it states *self.model_name*
67       if assoc = record.get_associations.detect{|h| [:has_one, :belongs_to].include?(h[:type]) && h[:foreign_model] == model_name.to_sym}
68         foreign_model_name = assoc[:options][:as] ? assoc[:options][:as] : model_name
69         key = "#{record.model_name}:#{record.id}:#{foreign_model_name}"
70         # overwrite assoc anyway so we don't need to check record.send(model_name.to_sym).nil? here
71         $redis.set(key, id)              
72         set_expire_on_reference_key(key)
73       end
74     end
75   end
76 end