Sinatra Streaming + nginx Proxy

Fairly easy. The important line here is:
proxy_buffering off;

I think this one works at least for most Rack based applications. The application itself runs on thin ( besides that, I only know Unicorn and Rainbow(s?) that have Streaming Support. Webrick won’t do that (yet))

My vhost config.


upstream stream {
  server 127.0.0.1:4800;
  server 127.0.0.1:4801;
  server 127.0.0.1:4802;
  server 127.0.0.1:4803;
  server 127.0.0.1:4804;
}

server {
  listen   80;
  server_name  stream.domain.com;
  client_max_body_size 5M;
  root /path/to/project/current/public;
  error_log	/path/to/project/shared/nginx/stream.error.log;
  access_log  off;
  location / {
    proxy_set_header  X-Real-IP  $remote_addr;
    proxy_set_header  X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header Host $http_host;
    proxy_buffering off;
    proxy_redirect off;

    if (-f $request_filename) {
      break;
    }

    if (!-f $request_filename) {
      proxy_pass http://stream;
      break;
    }

  }
}
Veröffentlicht in Ohne Kategorie, Ruby, Server / Deployment | Getagged: , , , | Kommentieren

Map Scale: Distance in Meters to Pixels depending on Zoom level

Took me a while to wrap my head around this: I tried to draw a circle around a specific coordinate (latitude & longitude) on a (google maps like) map.
My first attempt was:
EARTH_CIRCUMFERENCE / 2 ^ ZOOM_LEVEL / TILE_SIZE

which resulted in a circle whose radius was off by about 20% in my tests. ( South Germany; 500m radius ).

of course I had to factor in that this assumes we’re on the equator. To account the current latitude (for the circles’ center) I modified the formula:

EARTH_CIRCUMFERENCE * cos(Latitude * PI / 180) / 2 ^ ZOOM_LEVEL / TILE_SIZE

Veröffentlicht in Ohne Kategorie | Getagged: , | Kommentieren

memcached gem 1.3.5 on Lion 10.7.2

Maybe Xcode 4.2 and its compiler change (LLVM) is the reason I couldn’t install the darn thing. This helped:

$ export CC=gcc-4.2
$ gem install memcached
Veröffentlicht in Ohne Kategorie, Ruby | Getagged: , , , , , | Kommentieren

Ubuntu – RVM – Error?

RVM Installation seems pretty simple, worked flawlessly almost every time I used it on OSX. On my new production machine I couldn’t install it.

mkdir: cannot create directory `/usr/local/rvm': Permission denied

Every Tutorial or Snippet I tried looked liked this:

bash < <(curl -s https://raw.github.com/wayneeseguin/rvm/master/binscripts/rvm-installer )

To force RVM to your $HOME - or any other folder your user has RW privileges:

$ echo 'export rvm_prefix="$HOME"' > ~/.rvmrc
$ echo 'export rvm_path="$HOME/.rvm"' >> ~/.rvmrc

Then rerun the above bash/curl line.

Veröffentlicht in Ohne Kategorie, Ruby | Getagged: , , | Kommentieren

Rake Tasks for non-Rails application

put in your Rakefile:

Load seeds:

namespace :db do
  task :seed => :environment do
    seed_file = File.join(File.dirname(__FILE__), 'db', 'seeds.rb')
    load(seed_file) if File.exist?(seed_file)
  end
end

run Migrations & Rollback

namespace :db do
  desc "Migrate the database through scripts in db/migrate."
  task :migrate => :environment do
    ActiveRecord::Migration.verbose = ENV["VERBOSE"] ? ENV["VERBOSE"] == "true" : true
    ActiveRecord::Migrator.migrate("db/migrate/", ENV["VERSION"] ? ENV["VERSION"].to_i : nil)
    Rake::Task["db:schema:dump"].invoke if ActiveRecord::Base.schema_format == :ruby
  end
 
  desc 'Rolls the schema back to the previous version. Specify the number of steps with STEP=n'
  task :rollback => :environment do
    step = ENV['STEP'] ? ENV['STEP'].to_i : 1
    ActiveRecord::Migrator.rollback('db/migrate/', step)
    Rake::Task["db:schema:dump"].invoke if ActiveRecord::Base.schema_format == :ruby
  end
end

Dump & Load schema(.rb)

namespace :db do
  namespace :schema do
    desc "Create a db/schema.rb file that can be portably used against any DB supported by AR"
    task :dump => :environment do
      require 'active_record/schema_dumper'
      File.open(ENV['SCHEMA'] || "db/schema.rb", "w") do |file|
        ActiveRecord::SchemaDumper.dump(ActiveRecord::Base.connection, file)
      end
    end
 
    desc "Load a schema.rb file into the database"
    task :load => :environment do
      file = ENV['SCHEMA'] || "db/schema.rb"
      load(file)
    end
  end
end
Veröffentlicht in Ohne Kategorie, Ruby | Getagged: , , , | Kommentieren

ActiveRecord: Add Comments to Migrations and Schemas

For my most recent project I created some kind of “auto-documentation”. I thought the most easy way was to simply use MySQLs comments. Turns out, ActiveRecords doesn’t support this comments at all. Neither in schema dumping nor in migrations. ( used also for recreating database from a schema.rb ). This ain’t bound to Rails; It works wherever you use ActiveRecord (well tested only with activerecord gem 3.1.1).

Insert comments with a migration

(found here: http://goo.gl/7JO5T)
(working with activerecord 3.1.1)

module ActiveRecord
  module ConnectionAdapters
    class ColumnDefinition
      attr_accessor :comment
 
      def to_sql_with_comment
        column_sql = to_sql_without_comment
        return column_sql if comment.nil?
        "#{column_sql} COMMENT '#{base.quote_string(comment)}'"
        end
 
      alias_method_chain :to_sql, :comment
    end
 
    class TableDefinition
      def column(name, type, options = {})
        column = self[name] || ColumnDefinition.new(@base, name, type)
        if options[:limit]
          column.limit = options[:limit]
        elsif native[type.to_sym].is_a?(Hash)
          column.limit = native[type.to_sym][:limit]
        end
        column.precision = options[:precision]
        column.scale = options[:scale]
        column.default = options[:default]
        column.null = options[:null]  
        column.comment = options[:comment]
        @columns << column unless @columns.include? column
        self
      end
    end
  end
end

Get comment info for columns collection

module ActiveRecord
  module ConnectionAdapters
    class MysqlColumn
      attr_accessor :comment
    end	
 
    class MysqlAdapter
 
      def columns(table_name, name = nil)
        sql = "SHOW FULL FIELDS FROM #{quote_table_name(table_name)}"
        columns = []
        result = execute(sql, name)
        result.each { |field| 
          c = MysqlColumn.new(field[0], field[5], field[1], field[3] == "YES") 
          c.comment = field[8] || ""
          columns << c
        }
        result.free
        columns
      end  		  
    end
  end
end

You can use that in your application wherever you need access to the comment (or any other column information)

MyModel.columns_hash.each do |a|
  puts a[1].type.to_s
  puts a[1].name.to_s
  puts a[1].comment if a[1].respond_to?("comment")
end

SchemaDumper

to add comment to schema.rb export

module ActiveRecord
  class SchemaDumper  
    def table(table, stream)
      columns = @connection.columns(table)
      begin
        tbl = StringIO.new
        if @connection.respond_to?(:pk_and_sequence_for)
          pk, _ = @connection.pk_and_sequence_for(table)
        elsif @connection.respond_to?(:primary_key)
          pk = @connection.primary_key(table)
        end
        tbl.print "  create_table #{table.inspect}"
        if columns.detect { |c| c.name == pk }
          if pk != 'id'
            tbl.print %Q(, :primary_key => "#{pk}")
          end
        else
          tbl.print ", :id => false"
        end
        tbl.print ", :force => true"
        tbl.puts " do |t|"
        column_specs = columns.map do |column|
          raise StandardError, "Unknown type '#{column.sql_type}' for column '#{column.name}'" if @types[column.type].nil?
          next if column.name == pk
          spec = {}
          spec[:name]      = column.name.inspect
          spec[:type]      = if column.type == :integer && [/^numeric/, /^decimal/].any? { |e| e.match(column.sql_type) }
                               'decimal'
                             else
                               column.type.to_s
                             end
          spec[:limit]     = column.limit.inspect if column.limit != @types[column.type][:limit] && spec[:type] != 'decimal'
          spec[:precision] = column.precision.inspect if column.precision
          spec[:scale]     = column.scale.inspect if column.scale
          spec[:null]      = 'false' unless column.null
          spec[:comment]   = column.comment.inspect
          spec[:default]   = default_string(column.default) if column.has_default?
          (spec.keys - [:name, :type]).each{ |k| spec[k].insert(0, "#{k.inspect} => ")}
          spec
        end.compact
        keys = [:name, :limit, :precision, :scale, :default, :null, :comment] & column_specs.map{ |k| k.keys }.flatten
        lengths = keys.map{ |key| column_specs.map{ |spec| spec[key] ? spec[key].length + 2 : 0 }.max }
        format_string = lengths.map{ |len| "%-#{len}s" }
        type_length = column_specs.map{ |column| column[:type].length }.max
        format_string.unshift "    t.%-#{type_length}s "
        format_string *= ''
        column_specs.each do |colspec|
          values = keys.zip(lengths).map{ |key, len| colspec.key?(key) ? colspec[key] + ", " : " " * len }
          values.unshift colspec[:type]
          tbl.print((format_string % values).gsub(/,\s*$/, ''))
          tbl.puts
        end
        tbl.puts "  end"
        tbl.puts
        indexes(table, tbl)
        tbl.rewind
        stream.print tbl.read
      rescue => e
        stream.puts "# Could not dump table #{table.inspect} because of following #{e.class}"
        stream.puts "#   #{e.message}"
        stream.puts
      end
      stream
    end    
  end
end

(copy this snippets somewhere to your app, everything gets done by monkey patching)

Veröffentlicht in Database, Ruby | Getagged: , , | Kommentieren

Global ActiveRecord Observers

Have you ever tried to get ActiveRecord Observers working in a Sinatra environment? I spent hours crawling trough the Rails sources but eventually gave up.

Plus: My goal anyway was to have some kind of global observer through all models in my application. So, easy decision – I build my one solution – as always: with “Blackjack and Hookers”.

While browsing the ActiveRecord sources I found the perfect entrance to hook in to the needed callbacks (after_create, after_update and after_destroy).

Step 1: Hook in the callbacks

module ObjectWatcher 	                   
  def self.included(base)
    base.after_create do |obj|   
      puts "Yeah - we got a create"
    end
    base.after_update do |obj|  
      puts "Yeah - we got an update"
    end
    base.after_destroy do |obj| 	
      puts "Yeah - we got a destroy"
    end
  end
end	
[...]
ActiveRecord::Base.send(:include, ObjectWatcher)

After that, the rest was pretty easy an straightforward: Create an Observer. Well: Someone has to receive above signals, and do something with them. If you only need one observer, you easily could do you stuff in the blocks. I’d like to be more flexible and for now, I have already 5 observers listening.

Step 2: Listener

this one gets called by the ObjectWatcher and dispatches to all its listeners (observers)

class ObjectListener
  class << self
    def listeners
      @listeners ||= []
    end
    def listeners=(l)
      @listeners = l
    end
    def run(obj, action)
      mn = "after_#{action}"
      self.listeners.each do |listener|
      	lo = listener.to_s.classify.constantize
        lo.send method_name, obj if lo.respond_to?(mn)
      end
    end 
  end 
end

Usage in ObjectWatcher:

[...]
  base.after_create do |obj|   
    ObjectListener.run record, :create
  end
[...]

Step 3: Create & Register Observers

class TestObserver
  def self.after_update(record)
    puts " >> updated"
  end   
  def self.after_create(record)
    puts " >> created" 
  end
  def self.after_destroy(record)
    puts " >> destroyed"
  end
end
[...]
ObjectListener.listeners << TestObserver

that’s it – happy coding.

Veröffentlicht in Ohne Kategorie, Ruby | Getagged: , , , , , | Kommentieren

Typo3 – AMenu is missing a bunch of entries

Was solved by
plugin.tt_news.amenuStart = 1.1.2000

Veröffentlicht in Ohne Kategorie | Getagged: | Kommentieren