Module: Piggyback::ClassMethods

Defined in:
lib/piggyback.rb

Instance Method Summary collapse

Instance Method Details

#piggyback(*assoc_names) ⇒ Object



100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
# File 'lib/piggyback.rb', line 100

def piggyback(*assoc_names)
  columns = piggyback_associations.values_at(*assoc_names).map do |association|
    association.map do |attr_name, mapped_name|
      if attr_name == mapped_name
        "#{association.quoted_table_name}.#{connection.quote_column_name(attr_name)}"
      else
        if mapped_name.is_a? Arel::Nodes::SqlLiteral
          "#{mapped_name} AS #{attr_name}"
        else
          "#{association.quoted_table_name}.#{connection.quote_column_name(mapped_name)} AS #{attr_name}"
        end
      end
    end
  end
  columns.unshift("#{quoted_table_name}.*") unless scoped.select_values.any?
  select(columns.flatten.join(', ')).joins(*assoc_names)
end

#piggyback_association_for_attribute(attr_name) ⇒ Object



48
49
50
# File 'lib/piggyback.rb', line 48

def piggyback_association_for_attribute(attr_name)
  piggyback_associations.each_value.detect{ |association| association.has_attribute? attr_name }
end

#piggyback_associationsObject



44
45
46
# File 'lib/piggyback.rb', line 44

def piggyback_associations
  read_inheritable_attribute(:piggyback_associations) || write_inheritable_attribute(:piggyback_associations, {})
end

#piggyback_attributes(assoc_name) ⇒ Object



96
97
98
# File 'lib/piggyback.rb', line 96

def piggyback_attributes(assoc_name)
  piggyback_associations[assoc_name].attributes
end

#piggybacks(association, *attributes) ⇒ Object

Raises:

  • (ArgumentError)


52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
# File 'lib/piggyback.rb', line 52

def piggybacks(association, *attributes)
  
  attributes.flatten!
  mapped_attributes = attributes.extract_options!
  reflection = reflect_on_association(association.to_sym)
  
  raise ArgumentError, "#{name} has no association named '#{association}'"           if reflection.nil?
  raise ArgumentError, "Piggyback only supports belongs_to and has_one associations" if reflection.collection?
  raise ArgumentError, "No attributes specified for piggybacking"                    if attributes.empty?
        
  mappings = {}
  
  attributes.each do |attr_name|
    mappings[attr_name.to_s] = attr_name.to_s
  end
  
  mapped_attributes.each do |attr_name, mapped_name|
    mappings[attr_name.to_s] = mapped_name.is_a?(String) ? Arel.sql(mapped_name) : mapped_name.to_s
  end

  association = (piggyback_associations[reflection.name] ||= Association.new(reflection))
  association.add_mappings(mappings)

  # These default procs for +columns_hash+ and +serialized_attributes+
  # allow +read_attribute+ to work transparently and consistently with 
  # attributes from joined models. They rely heavily on the implementation
  # of +read_attribute+ and related methods. Since ActiveRecord doesn't
  # provide hooks for overriding this behavior, it is the simplest and
  # least intrusive way to implement proper type casting for attributes
  # while avoiding code duplication.
  
  columns_hash.default_proc = lambda do |hash, attr_name|
    if association = piggyback_association_for_attribute(attr_name)
      association.column(attr_name)
    end
  end

  serialized_attributes.default_proc = lambda do |hash, attr_name|
    if association = piggyback_association_for_attribute(attr_name)
      association.serialized_attribute(attr_name)
    end
  end
end