Prevent paths in mails (ActionMailer)

It happens once in a while, a path gets into a mail, but with this patch it should happen nevermore.

Looks for paths in non-production and raises if it finds one.


unless Rails.env.production?
  class ActionMailer::Base
    def render_message_with_path_protection(method_name, body)
      body = render_message_without_path_protection(method_name, body)
      if body =~ %r{((href|src)=['"]/.*)}
        raise "Use absolute path in mail urls! #{$1}"
      end
      body
    end

    alias_method_chain :render_message, :path_protection
  end
end

Hash#first for ruby 1.8.6

Just got some failing specs from our 1.8.6 test runner, when using OrderedHash#first, so we fix that…

# add {}.first if its not there (1.8.6)
unless {}.respond_to?(:first)
  class Hash
    def first
      return if keys.empty?
      [keys.first, self[keys.first]]
    end
  end
end

Remove a line from known hosts with single command

No more going into the file and deleting the entry manually.
To remove line 123 from ~/.ssh/known_hosts:

Usage

rmknownhost 123

Code
Put this it into a file called rmknownhost inside a folder that is in your PATH and chmod +x the file.

#! /usr/bin/env ruby
line = ARGV[0] || raise("gimme line to remove")
hosts = File.expand_path("~/.ssh/known_hosts")
content = File.readlines(hosts)
removed = content.delete_at line.to_i - 1
puts "Removed:\n#{removed}"
File.open(hosts, 'w'){|f| f.write content * ""}

MySql: 4 ways to lower the impact of TEXT columns

Starting point

Normally there is a table with some small stuff like id/type/xxx_id(~50B) and a text column(default 768B + x) that is not needed all the time, because most users enter less than 255 chars or most queries only need the smaller columns.

  • text bloats table size
  • text makes queries slow
  • text bloats mysql query cache
  • text is always loaded into buffer pool (consumes ram)

Alternative Row format

With row ROW_FORMAT=​DYNAMIC those default 768B+x can be reduced to a mere default 20B+x, but requires innodb_file​_format=Barracuda.

1 to 1 Relationship

Keep all small columns on the first model and pull in the text from another model e.g. using translated_attributes.
Generates some overhead in the model but is reasonably fast.

Varchar column as cache + 1 to 1 Relationship

Only fetches the text/adds the relationship when needed. Useful when only a few texts are larger then 255 chars and the content is often needed. e.g. on original model:

def text_truncated(to=255)
  text = if to > 255 and text_cache.size == 255
    1_to_1_relationship.text
  else
    text_cache
  end
  text.truncate(to)
end

(this needs truncate on string)
And e.g. in the UI the text could always show truncated to 255 chars and only on click it is really loaded from the db.

Using covering index

Make an index that covers all the normal columns except the text, and FORCE INDEX on the queries.

Performance

Source:
A lot more details on the 1-to-1-relation ship / covering index can be found here