inicio mail me! sindicaci;ón

Use CSS to change link content on hover

Using just a data-attribute and a simple stylesheet rule it is possible to change the content of a link when hovering over it.
Use an HTML / SASS combination like the following:

<a href="target" data-hovertext="Hover Text">
  Normal Text
</a>
a[data-hovertext]:hover
  font-size: 0
  &:before
    font-size: initial
    content: attr(data-hovertext)

See this in action.

Using throw and catch to tidy up our code

Let’s say we want a simple controller action that checks, if a given code is valid.
It should return true and false and, if the code is invalid, give the reason (whether that is because it is unknown or because it has been used already). The action could look like this:

def valid
  if code = Code.find_by_value(params[:id])
    unless code.used?
      respond_with :valid => true
    else
      respond_with :valid => false, :reason => 'used'
    end 
  else
    respond_with :valid => false, :reason => 'unknown'
  end 
end 

Now this deep nesting effectively hides the underlying algorithm, a simple one in this case.
Expressing this using throw and catch straightens the code a bit:

def valid
  failure = catch :fail do
    code = Code.find_by_value(params[:id]) or throw(:fail, 'unknown')
    code.unused?                           or throw(:fail, 'used')
    nil
  end
  respond_with({:valid => !failure}.merge(failure ? {:reason => failure}: {}))
end

We are down to one respond_with line but the has merging and the throws at the beginning of the line are not particularly pretty.

Let’s introduce a little Ruby mixin for the Hash class that provides it with a compact method that its friend Array has had all along:

module HashExtensions
  def compact
    self.reject{|key, value| value.nil? }
  end
end

class Hash
  include HashExtensions
end

Now using this to clean up the response hash and moving the throw statements to the end so the steps of the algorithm are visible we have our final version of the action:

def valid
  failure = catch :fail do
    code = Code.find_by_value(params[:id]) or throw :fail, 'unknown'
    code.unused?                           or throw :fail, 'used'
    nil 
  end 
  respond_with({:valid => !failure, :reason => failure}.compact)
end 

Saving local text files to S3 using paperclip

Sometimes you need to save a locally created file to S3 instead of an uploaded file, as is the standard. Here is how:

  has_attached_file :tagged_text_file,  STORAGE_OPTIONS.merge({
    :processors   => []
  })
  def save_tagged_text_file
    file = File.open("#{RAILS_ROOT}/tmp/tagged_text_#{id}.txt", 'w+')
    file << tagged_text
    self.tagged_text_file = file
    save!
    file.close
  end

Connecting to redis via SSH tunneling

SSH tunneling is, of course, useful for a ton of services, but I happened to stumble upon it, when I wanted to connect to a remote redis server.

If you have a redis server running on [remotehost], you can easily connect
to it (given you have ssh access to it, of course) via:

ssh -L 9999:localhost:6379 [remoteuser]@[remotehost]

This will open a tunnel from the remote port 6379 (redis standard) to your local port 9999.

You can now use the redis on your local port 9999 like you would if it was running locally. Nice.

Push local branch to specific heroku app

You use two heroku apps as staging and production for your project. You added both as git remotes, e.g. “production” and “staging”.

Now you want to push your local branch “poster” to remote “staging”, use
git push staging poster:master

Note, that you can only push to “master” on herokus side. This is just git syntax, but I keep forgetting it, so here it is for future reference.

Ruby: map Array to Hash

Sometimes you may wish to map an Array to a Hash in Ruby, like say, you got the output of I18n.available_locales

locales = [:en, :de, :fr]

and want to transform that into a Hash to fill a select element, like so:

{:en => 'EN', :de => 'DE', :fr => 'FR'}

How do you do that in the most concise way?
First, there is always inject:

locales.inject({}) {|hsh, sym| hsh[sym] = sym.to_s.upcase; hsh}

But I like the following approach way better, mainly because it emphasizes my intention more clearly (and, btw. is faster too):

Hash[locales.map{|sym| [sym, sym.to_s.upcase]}]

Remember: Hash[[:a,:b],[:c,:d]] (as well as Hash[:a,:b,:c,:d])
produces {:a => :b, :c => :d}.

Copying Files between S3 buckets

Building on this article here is a simple ruby script, that copies files between two buckets of the same S3 account, omitting files already present (by name).
This variant adds a list of path prefixes, so you can selectively copy only certain directories of your buckets.
Furthermore it copies the original buckets ACLs for each key.

require 'rubygems'
require 'right_aws'

aws_access_key_id     = 'YOUR AMAZON ACCESS KEY'
aws_secret_access_key = 'YOUR AMAZON SECRET ACCESS KEY'
source_bucket         = 'SOURCE BUCKET NAME'
target_bucket         = 'TARGET BUCKET NAME'
prefixes              = [PATH_PREFIX1, PATH_PREFIX2, ...]

s3 = RightAws::S3Interface.new(aws_access_key_id, aws_secret_access_key)

copied_keys = Array.new
(prefixes || ['']).each do |prefix|
  s3.incrementally_list_bucket(target_bucket, {:prefix => prefix}) do |key_set|
    copied_keys << key_set[:contents].map{|k| k[:key]}.flatten
  end
end
copied_keys.flatten!

(prefixes || ['']).each do |prefix|
  s3.incrementally_list_bucket(source_bucket, {:prefix => prefix}) do |key_set|
    key_set[:contents].each do |key|
      key = key[:key]
      if copied_keys.include?(key)
        puts "#{target_bucket} #{key} already exists. Skipping..."
      else

        puts "Copying #{source_bucket} #{key}, setting acl"

        retries=0
        begin
          s3.copy(source_bucket, key, target_bucket)
          acl = s3.get_acl(source_bucket, key)
          s3.put_acl(target_bucket, key, acl[:object])
        rescue Exception => e
          puts "cannot copy key, #{e.inspect}\nretrying #{retries} out of 10 times..."
          retries += 1
          retry if retries <= 10
        end
      end
    end
  end
end

MomoFlow

Coverflow has become a de facto visualization standard for the presentation of collections of images, be it covers or portraits.
There are a number of implementations for usage on web pages (e.g. this one) but the usable ones require Adobes Flash and thus won’t run on the iPhone.

When looking for HTML5 canvas based implementations I found this promising implementation based on the YUI library.
Though workig, it has three major drawbacks: It is rather overengineered and difficult to tweak, it uses YUI (whereas I prefer the more lightweight jQuery) and it performs poorly with image sizes bigger than thumbnails.

After trying to change the code for a while I decided to do a reimplementation in jQuery. The result can be seen on the MomoFlow demo page. Here are two screenshots:

CoverFlow using canvas and jQuery

CoverFlow using canvas and jQuery

Quicklook mode

Quicklook mode

The used 3D transformation is superbly described on the YUI blog .

My implementation caches the rendered canvases per rendering angle. Further speed increments are made possible by adjusting the mesh width used for the slicing transformation depending on the achieved framerate.

The result performs beautifully in recent Safari, Chrome and Opera, decently on Firefox. It also works flawlessly on the iPhone. Keyboard control is coming soon.

I do still need help on IE, maybe the image composition is too demanding for ExplorerCanvas
The code is available on github: http://github.com/momolog/momoflow.
Comments and improvements are very much welcome!

MySQL BEFORE INSERT trigger as check constraint

Since MySQL does neither have real check constraints nor a way to raise an exception in a stored procedure, we found it not instantly obvious, how we could *reject* a certain row on insert, based on a certain condition.

A nice way we found was to set the value in question to NULL, based on the condition and let the NOT NULL constraint do its work.

ALTER TABLE sessions MODIFY session_id varchar(255) NOT NULL;
DROP TRIGGER IF EXISTS check_sessionid;
DELIMITER $$
CREATE TRIGGER check_sessionid BEFORE INSERT ON sessions
FOR EACH ROW BEGIN
  IF NOT NEW.session_id REGEXP '^[[:xdigit:]]{32}$' THEN
    SET NEW.session_id = NULL;
  END IF;
END;
$$
DELIMITER ;

The trigger will let any 32 character string with only HEX characters for the column session_id pass and rejects the rest.

> INSERT INTO sessions (session_id) VALUES ('ffffffffffffffffffffffffffffffff');
Query OK, 1 row affected (0.01 sec)
> INSERT INTO sessions (session_id) VALUES ('fffffffffffffffffffffffffffffffg');
ERROR 1048 (23000): Column 'session_id' cannot be null

Happy triggering.

Vor kurzem dazugelernt:

Suche nach Wort unter dem Cursor in vim: #.

jssh ist eine JavaScript Shell, die den Firefox per Port 9997 fernsteuerbar macht.
Download z.B. hier.

y erzeugt einen YAML dump auf der Rails console, mehr dazu hier.

=3D ist ein escaptes “=” in quoted_printable.

sudo /usr/libexec/locate.updatedb aktualisiert unter MacOSX sofort die locate Datenbank.

rake db:migrate:redo führt unter rails die letzte Migration rückwärts und sofort wieder vorwärts aus, so dass sich die Vorwärts-Action korrigieren läßt

ack -Q bringt ack dazu, literal, also ohne RegExp zu suchen.

Next entries »