A ‘joins_many’ relation. This objects is associated with an other using an intermediate join table.

Examples

joins_many :categories joins_many Category joins_many :categories, MyCategory

Methods
Public Instance methods
enchant()
     # File lib/og/relation/joins_many.rb, line 36
 36:   def enchant
 37:     self[:owner_singular_name] = owner_class.to_s.demodulize.underscore.downcase 
 38:     self[:target_singular_name] = target_plural_name.to_s.singular
 39: 
 40:     owner_class.ogmanager.with_store do |store|
 41:       # handle schema_inheritance
 42:       
 43:       join_class = owner_class.table_class
 44:       join_table_info = store.join_table_info(self)
 45:       
 46:       if through = self[:through] 
 47:         # A custom class is used for the join. Use the class 
 48:         # table and don't create a new table.
 49: 
 50:         through = Relation.symbol_to_class(through, owner_class) if through.is_a?(Symbol)
 51:         join_table = self[:join_table] = store.table(through)
 52:         
 53:         tmp_join_class = through
 54:       else    
 55:         # Calculate the name of the join table.
 56: 
 57:         join_table = self[:join_table] = join_table_info[:table]
 58: 
 59:         # Create a join table.
 60: 
 61:         owner_class.ann!(:self)[:join_tables] ||= []
 62:         owner_class.ann!(:self, :join_tables) << join_table_info
 63:         
 64:         # Create temporary classes to be able to use ann.descendants to cascade
 65:         # delete joins_many relations when one side of the relation is removed.
 66:         
 67:         tmp_join_class_name = "OgTempJ_#{join_table}"
 68:         
 69:         unless self.class.constants.include?(tmp_join_class_name)
 70:           tmp_join_class = self.class.const_set(tmp_join_class_name, Class.new)
 71:           tmp_join_class.const_set('OGTABLE', join_table)
 72:         else
 73:           tmp_join_class = self.class.const_get(tmp_join_class_name)
 74:         end
 75:       end
 76:       
 77:       owner_key = join_table_info[:owner_key]
 78:       target_key = join_table_info[:target_key]
 79:       
 80:       # Add join class to ann(:descendants) to be able to use cascade deletes.
 81: 
 82:       owner_class.ann!(:self)[:descendants] ||= []
 83:       owner_class.ann!(:self, :descendants) << [tmp_join_class, owner_key]
 84: 
 85:       owner_class.module_eval %{ 
 86:         attr_accessor :#{target_plural_name}
 87: 
 88:         def #{target_plural_name}(options = nil)
 89:           reload = options and options[:reload]
 90: 
 91:           unless @#{target_plural_name}
 92:             @#{target_plural_name} = JoinsManyCollection.new(
 93:               self, 
 94:               #{target_class},
 95:               :add_#{target_singular_name},
 96:               :remove_#{target_singular_name},
 97:               :find_#{target_plural_name},
 98:               :count_#{target_plural_name},
 99:               options
100:             )
101:           end
102: 
103:           @#{target_plural_name}.find_options = options
104:           @#{target_plural_name}.reload(options) if options and options[:reload]
105:           @#{target_plural_name}
106:         end
107: 
108:         def add_#{target_singular_name}(obj, options = nil)
109:           obj.save if obj.unsaved?
110:           obj.class.ogmanager.with_store do |s|
111:             s.join(self, obj, "#{join_table}", options)
112:           end
113:         end
114: 
115:         def remove_#{target_singular_name}(obj)
116:           obj.class.ogmanager.with_store do |s|
117:             s.unjoin(self, obj, "#{join_table}")
118:           end
119:         end
120: 
121:         def find_#{target_plural_name}(options = {})
122:           find_options = {
123:             :join_table => "#{join_table}",
124:             :join_condition => "#{join_table}.#{target_key}=\#{#{target_class}::OGTABLE}.oid",
125:             :condition => "#{join_table}.#{owner_key}=\#\{#{owner_class.primary_key}\}"          
126:           }
127:           if options
128:             if condition = options.delete(:condition)
129:               find_options[:condition] += " AND (\#{condition})"
130:             end        
131:             find_options.update(options)
132:           end        
133:           #{target_class}.find(find_options)
134:         end      
135: 
136:         def count_#{target_plural_name}
137:           find_options = {
138:             :join_table => "#{join_table}",
139:             :join_condition => "#{join_table}.#{target_key}=\#{#{target_class}::OGTABLE}.oid",
140:             :condition => "#{join_table}.#{owner_key}=\#\{#{owner_class.primary_key}\}"
141:           }
142:           #{target_class}.count(find_options)
143:         end
144:       }
145:       
146:       if through
147:         owner_class.module_eval %{
148:           def #{target_singular_name}_join_data(t)
149:             #{through}.find_one(:condition => "#{owner_key}=\#{#{owner_class.primary_key}} and #{target_key}=\#{t.pk}")
150:           end
151:         }
152:       end    
153:     end
154:   end
resolve_polymorphic()
    # File lib/og/relation/joins_many.rb, line 30
30:   def resolve_polymorphic
31:     target_class.module_eval %{
32:       joins_many :#{owner_class.to_s.demodulize.underscore.pluralize}
33:     }
34:   end