aboutsummaryrefslogblamecommitdiffstats
path: root/activerecord/lib/active_record/associations/has_one_association.rb
blob: 0070606c24260b1163e9e23a7b3da979904ba2ad (plain) (tree)
1
2
3
4
5
6
7
8
9
                   
                                                  
                     
                                                       

                            
                                                     
                                                    
                                              

                                              


                                                      
                                                    
                                              

                                               

         
                                                    
                                                    
                                              

                                             

         

                                         
 
                                             
                                                          

                                                
                                                  
                         
                                                   
                         
                                                    
                                                                     
               
              
                                                  
                                                                   
             





                                     
                                   
                                                                 

           
                                 
              
 
                                                          
                                          
            
                                        

           
 

                       
                                                                    

           
                                






                                                          
           
 
                                  
                                    
           

                                        
                                                                                    


                                                                             
                                                       

                             
                                 
              
                                                                            
                                
                                        



                
 




                                                                                                        


       
module ActiveRecord
  # = Active Record Belongs To Has One Association
  module Associations
    class HasOneAssociation < AssociationProxy #:nodoc:
      include HasAssociation

      def create(attrs = {}, replace_existing = true)
        new_record(replace_existing) do |reflection|
          attrs = merge_with_conditions(attrs)
          reflection.create_association(attrs)
        end
      end

      def create!(attrs = {}, replace_existing = true)
        new_record(replace_existing) do |reflection|
          attrs = merge_with_conditions(attrs)
          reflection.create_association!(attrs)
        end
      end

      def build(attrs = {}, replace_existing = true)
        new_record(replace_existing) do |reflection|
          attrs = merge_with_conditions(attrs)
          reflection.build_association(attrs)
        end
      end

      def replace(obj, dont_save = false)
        load_target

        unless @target.nil? || @target == obj
          if @reflection.options[:dependent] && !dont_save
            case @reflection.options[:dependent]
            when :delete
              @target.delete if @target.persisted?
            when :destroy
              @target.destroy if @target.persisted?
            when :nullify
              @target[@reflection.foreign_key] = nil
              @target.save if @owner.persisted? && @target.persisted?
            end
          else
            @target[@reflection.foreign_key] = nil
            @target.save if @owner.persisted? && @target.persisted?
          end
        end

        if obj.nil?
          @target = nil
        else
          raise_on_type_mismatch(obj)
          set_owner_attributes(obj)
          @target = (AssociationProxy === obj ? obj.target : obj)
        end

        set_inverse_instance(obj)
        loaded

        unless !@owner.persisted? || obj.nil? || dont_save
          return (obj.save ? self : false)
        else
          return (obj.nil? ? nil : self)
        end
      end

      private
        def find_target
          scoped.first.tap { |record| set_inverse_instance(record) }
        end

        def construct_find_scope
          {
            :conditions => construct_conditions,
            :select     => @reflection.options[:select],
            :include    => @reflection.options[:include],
            :readonly   => @reflection.options[:readonly],
            :order      => @reflection.options[:order]
          }
        end

        def construct_create_scope
          construct_owner_attributes
        end

        def new_record(replace_existing)
          # Make sure we load the target first, if we plan on replacing the existing
          # instance. Otherwise, if the target has not previously been loaded
          # elsewhere, the instance we create will get orphaned.
          load_target if replace_existing
          record = scoped.scoping { yield @reflection }

          if replace_existing
            replace(record, true)
          else
            record[@reflection.foreign_key] = @owner.id if @owner.persisted?
            self.target = record
            set_inverse_instance(record)
          end

          record
        end

        def merge_with_conditions(attrs={})
          attrs ||= {}
          attrs.update(@reflection.options[:conditions]) if @reflection.options[:conditions].is_a?(Hash)
          attrs
        end
    end
  end
end