What causes the extreme slowness when changing from rails 3.2.12 to 3.2.13 What causes the extreme slowness when changing from rails 3.2.12 to 3.2.13 ruby ruby

What causes the extreme slowness when changing from rails 3.2.12 to 3.2.13


We had the same issues with Discourse. I extracted the relevant security fixes into a monkey patch you can apply to a Rails 3.2 application:

module HTML  class WhiteListSanitizer      # Sanitizes a block of css code. Used by #sanitize when it comes across a style attribute    def sanitize_css(style)      # disallow urls      style = style.to_s.gsub(/url\s*\(\s*[^\s)]+?\s*\)\s*/, ' ')      # gauntlet      if style !~ /\A([:,;#%.\sa-zA-Z0-9!]|\w-\w|\'[\s\w]+\'|\"[\s\w]+\"|\([\d,\s]+\))*\z/ ||          style !~ /\A(\s*[-\w]+\s*:\s*[^:;]*(;|$)\s*)*\z/        return ''      end      clean = []      style.scan(/([-\w]+)\s*:\s*([^:;]*)/) do |prop,val|        if allowed_css_properties.include?(prop.downcase)          clean <<  prop + ': ' + val + ';'        elsif shorthand_css_properties.include?(prop.split('-')[0].downcase)          unless val.split().any? do |keyword|            !allowed_css_keywords.include?(keyword) &&              keyword !~ /\A(#[0-9a-f]+|rgb\(\d+%?,\d*%?,?\d*%?\)?|\d{0,2}\.?\d{0,2}(cm|em|ex|in|mm|pc|pt|px|%|,|\))?)\z/          end            clean << prop + ': ' + val + ';'          end        end      end      clean.join(' ')    end  endendmodule HTML  class WhiteListSanitizer    self.protocol_separator = /:|(&#0*58)|(&#x70)|(&#x0*3a)|(%|&#37;)3A/i    def contains_bad_protocols?(attr_name, value)      uri_attributes.include?(attr_name) &&      (value =~ /(^[^\/:]*):|(&#0*58)|(&#x70)|(&#x0*3a)|(%|&#37;)3A/i && !allowed_protocols.include?(value.split(protocol_separator).first.downcase.strip))    end  endendmodule ActiveRecord  class Relation    def where_values_hash      equalities = with_default_scope.where_values.grep(Arel::Nodes::Equality).find_all { |node|        node.left.relation.name == table_name      }      Hash[equalities.map { |where| [where.left.name, where.right] }].with_indifferent_access    end  endendmodule ActiveRecord  class PredicateBuilder # :nodoc:    def self.build_from_hash(engine, attributes, default_table, allow_table_name = true)      predicates = attributes.map do |column, value|        table = default_table        if allow_table_name && value.is_a?(Hash)          table = Arel::Table.new(column, engine)          if value.empty?            '1 = 2'          else            build_from_hash(engine, value, table, false)          end        else          column = column.to_s          if allow_table_name && column.include?('.')            table_name, column = column.split('.', 2)            table = Arel::Table.new(table_name, engine)          end          attribute = table[column]          case value          when ActiveRecord::Relation            value = value.select(value.klass.arel_table[value.klass.primary_key]) if value.select_values.empty?            attribute.in(value.arel.ast)          when Array, ActiveRecord::Associations::CollectionProxy            values = value.to_a.map {|x| x.is_a?(ActiveRecord::Base) ? x.id : x}            ranges, values = values.partition {|v| v.is_a?(Range) || v.is_a?(Arel::Relation)}            array_predicates = ranges.map {|range| attribute.in(range)}            if values.include?(nil)              values = values.compact              if values.empty?                array_predicates << attribute.eq(nil)              else                array_predicates << attribute.in(values.compact).or(attribute.eq(nil))              end            else              array_predicates << attribute.in(values)            end            array_predicates.inject {|composite, predicate| composite.or(predicate)}          when Range, Arel::Relation            attribute.in(value)          when ActiveRecord::Base            attribute.eq(value.id)          when Class            # FIXME: I think we need to deprecate this behavior            attribute.eq(value.name)          when Integer, ActiveSupport::Duration            # Arel treats integers as literals, but they should be quoted when compared with strings            column = engine.connection.schema_cache.columns_hash[table.name][attribute.name.to_s]            attribute.eq(Arel::Nodes::SqlLiteral.new(engine.connection.quote(value, column)))          else            attribute.eq(value)          end        end      end      predicates.flatten    end  endend

With the security patches applied and Rails 3.2.13 reverted the performance returns to normal. We also wereexperiencing UTF-8 errors when precompiling our assets and this is no longer happening. It seems there is a bunch of non-security related stuff in the 3.2.13 patch that is breaking stuff :(


@fredwu fixed this in a pull request: https://github.com/rails/rails/pull/9820

To use this fix right away (and don't have to wait on a new Rails release) you can monkey patch the AssetsPaths class in your own application by using the following code:

module Sprockets  module Helpers    module RailsHelper      class AssetPaths < ::ActionView::AssetPaths        private        def rewrite_extension(source, dir, ext)          source_ext = File.extname(source)[1..-1]          if !ext || ext == source_ext            source          elsif source_ext.blank?            "#{source}.#{ext}"          elsif File.exists?(source) || exact_match_present?(source)            source          else            "#{source}.#{ext}"          end        end      end    end  endend