0
votes

So here is example

class Foos
 has_many :bars
 belongs_to :cities
end

class Bar
 belongs_to :foo
end

So, if i have Foo instance named "Foo1" that belong to city numbered 1 and have another Foo instance named "Foo1" that also belongs to city no 1 how I can glue it up if they both have DIFFERENTS Bars to one Foo instance that will be include all that Bars?

Thx. Best reards

2
Delete one foo and add its bar to the other foo. Is that what you are looking for?aromero

2 Answers

0
votes
foo1, foo2 = Foo.where(:name => "Foo1", :city_id => some_id).limit(2)
foo1.bars << foo2.bars
foo2.bars = []
foo2.delete
0
votes

Founded Active Record merge lib that helps

        module Merge

      # True if self is safe to merge with +object+, ie they are more or less equal.
      # Default implementation compares all attributes except id and metadata.
      # Can be overridden in specific models that have a neater way of comparison.
      def merge_equal?(object)
        object.instance_of?(self.class) and merge_attributes == object.merge_attributes
      end

      MERGE_INDIFFERENT_ATTRIBUTES = %w(id created_at updated_at).freeze
      MERGE_EXCLUDE_ASSOCIATIONS = [].freeze

      # Attribute hash used for comparison.
      def merge_attributes
        merge_attribute_names.inject({}) do |attrs, name|
          attrs[name] = self[name]
          attrs
        end
      end

      # Names of the attributes that should be merged.
      def merge_attribute_names
        attribute_names - MERGE_INDIFFERENT_ATTRIBUTES
      end

      # Names of associations excluded from the merge. 
      # Override if the model has multiple scoped associations,
      # that can all be retrieved by a single has_many association.
      def merge_exclude_associations
        MERGE_EXCLUDE_ASSOCIATIONS
      end

      # Merge this object with the given +objects+. 
      # This object will serve as the master,
      # blank attributes will be taken from the given objects, in order.
      # All associations to +objects+ will be assigned to +self+.
      def merge!(*objects)
        transaction do
          merge_attributes!(*objects)
          merge_association_reflections.each do |r|
            local = send(r.name)
            objects.each do |object|
              if r.macro == :has_one
                other = object.send(r.name)
                if local and other
                  local.merge!(other)
                elsif other
                  send("#{r.name}=", other)
                end
              else
                other = object.send(r.name) - local
                # May be better to compare without the primary key attribute instead of setting it.
                other.each {|o| o[r.foreign_key] = self.id}
                other.reject! {|o| local.any? {|l| merge_if_equal(l,o) }}
                local << other
              end
            end
          end
          objects.each {|o| o.reload and o.destroy unless o.new_record?}
        end
      end

      def merge_attributes!(*objects)
        blank_attributes = merge_attribute_names.select {|att| self[att].blank?}
        until blank_attributes.empty? or objects.empty?
          object = objects.shift
          blank_attributes.reject! do |att|
            if val = object[att] and not val.blank?
              self[att] = val
            end
          end
        end
        save!
      end

      private

      def merge_association_reflections
        self.class.reflect_on_all_associations.select do |r| 
          [:has_many, :has_one, :has_and_belongs_to_many].include?(r.macro) and 
          not r.options[:through] and 
          not merge_exclude_associations.include?(r.name.to_sym)
        end
      end

      def merge_if_equal(master, object)
        if master.merge_equal?(object)
          master.merge!(object) ; true
        end
      end

    end

    ActiveRecord::Base.class_eval { include Merge }

    # Compatibility with ActiveRecord 2.x
    class ActiveRecord::Reflection::AssociationReflection
      alias :foreign_key :primary_key_name unless method_defined? :foreign_key
    end