<commit_before>class ActiveRecord::Base
  class << self

    # make validate_find_options accept :piggy
    VALID_FIND_OPTIONS << :piggy

    alias_method :old_construct_finder_sql, :construct_finder_sql

    # redefine construct_finder_sql to support piggy back option
    def construct_finder_sql(options) #:nodoc:
      add_piggy_back!(options)
      old_construct_finder_sql(options)
    end

    alias_method :old_set_readonly_option!, :set_readonly_option!

    # records with piggy backed attributes are always read only.
    def set_readonly_option!(options) #:nodoc:
      if options[:piggy]
        options[:readonly] = true
      else
        old_set_readonly_option!(options)
      end
    end

    # declare piggy back for current AR class. Calls look like
    #
    #   piggy_back :user_name_and_login, :from => :user, :attributes => [:name, :login], :prefix => "user"
    #
    # or (deprecated)
    #
    #    piggy_back :user_name_and_login, :user, :name, :login
    #
    def piggy_back(piggy_back_name, *args)
      prefix = nil
      if args.first.is_a? Hash
        hash = args.first
        attributes = hash[:attributes]
        reflection_name = hash[:from]
        prefix = hash[:prefix]
      else
        reflection_name = args.first
        attributes = args[1..-1]
      end
      reflection = reflections[reflection_name]
      prefix ||= reflection.name
      unless [:belongs_to, :has_one, :has_many].include? reflection.macro
        raise "can't piggy back #{reflection.macro} on class #{self}"
      end

      if attributes.empty?
        columns = reflection.klass.content_columns
        attributes = [:*]
      else
        columns = attributes.map{|name| reflection.klass.columns_hash[name.to_s]}
      end
      columns.each{|column| define_piggy_back_read_method(column, prefix)}

      add_piggy_back_sql_data!(reflection_name, prefix, attributes, select="", joins="", conditions="")
      piggy_back_info[piggy_back_name] = [select, joins, conditions]
    end

    # replace piggy option by adding to :select, :joins and :conditions options
    def add_piggy_back!(options)
      piggy = options.delete(:piggy) or return
      select = (options[:select] ||= "#{table_name}.*")
      joins = (options[:joins] ||= '')
      if conditions = (options[:conditions] ||= '')
        conditions = conditions[0] if conditions.is_a? Array
      end

      piggy = [piggy] if piggy.is_a? Symbol
      piggy_info_hash = piggy_back_info()
      for piggy_name in piggy do
        p_info = piggy_info_hash[piggy_name]
        select << p_info[0]
        joins << p_info[1]
        conditions << " AND " unless conditions.empty? || p_info[2].empty?
        conditions << p_info[2]
      end
      options.delete(:conditions) if conditions.empty?
    end

    protected
    def piggy_back_info
      @piggy_back_info ||= descends_from_active_record? ? {} : superclass.piggy_back_info
    end

    # define reader method(s) for piggy backed association attribute
    # +prefix+ is prefixed to the attribute name
    def define_piggy_back_read_method(column, prefix)
      attr = column.name
      attr_key = "#{prefix}_#{attr}"
      return if instance_methods.include?(attr_key)

      cast_code = column.type_cast_code('v')
      access_code = if cast_code
                      "(v=@attributes['#{attr_key}']) && #{cast_code}"
                    else
                      "@attributes['#{attr_key}']"
                    end

      self.class_eval <<-"end_method"
        def #{attr_key}
          if @attributes.has_key? '#{attr_key}'
            #{access_code}
          else
            #{prefix}.#{attr}
          end
        end
      end_method
    end

    # add select, join and conditions form the given association
    def add_piggy_back_sql_data!(reflection_name, prefix, attributes, select, joins, conditions)
      ktn = table_name
      kpkey = primary_key
      reflection = reflections[reflection_name]
      atn = reflection.table_name
      attributes.each do |attr|<commit_msg>fixed problem with accessing piggybacked attributes when piggyback wasn't added to find<commit_after>class ActiveRecord::Base
  class << self

    # make validate_find_options accept :piggy
    VALID_FIND_OPTIONS << :piggy

    alias_method :old_construct_finder_sql, :construct_finder_sql

    # redefine construct_finder_sql to support piggy back option
    def construct_finder_sql(options) #:nodoc:
      add_piggy_back!(options)
      old_construct_finder_sql(options)
    end

    alias_method :old_set_readonly_option!, :set_readonly_option!

    # records with piggy backed attributes are always read only.
    def set_readonly_option!(options) #:nodoc:
      if options[:piggy]
        options[:readonly] = true
      else
        old_set_readonly_option!(options)
      end
    end

    # declare piggy back for current AR class. Calls look like
    #
    #   piggy_back :user_name_and_login, :from => :user, :attributes => [:name, :login], :prefix => "user"
    #
    # or (deprecated)
    #
    #    piggy_back :user_name_and_login, :user, :name, :login
    #
    def piggy_back(piggy_back_name, *args)
      prefix = nil
      if args.first.is_a? Hash
        hash = args.first
        attributes = hash[:attributes]
        reflection_name = hash[:from]
        prefix = hash[:prefix]
      else
        reflection_name = args.first
        attributes = args[1..-1]
      end
      reflection = reflections[reflection_name]
      prefix ||= reflection.name
      unless [:belongs_to, :has_one, :has_many].include? reflection.macro
        raise "can't piggy back #{reflection.macro} on class #{self}"
      end

      if attributes.empty?
        columns = reflection.klass.content_columns
        attributes = [:*]
      else
        columns = attributes.map{|name| reflection.klass.columns_hash[name.to_s]}
      end
      columns.each{|column| define_piggy_back_read_method(reflection.name, column, prefix)}

      add_piggy_back_sql_data!(reflection_name, prefix, attributes, select="", joins="", conditions="")
      piggy_back_info[piggy_back_name] = [select, joins, conditions]
    end

    # replace piggy option by adding to :select, :joins and :conditions options
    def add_piggy_back!(options)
      piggy = options.delete(:piggy) or return
      select = (options[:select] ||= "#{table_name}.*")
      joins = (options[:joins] ||= '')
      if conditions = (options[:conditions] ||= '')
        conditions = conditions[0] if conditions.is_a? Array
      end

      piggy = [piggy] if piggy.is_a? Symbol
      piggy_info_hash = piggy_back_info()
      for piggy_name in piggy do
        p_info = piggy_info_hash[piggy_name]
        select << p_info[0]
        joins << p_info[1]
        conditions << " AND " unless conditions.empty? || p_info[2].empty?
        conditions << p_info[2]
      end
      options.delete(:conditions) if conditions.empty?
    end

    protected
    def piggy_back_info
      @piggy_back_info ||= descends_from_active_record? ? {} : superclass.piggy_back_info
    end

    # define reader method(s) for piggy backed association attribute
    # +prefix+ is prefixed to the attribute name
    def define_piggy_back_read_method(reflection_name, column, prefix)
      attr = column.name
      attr_key = "#{prefix}_#{attr}"
      return if instance_methods.include?(attr_key)

      cast_code = column.type_cast_code('v')
      access_code = if cast_code
                      "(v=@attributes['#{attr_key}']) && #{cast_code}"
                    else
                      "@attributes['#{attr_key}']"
                    end

      self.class_eval <<-"end_method"
        def #{attr_key}
          if @attributes.has_key? '#{attr_key}'
            #{access_code}
          else
            #{reflection_name}.#{attr}
          end
        end
      end_method
    end

    # add select, join and conditions form the given association
    def add_piggy_back_sql_data!(reflection_name, prefix, attributes, select, joins, conditions)
      ktn = table_name
      kpkey = primary_key
      reflection = reflections[reflection_name]
      atn = reflection.table_name
      attributes.each do |attr|
{'fraction_non_alphanumeric': 0.1010644806068763, 'fraction_numerical': 0.0017129572984216322, 'mean_word_length': 2.7273141814865483, 'pattern_counts': {'":': 0, '<': 31, '<?xml version=': 0, '>': 9, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 1, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '461959', 'n_tokens_mistral': 2539, 'n_tokens_neox': 2500, 'n_words': 578}