| | 1648 | |
|---|
| | 1649 | #loads the named associations for the activerecord object (or objects) given |
|---|
| | 1650 | # |
|---|
| | 1651 | # |
|---|
| | 1652 | def preload_associations(top_objects, associations) |
|---|
| | 1653 | top_objects = [top_objects].flatten.compact |
|---|
| | 1654 | case associations |
|---|
| | 1655 | when Array then associations.each {|association| preload_associations top_objects, association} |
|---|
| | 1656 | when Symbol, String then preload_one_association top_objects, associations.to_sym |
|---|
| | 1657 | when Hash then |
|---|
| | 1658 | associations.each do |parent, child| |
|---|
| | 1659 | raise "parent must be an association name" unless parent.is_a?( String) || parent.is_a?( Symbol) |
|---|
| | 1660 | preload_associations top_objects, parent |
|---|
| | 1661 | reflection = reflections[parent] |
|---|
| | 1662 | parents = top_objects.map {|top_object| top_object.send reflection.name}.flatten |
|---|
| | 1663 | unless parents.empty? |
|---|
| | 1664 | parents.first.class.preload_associations parents, child |
|---|
| | 1665 | end |
|---|
| | 1666 | end |
|---|
| | 1667 | end |
|---|
| | 1668 | |
|---|
| | 1669 | end |
|---|
| | 1670 | |
|---|
| | 1671 | def preload_collection_object(id_to_object_map, reflection_name, associated_object, key) |
|---|
| | 1672 | association_proxy = id_to_object_map[associated_object[key].to_i].send(reflection_name) |
|---|
| | 1673 | association_proxy.loaded |
|---|
| | 1674 | if associated_object.is_a? Array |
|---|
| | 1675 | association_proxy.target.push(*associated_object) |
|---|
| | 1676 | else |
|---|
| | 1677 | association_proxy.target << associated_object |
|---|
| | 1678 | end |
|---|
| | 1679 | end |
|---|
| | 1680 | |
|---|
| | 1681 | def preload_single_object(id_to_object_map, reflection_name, associated_object, key) |
|---|
| | 1682 | id_to_object_map[associated_object[key].to_i].send("set_#{reflection_name}_target",associated_object) |
|---|
| | 1683 | end |
|---|
| | 1684 | |
|---|
| | 1685 | def preload_one_association(top_objects, association) |
|---|
| | 1686 | reflection = reflections[association] |
|---|
| | 1687 | raise ConfigurationError, "Association named '#{ association }' was not found; perhaps you misspelled it?" unless reflection |
|---|
| | 1688 | |
|---|
| | 1689 | reflection_name = reflection.name |
|---|
| | 1690 | options = reflection.options |
|---|
| | 1691 | table_name = reflection.klass.table_name |
|---|
| | 1692 | primary_key_name = reflection.primary_key_name |
|---|
| | 1693 | foreign_key = options[:foreign_key] || reflection.active_record.to_s.classify.foreign_key |
|---|
| | 1694 | |
|---|
| | 1695 | id_to_object_map = top_objects.index_by &:id |
|---|
| | 1696 | ids = top_objects.collect &:id |
|---|
| | 1697 | |
|---|
| | 1698 | case reflection.macro |
|---|
| | 1699 | when :belongs_to |
|---|
| | 1700 | conditions = "t0.#{self.primary_key} IN (?)" |
|---|
| | 1701 | conditions << " AND (#{sanitize_sql options[:conditions]})" if options[:conditions] |
|---|
| | 1702 | associated_objects = reflection.klass.find :all, :conditions => [conditions, ids], |
|---|
| | 1703 | :joins => "INNER JOIN #{self.table_name} AS t0 ON #{table_name}.#{primary_key} = t0.#{primary_key_name}", |
|---|
| | 1704 | :select => "#{options[:select] || table_name+'.*'}, t0.#{self.primary_key} as _parent_object_id", |
|---|
| | 1705 | :order => options[:order] |
|---|
| | 1706 | associated_objects.each do |associated_object| |
|---|
| | 1707 | preload_single_object( id_to_object_map, reflection_name, associated_object, '_parent_object_id') |
|---|
| | 1708 | end |
|---|
| | 1709 | when :has_one |
|---|
| | 1710 | top_objects.each {|object| object.send("set_#{reflection.name}_target", nil)} |
|---|
| | 1711 | conditions = "#{table_name}.#{foreign_key} IN (?)" |
|---|
| | 1712 | conditions << " AND (#{sanitize_sql options[:conditions]})" if options[:conditions] |
|---|
| | 1713 | associated_objects = reflection.klass.find :all, :conditions => [conditions, ids], |
|---|
| | 1714 | :select => (options[:select] || "#{table_name}.*"), |
|---|
| | 1715 | :order => options[:order] |
|---|
| | 1716 | associated_objects.each do |associated_object| |
|---|
| | 1717 | preload_single_object( id_to_object_map, reflection_name, associated_object, foreign_key) |
|---|
| | 1718 | end |
|---|
| | 1719 | |
|---|
| | 1720 | when :has_many |
|---|
| | 1721 | top_objects.each {|object| object.send(reflection.name).loaded} |
|---|
| | 1722 | |
|---|
| | 1723 | if options[:through] |
|---|
| | 1724 | through_reflection = reflections[options[:through]] |
|---|
| | 1725 | through_primary_key = through_reflection.primary_key_name |
|---|
| | 1726 | top_objects.first.class.preload_one_association top_objects, options[:through] |
|---|
| | 1727 | through_objects = top_objects.compact.map {|object| object.send options[:through]}.flatten |
|---|
| | 1728 | |
|---|
| | 1729 | unless through_objects.empty? |
|---|
| | 1730 | source = reflection.source_reflection.name |
|---|
| | 1731 | through_objects.first.class.preload_one_association through_objects, source |
|---|
| | 1732 | |
|---|
| | 1733 | through_objects.compact.each do |through_object| |
|---|
| | 1734 | association_proxy = id_to_object_map[through_object[through_primary_key].to_i].send(reflection_name) |
|---|
| | 1735 | association_proxy.loaded |
|---|
| | 1736 | associated_object = through_object.send(source) |
|---|
| | 1737 | if associated_object.is_a? Array |
|---|
| | 1738 | association_proxy.target.push(*associated_object) |
|---|
| | 1739 | else |
|---|
| | 1740 | association_proxy.target << associated_object |
|---|
| | 1741 | end |
|---|
| | 1742 | end |
|---|
| | 1743 | end |
|---|
| | 1744 | |
|---|
| | 1745 | else |
|---|
| | 1746 | conditions = "#{table_name}.#{foreign_key} IN (?)" |
|---|
| | 1747 | conditions << " AND (#{sanitize_sql options[:conditions]})" if options[:conditions] |
|---|
| | 1748 | associated_objects = reflection.klass.find :all, :conditions => [conditions, ids], |
|---|
| | 1749 | :select => (options[:select] || "#{table_name}.*"), |
|---|
| | 1750 | :order => options[:order] |
|---|
| | 1751 | associated_objects.each do |associated_object| |
|---|
| | 1752 | preload_collection_object( id_to_object_map, reflection_name, associated_object, foreign_key) |
|---|
| | 1753 | end |
|---|
| | 1754 | end |
|---|
| | 1755 | when :has_and_belongs_to_many |
|---|
| | 1756 | top_objects.each {|object| object.send(reflection.name).loaded} |
|---|
| | 1757 | conditions = "t0.#{reflection.primary_key_name} IN (?)" |
|---|
| | 1758 | conditions << " AND (#{options[:conditions]})" if options[:conditions] |
|---|
| | 1759 | associated_objects = reflection.klass.find :all, :conditions => [conditions, ids], |
|---|
| | 1760 | :joins => "INNER JOIN #{options[:join_table]} as t0 ON #{reflection.klass.table_name}.#{reflection.klass.primary_key} = t0.#{reflection.association_foreign_key}", |
|---|
| | 1761 | :select => "#{options[:select] || table_name+'.*'}, t0.#{reflection.primary_key_name} as _parent_object_id", |
|---|
| | 1762 | :order => options[:order] |
|---|
| | 1763 | associated_objects.each do |associated_object| |
|---|
| | 1764 | preload_collection_object( id_to_object_map, reflection_name, associated_object, '_parent_object_id') |
|---|
| | 1765 | end |
|---|
| | 1766 | else |
|---|
| | 1767 | raise "Unsupported association type #{reflection.name}!" |
|---|
| | 1768 | end |
|---|
| | 1769 | |
|---|
| | 1770 | end |
|---|
| | 1771 | |
|---|