Module: ApiResource::Associations::ClassMethods

Defined in:
lib/api_resource/associations.rb

Instance Method Summary collapse

Instance Method Details

#association?(assoc) ⇒ Boolean

Returns:

  • (Boolean)


121
122
123
124
125
126
# File 'lib/api_resource/associations.rb', line 121

def association?(assoc)
  self.related_objects.any? do |key, value|
    next if key.to_s == "scopes"
    value.detect { |k,v| k.to_sym == assoc.to_sym }
  end
end

#association_class(assoc) ⇒ Object



133
134
135
# File 'lib/api_resource/associations.rb', line 133

def association_class(assoc)
  self.association_class_name(assoc).constantize
end

#association_class_name(assoc) ⇒ Object

Raises:

  • (ArgumentError)


137
138
139
140
141
142
143
# File 'lib/api_resource/associations.rb', line 137

def association_class_name(assoc)
  raise ArgumentError, "#{assoc} is not a valid association of #{self}" unless self.association?(assoc)
  result = self.related_objects.detect do |key,value|
    ret = value.detect{|k,v| k.to_sym == assoc.to_sym }
    return self.find_namespaced_class_name(ret[1]) if ret
  end
end

#association_foreign_key_field(assoc, type = nil) ⇒ Object

TODO: add a special foreign_key option to associations



146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
# File 'lib/api_resource/associations.rb', line 146

def association_foreign_key_field(assoc, type = nil)

  if type.nil? && has_many?(assoc)
    type = :has_many
  else
    type = type.to_s.to_sym
  end

  # for now just use the association name
  str = assoc.to_s.singularize.foreign_key

  if type.to_s =~ /^has_many/
    str = str.pluralize
  end

  str.to_sym
end

#association_namesObject



128
129
130
131
# File 'lib/api_resource/associations.rb', line 128

def association_names
  # structure is {:has_many => {"myname" => "ClassName"}}
  self.related_objects.clone.delete_if{|k,v| k.to_s == "scopes"}.collect{|k,v| v.keys.collect(&:to_sym)}.flatten
end

#define_association_methodsObject

Define the methods for creating and testing for associations, unfortunately scopes are different enough to require different methods :(



77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
# File 'lib/api_resource/associations.rb', line 77

def define_association_methods
  self.association_types.each_key do |assoc|
    self.instance_eval <<-EOE, __FILE__, __LINE__ + 1
      def #{assoc}(*args)
        options = args.extract_options!
        options = options.with_indifferent_access
        # Raise an error if we have multiple args and options
        raise "Invalid arguments to #{assoc}" unless options.blank? || args.length == 1
        args.each do |arg|
          klass_name = (options[:class_name] ? options[:class_name].to_s.classify : arg.to_s.classify)
          # add this to any descendants - the other methods etc are handled by inheritance
          ([self] + self.descendants).each do |klass|
            #We need to merge upon itself to generate a new object since the children all share their related objects with each other
            klass.related_objects = klass.related_objects.merge(:#{assoc} => klass.related_objects[:#{assoc}].merge(arg.to_sym => klass_name))
          end
          # We need to define reader and writer methods here
          define_association_as_attribute(:#{assoc}, arg, options)
        end
      end

      def #{assoc}?(name)
        return self.related_objects[:#{assoc}][name.to_s.pluralize.to_sym].present? || self.related_objects[:#{assoc}][name.to_s.singularize.to_sym].present?
      end

      def #{assoc}_class_name(name)
        raise "No such" + :#{assoc}.to_s + " association on #{name}" unless self.#{assoc}?(name)
        return self.find_namespaced_class_name(self.related_objects[:#{assoc}][name.to_sym])
      end

    EOE
    # For convenience we will define the methods for testing for the existence of an association
    # and getting the class for an association as instance methods too to avoid tons of self.class calls
    self.class_eval <<-EOE, __FILE__, __LINE__ + 1
      def #{assoc}?(name)
        return self.class.#{assoc}?(name)
      end

      def #{assoc}_class_name(name)
        return self.class.#{assoc}_class_name(name)
      end
    EOE
  end
end