Blog
what did i learn today
News rails-assets ruby ssl gem rails
[rubygems] handling SSL errors on Windows when installing gems

When you encounter SSL errors when installing gems on Windows, the easiest workaround is to change your sources from https://... to http://.... But ... I am an avid user/fan of rails-assets.org and today I suddenly started getting the error on their domain.

So at first I feared that rails-assets had stopped as foreseen (in this ticket), but the site was still reachable, and actually they switched (imho just two days ago) to a new maintainer, which is awesome: the future of rails-assets is safe for now.

But there is no rose without a thorn and now rails-assets enforces TLS (which is actually a good thing), so it is always SSL and gem cannot ignore SSL anymore. Doh! So I was stuck on windows.

I tried to make gem command ignore ssl errors regardless, by creating c:\ProgramData\gemrc with the following content:

---
:ssl_verify_mode: 0

and that partly worked: I was now able to fetch the index, but now I received the SSL error on the first gem retrieved from rails-assets, so I was still not in the clear. I had to make sure the SSL verification actually worked!

Fortunately, after some googling this proved easier then expected! The root cause is that ruby on windows (or openssl) has no default root certificate. So I found a good description how to fix that on windows.

I used the boring/easy/manual approach, in short:

  • download the cacert.pem file from http://curl.haxx.se/ca/cacert.pem. I saved this to my ruby folder (e.g. c:\ruby21).
  • add an environment variable SSL_CERT_FILE, so ruby can pick it up. E.g. in your command prompt type set SSL_CERT_FILE=C:\ruby21\cacert.pem. To make this a permanent setting, add this to your environment variables.
More ...
News ruby gis oracle ruby on rails
[oracle] avoiding SLOW sdo_aggr_union

There is this recurring problem we have in GIS: getting road-segments and wanting to show complete roads. The naive approach would we to do something like the following:

insert into street_geoms
select ro.rd_ro_ident, ro.rd_ro_name, ro.com_code, ssdo_aggr_union(sdoaggrtype(rd.ro_geometry, 0.005)) as geom
from rd_road ro, rd_ro_sec ros
where ros.rd_ro_ident = ro.rd_ro_ident
group by ro.rd_ro_ident, ro.rd_ro_name, ro.com_code;

For good measure: we have 45.000+ roads, with a total of 230.000+ road segments. So when that query starts running and starts taking a long time, I started googling. Apparently there are two faster alternatives: SDO_AGGR_CONCAT_LINES and SDO_AGGR_SET_UNION. While the first was really quick, completed in minutes, the result was completely wrong (complete segments were missing). The second might be quicker, but it was really hard to get an idea about any progress, and if it would fail, everything should be lost (rolled back).

So I decided to write a little script, and issue a sql statement for each single road, allowing me to track progress and added restartibility. For each road I issued a statement like:

insert into street_geoms
select ro.rd_ro_ident, ro.rd_ro_name, ro.com_code, sdo_aggr_set_union(CAST(COLLECT(ros.rd_ros_geometry) AS mdsys.SDO_Geometry_Array),0.005) as geom
from rd_road ro, rd_ro_sec ros
where ros.rd_ro_ident = ro.rd_ro_ident
  and ro.rd_ro_ident = 1895101 
group by ro.rd_ro_ident, ro.rd_ro_name, ro.com_code;

I added some ruby code around it, to make sure it tracked the progress and calculated the remaining time, just to have an idea. The first "large" road it stumbled upon literally took hours. It only had to join 39 segments. A simple query learned I had 150+ roads with more segments, and a maximum of 125 segments in the database. I could not just simply ignore them :) So this was not going to work either.

Why would this be so hard? I just wanted to throw all linestrings together into one geometry. How could I do that? Querying the geometries was really easy, so what if I joined the geometries outside of oracle? And wouldn't that be hard? But there is a simple solution: convert the strings to WKT, and join all LINESTRING in a MULTILINESTRING. This would just be simple string manipulation. I can do that ;)

I had some hiccups with this approach: handling the long strings proved a bit akward (use CLOB instead) and I had to regularly call GC.start to make sure the open cursors were released. And I had to make sure not to build a string literal which was too long (ORA-06550).

But in the end I was able to join the road-sections for the 45.000 + roads in approx 1.5h, which is not blindingly fast, but faster than 1 single SDO_AGGR_SET_UNION operation :) :)

For reference you can see the full code:

class StreetGeom < ActiveRecord::Base
  self.primary_key = 'rd_ro_ident'
end

def format_time (t)
  t = t.to_i
  sec = t % 60
  min = (t / 60) % 60
  hour = t / 3600
  sprintf("% 3d:%02d:%02d", hour, min, sec)
end

def eta(count)
  if count == 0
    "ETA: --:--:--"
  else
    elapsed = Time.now - @start_time
    # eta = elapsed * @total / count - elapsed;
    eta = (elapsed / count) * (@total - count)

    sprintf("ETA: %s", format_time(eta))
  end
end

all_roads = Road.count
geoms_to_calculate = all_roads - StreetGeom.count
@total = geoms_to_calculate

puts "Joining geometries for #{all_roads} roads [still #{geoms_to_calculate} to do]"

cntr = 1
@start_time = Time.now

done = 0

Road.order(:rd_ro_ident).each do |road|
  street_count = StreetGeom.where(rd_ro_ident: road.rd_ro_ident).count
  print "\rConverting #{cntr}/#{all_roads} [#{eta(done)}] "
  if street_count == 0
    print "..."
    $stdout.flush

    ## get all geometries in WKT format
    get_geoms_sql = <<-SQL
      select sdo_cs.make_2d(ros.rd_ros_geometry).get_wkt() as wkt_geom from rd_ro_sec ros where ros.rd_ro_ident = #{road.rd_ro_ident}
    SQL

    cursor = Road.connection.execute(get_geoms_sql)

    line_strings = []

    while row = cursor.fetch
      line_string = row[0].read.to_s
      line_strings << line_string[10..-1]
    end

    insert_sql = <<-SQL
      DECLARE
        wkt_str clob;
      BEGIN
        wkt_str := 'MULTILINESTRING(#{line_strings.join(", ';\nwkt_str := wkt_str || '")})';
        insert into street_geoms(rd_ro_ident, name, com_code, geom)
        values (#{road.rd_ro_ident}, q'[#{road.rd_ro_name}]', '#{road.com_code}',
             sdo_util.from_wktgeometry(to_clob(wkt_str)) );
      END;
    SQL

    Road.connection.execute(insert_sql)
    done += 1
  else
    print "_"
  end

  cntr += 1

  # periodically cleanup GC so we release open cursors ...
  # to avoid ORA-1000 errors
  if (cntr % 50) == 0
    GC.start
  end
end

print "\n"
puts "\n\nDone!"

and I run this script in the rails environment as follows: rails runner lib\tasks\join_road_geometries.rb.

More ...
Technology ruby render_anywhere ruby on rails
Using render-anywhere gem with partials

Normally in rails, you can only render views inside of the controller. But what if you want to render a view somewhere else? For instance we wanted to generate xml-files using views. Haml can be used to describe xml just as well as plain html.

There is a gem called render_anywhere that allows just that. So how does this work, for example:

class Organisation < ActiveRecord::Base

  has_many :members

  include RenderAnywhere

  def to_xml
    render partial: "#{self.to_partial_path}", object: self, layout: 'my_xml_layout'
  end
end

We had a little problem when using partials though.

Normally if you type something like

= render @member

it will ask the partial path from the model (@member.to_partial_path), but somehow this always got prefixed with render_anywhere. The gem creates a dummy RenderingController in the RenderAnywhere namespace, so apparently it will look for the following view:

render_anywhere/members/member

In our case, I did not want to use the render_anywhere subfolder. It took me a while to figure out how to overrule this, but in essence it is pretty simple: rails uses the namespace of the rendering controller to prefix the path. Some deep googling proved that any controller has a method called _prefixes which lists all the prefixes for that class.

We can easily verify this in the rails console:

:001 > RenderAnywhere::RenderingController._prefixes
=> ["render_anywhere/rendering"]

So if we could overrule _prefixes to just return ["rendering"] ... Mmmmmm fork the code of render_anywhere? Or ...

There is another option: render_anywhere allows you to supply your own RenderingController and will use that instead if found in the context where the RenderAnywhere code is included.

So, if you write something like:

class Organisation < ActiveRecord::Base

  has_many :members

  include RenderAnywhere

  class RenderingController < RenderAnywhere::RenderingController

    def self._prefixes
      ["rendering"]
    end

  end

  def to_xml
    render partial: "#{self.to_partial_path}", object: self, layout: 'my_xml_layout'
  end
end

it will look for a view called members/member. Woot. To specify a different sub-folder you can adapt the _prefixes method as you wish :)

More ...
Technology ruby
[ruby] hate private methods? use protected instead

I started out writing something like the following:

If I could change just one thing in ruby, I would change how private works. Aaarrgghh.

For instance, I am trying to implement an equality of bounding boxes in ruby. I would presume I could write something like:

class BoundingBox

  attr_accessor :xmin, :ymin, :xmax, :ymax

  def initialize(xmin, ymin, xmax, ymax)
    @xmin = xmin
    @ymin = ymin
    @xmax = xmax
    @ymax = ymax
  end

  def ==(other)
    other.class == self.class && self.state == other.state
  end
  alias_method :eql?, :==

  private

  def state
    [@xmin, @ymin, @xmax, @ymax]
  end

end

Because I am inside the scope of the class, I am allowed to access the private methods. That is how it is supposed to be. But no, ruby says something silly like:

private methods cannot be called with an explicit receiver

So you have to resort to something ludicrous like writing

def ==(other)
    other.class == self.class && self.send(:state) == other.send(:state)
  end

This works. So I could have left it there. But wait: protected is exactly what I want. I have been using it wrong completely.

So in short:

  • use public for your public API of your class (obviously)
  • use protected for methods that are not part of your API, but other instances of the same class need to be able to reach (e.g. for equality checking, sorting, ...)
  • use private for methods that are only used inside the class, and only refer to the implicit receiver.

So if in the first example I change private to protected, it just works. I have been doing it wrong all along.

More ...
Technology ruby method_missing rails
[rails] store your settings in a model

Most of the times I use a config.yml to store application settings, that I want to be able to change quickly between environments, servers, deployments. But what with settings that need to be changed on the fly, by a user?

I create a small model, with three fields.

rails g model Setting name:string description:string value:string

I use a seed file to define the different settings. Settings are checked in code, but I can not preload them, since a user might change them. So first I added a method as_hash that loads all settings, and I can then directly use a hash, but that gets wordy quickly.

What if ... I could provide a method on the class Setting for each setting in the database? That would be really nice. This seems like a job for ... method-missing-man Special superpower: seeing places where method_missing could be used :)

class Setting < ActiveRecord::Base

  validates_presence_of :name

  def self.as_hash
    settings = {}
    Setting.all.each do |setting|
      settings[setting.name.to_sym] = setting.value
    end
    settings
  end

  # offer all settings as methods on the class
  def self.method_missing(meth, *args, &block) #:nodoc:
    @all_settings ||= Setting.as_hash
    if @all_settings.keys.include?(meth)
      @all_settings[meth]
    else
      super
    end
  end
end

For documentation, the test:

context "convenience: define methods for all settings" do
  before do
    Setting.instance_variable_set('@all_settings', nil)
    Setting.create(name: 'my_other_test_setting', value: '123ZZZ')
  end
  it "Setting.my_other_test_setting returns the correct result" do
    Setting.my_other_test_setting.should == '123ZZZ'
  end
  it "an unexisting setting behaves as a normal missing method" do
    expect {
      Setting.this_setting_does_not_exist
    }.to raise_exception(NoMethodError)
  end
end

I love ruby :) :)

More ...
Technology ruby windows ruby on rails
Run rails 2.3.18 using ruby 1.8.7 on windows server 2012

For my current job we have two 2.3.5 rails sites, of which I already succesfully upgraded one to rails 4. For the other we still need to start the migration, and we were asked to install new windows servers to run the rails servers on in the meantime (let's not digress why they choose windows, in a business environment Windows servers are still preferred, and let's be honest; they are easier to maintain and manage then *nix servers at first sight).

So whatever: I had to install the rails 2.3.5 on a new Windows 2012 server.

This proved problematic, since the new ruby 1.8.7 comes with the new rubygems, and this does not work nicely with rails 2.3.5.

So step 1: install the old ruby 1.8.7 (p302), the old gems and run the rails server. This worked.

But then I saw this one thing I really needed to improve. So I migrated the project to the latest 1.8.7 and rails 2.3.18, use bundler for gem dependencies. On my development box this worked like a charm (Macbook Pro). So then I deployed this back on the server, and then the following happened:

C:/Ruby187/lib/ruby/1.8/pathname.rb:290:in `[]': no implicit conversion from nil to integer (TypeError)
    from C:/Ruby187/lib/ruby/1.8/pathname.rb:290:in `chop_basename'
    from C:/Ruby187/lib/ruby/1.8/pathname.rb:343:in `cleanpath_aggressive'
    from C:/Ruby187/lib/ruby/1.8/pathname.rb:331:in `cleanpath'
    from C:/Ruby187/lib/ruby/gems/1.8/gems/rails-2.3.18/lib/rails/rack/log_tailer.rb:9:in `initialize'
    from C:/Ruby187/lib/ruby/gems/1.8/gems/rack-1.1.6/lib/rack/builder.rb:54:in `new'
    from C:/Ruby187/lib/ruby/gems/1.8/gems/rack-1.1.6/lib/rack/builder.rb:54:in `use'
    from C:/Ruby187/lib/ruby/gems/1.8/gems/rack-1.1.6/lib/rack/builder.rb:73:in `call'
    from C:/Ruby187/lib/ruby/gems/1.8/gems/rack-1.1.6/lib/rack/builder.rb:73:in `to_app'
    from C:/Ruby187/lib/ruby/gems/1.8/gems/rack-1.1.6/lib/rack/builder.rb:71:in `inject'
    from C:/Ruby187/lib/ruby/gems/1.8/gems/rack-1.1.6/lib/rack/builder.rb:73:in `each'
    from C:/Ruby187/lib/ruby/gems/1.8/gems/rack-1.1.6/lib/rack/builder.rb:73:in `inject'
    from C:/Ruby187/lib/ruby/gems/1.8/gems/rack-1.1.6/lib/rack/builder.rb:73:in `to_app'
    from C:/Ruby187/lib/ruby/gems/1.8/gems/rails-2.3.18/lib/commands/server.rb:95
    from script/server:3:in `require'
    from script/server:3

What was going on here? Apparently in the rails/rack/logtailer.rb is the following code:

class LogTailer
  def initialize(app, log = nil)
    @app = app

    path = Pathname.new(log || "#{::File.expand_path(Rails.root)}/log/#{Rails.env}.log").cleanpath

And the cleanpath is somehow crashing. I tried googling this, to no avail.

Of course:

  • rails 2.3.18: who uses that still?
  • ruby 1.8.7 is deprecated
  • and deploying on windows servers

So I was on my own. I tracked the error down to the cleanpath_agressive which called the chop_basename recursively to remove superfluous . and .. redirections.

I am guessing the problem is that on windows, a path starts with a drive-letter, like D:\ or C:\ which messes up the ending of the cleanpath_aggressive loop.

Instead of really diving in, the path handed down to cleanpath in my case, did not need any cleaning, and furthermore, an uncleaned path would still work.

So I added an initializer config\cleanpath_bug_fix.rb with the following code:

if RUBY_PLATFORM =~ /mingw/
  # on windows the Pathname.cleanpath crashes on windows paths, instead of fixing it thoroughly
  # just ignore it
  class Pathname
    def cleanpath_aggressive
      self
    end
  end
end

Now my rails 2.3.18, using ruby 1.8.7p374 runs on Windows Server 2012R2. Woot ;)

More ...
Technology ruby refactoring
Short and clean ruby (or an exercise in group-think)

In some part of my code I ended writing the following:

self.count_processed ||= 0 
self.count_processed += 1

where self is some ActiveRecord model, and count_processed is an attribute of that model (and stored in the database). What am i trying to achieve (if it is not blatantly obvious):

  • if count_processed is not initialised, make it zero
  • increment count_processed

Imho this code is clear and readable, but I had the feeling it could be more concise/prettier. So I asked that question on our campfire, to see if we could come up with something shorter. Very nice to be working in a team where you can just throw up questions like these and a very useful, educational discussion unfolds. In short we came up with the following solutions.

Solution 1: to_i

self.count_processed = self.count_processed.to_i + 1

Nifty! Isn't it? Use to_i because it will handle the nil correctly. But for me this looked wrong. If I would return to this code after a few weeks, months, I would wonder why I did this way, and not just wrote self.count_processed += 1. So while the code is correct, the intent of the code is not clear.

Solution 2: concise!

self.count_processed = (self.count_processed || 0) + 1 

This is very beautiful, and the intent is also very clear. If it is not initialised, use the zero, else just use the value and add 1. Awesome.

Solution 3: change the getter

An alternative solution would be to overwrite the getter, like this

def count_processed 
  self[:count_processed] ||= 0 
end

Note the notation we used: we use self[:count_processed] because this will fetch the value from the database column. If this was a normal getter, we would write @count_processed (but that does not work for an ActiveRecord model). After redefining the getter, we can just write: self.count_processed += 1 While this will work always, does it express its intent more clearly or not? Actually you no longer have to worry about the initialisation, because it is handled, and we can focus on what we really want: increment the counter. I opted for this solution.

What about you?

Which version do you prefer? Do you have any alternative suggestions?

More ...
Technology ruby debugging session rails
logging the activerecord-session-store

I had an issue where I was not sure the ActiveRecord::SessionStore was actually working (in hindsight: it worked). But to make sure, I needed to know what was stored in the session or retrieved.

All logging for the session-store is silenced, using Base.silence.

Obviously I was very interested in that logging, and did not find another to unsilence the logging but to add an initializer with the following code.

So in file config/initializers/unsilence_logging.rb write:

class ActiveRecord::Base 
  def self.silence 
    yield self 
  end 
end

This will unsilence the SessionStore logging. Your logging will look like this:

 ^[[1m^[[36mAREL (0.0ms)^[[0m ^[[1mUPDATE "sessions" SET "data" = 'BAh7DEkiFnF1aWN<<snipped to protect the inncocent>>iEi9mcC9kYXNoYm9hcmQ= ', "updated_at" = '2012-05-04 11:17:24.704491' WHERE "sessions"."id" = 33635

This at least allows us to verify that the sessions are stored and retrieved correctly. But how can we see what is stored inside the session? To be able to read or inspect what is actually stored in the session, you can use the following line:

session_data = 'BAh7DEkiFnF1aWN<<snipped to protect the inncocent>>iEi9mcC9kYXNoYm9hcmQ= ' 
Marshal.load(ActiveSupport::Base64.decode64(session_data))

And this will present your session data in a readable format.

This way I learned that a time-drift between our two servers caused a very obscure bug. I hope it can help you too.

More ...
News ruby jasmine tdd
using jasmine without rails

Assume you have, like I did, a ruby gem that contains some javascript you want to test standalone. First you need to install the jasmine-gem. You have two options:

  • either you use your gemspec to drive your bundler gemfile, so just add it to your developement dependencies
  • I am still using jeweler, so I use a normal Gemfile, which jeweler parses to populate my gemspec with. Personally I find this much easier, and my workflow is much closer to any ruby development for me, this way

If you have a rails-project, starting with jasmine is easy, and takes three easy steps:

# first add jasmine to Gemfile, and then 
bundle install 
rails g jasmine:install 
rake jasmine 

Inside your gem or simple ruby-project it is equally simple, just type

jasmine init 
rake jasmine

Now you can need to edit the jasmine.yml to make sure it is running your tests and your code, instead of the example code. In my case I had to change only one line:

src_files: - app/assets/javascripts/\*\*/\*.js 

Happy testing :) Some interesting links to help you with jasmine:

More ...
Technology ruby mongodb mongoid
[mongoid] adding timestamps to an existing mongo collection

In our Rails 3 application we use mongo to store logging of critical actions. At first we did not store a separate timestamp, since the _id (which is a BSON::ObjectId contains a timestamp as well. Our model, simplified, looked like this: [ruby] class Log include Mongoid::Document # mongo id's contain timestamps, 4 bytes = epoch def timestamp Time.at([id.to_s].pack("H8").unpack("N")[0]) end end [/ruby] This is all fine and dandy, but when we wanted to build some reporting, of course we were unable to filter and query based upon date. Mongoid has an easy way to add timestamp fields, and will add the timestamp to all the newly created documents for you. Inside your model just add: [ruby] include Mongoid::Timestamps::Created [/ruby] We only need to track the creation-time, since we are not interested in any updates. Including Mongoid::Timestamps will add and maintain both created_at and updated_at. Now all that remained was adding the created_at field to all existing data. We needed reporting, but also on the existing data. Luckily, the value of the field was known, using the timestamp hidden in the id. Secondly, building a script to add and populate the field was also not too hard. This gist was my inspiration, but unlike that script, I was able to use the higher level interface of Mongoid. [ruby] # To allow querying on time-ranges, we need to add the created_at field. # Querying on the timestamp does not seem possible, which is not completely surprising # as it is (if i understand correctly) a part of the _id field. # # As a one time operation, we iterate over all documents and add the created_at field # This script has to be run in the Rails environment, please use : # # rails runner script/convert_mongo_add_created_at.rb # COLLECTIONS = ["your-collection"] # Put a list of collection names here def convert_collection(collection) skipped_docs = 0 all_converted_docs = 0 Audit::Log.all.each do |doc| unless doc.respond_to?(:created_at) && doc.created_at.present? doc[:created_at] = doc.timestamp doc.save all_converted_docs +=1 else skipped_docs += 1 end end puts " added :created_at to #{all_converted_docs} documents [skipped: #{skipped_docs}]" puts "Converted #{collection}" end puts "Start conversion ..." @db = Mongoid.database COLLECTIONS.each do |collection| convert_collection collection end [/ruby]

More ...
News ruby mongo mongoid
[mongoid] doing a group-by on date

Doing a simple group-by query using mongo and mongoid is actually pretty straightforward. According to the documentation, mongoid does not offer any group/aggregation function itself, but mongo does. And you can directly access the mongo using the collection. So assume we have a mongo collection: [ruby] class Log include Mongoid::Document include Mongoid::Timestamps::Created field :action, :type => String end [/ruby] and now I want to count all occurrences of the different actions. [ruby] Log.collection.group(:key => "action", :initial => { :count => 0 }, :reduce => "function(doc,prev) { prev.count += +1; }") [/ruby] This will return an array of hashes as follows: [ruby] [{"action"=>"create", "count"=>1565.0}, {"action"=>"update", "count"=>2142.0}, {"action"=>"destroy", "count"=>27.0}] [/ruby] That is already very nice. But now I want to get the results of a certain action, grouped per day and month. [ruby] Log.collection.group(:keyf => "function(doc) { d = new Date(doc.created_at); return {nr_month: d.getMonth(), nr_day: d.getDate() }; }", :initial => { :visits => 0 }, :reduce => "function(doc,prev) { prev.visits += +1; }" ) [/ruby]Notice: the value of :keyf and :reduce is a string containing javascript. This is very flexible, but important: no ruby! But since it is a string, you can use string interpolation to get values in there. We should, of course, add a condition, to limit the result-set. So something like this: [ruby] Log.collection.group(:keyf => "function(doc) { d = new Date(doc.created_at); return {nr_month: d.getMonth() }; }", :initial => { :visits => 0 }, :reduce => "function(doc,prev) { prev.visits += +1; }", :cond => {:action => 'create'}) [/ruby] This will returns the logged create per month.Notice: the :cond and :initial contain regular ruby hashes. Selecting on a date-range is also pretty easy, once you know how this took me hours to find : [ruby] Log.collection.group(:keyf => "function(doc) { d = new Date(doc.created_at); return {nr_month: d.getMonth() }; }", :initial => { :visits => 0 }, :reduce => "function(doc,prev) { prev.visits += +1; }", :cond => {:created_at => {'$gte' => Time.utc(2011,04), '$lt' => Time.utc(2011,05) }) [/ruby] I still have some weird offset error with the dates, since I also get a few from the previous month, but I guess this has something to do with the time-zones. Now, Mongoid can help us to write the condition. We can do something like: [ruby] conditions = Log.where(:created_at.gte => Date.today.at_beginning_of_month, :created_at.lte => Date.today.at_end_of_month).selector Log.collection.group(:keyf => "function(doc) { d = new Date(doc.created_at); return {nr_month: d.getMonth() }; }", :initial => { :visits => 0 }, :reduce => "function(doc,prev) { prev.visits += +1; }", :cond => conditions) [/ruby] Hope this helps.

More ...
News ruby migrate to rails3 rspec2 rails3 rails
Porting an existing rails 2 site to rails 3

I have created a few rails 3 sites, but i have never before ported an existing rails2 application to rails3. I will describe the problems i encountered. First off there were some very good resources (step-by-step descriptions) to guide me through it:

ActiveSupport::Callbacks

Before we wrote: [ruby] module Workflow class Base define_callbacks :before_something, :after_something def some_method run_callbacks :before_something puts "some method" run_callbacks :after_something end end class SpecificWorkflow < Base before_something :do_something def do_something puts "something" end end [/ruby] Now, this has changed. Into the following: [ruby] module Workflow class Base define_callbacks :something def some_method run_callbacks :something do puts "some method" end end end class SpecificWorkflow < Base set_callback :something, :before, :do_something def do_something puts "something" end end [/ruby] Which is pretty nice. It has the disadvantage we can only use :before and :after callbacks anymore, but that was easily solved.

ActionController::ParamsParser

We hooked into the Rack middleware before the ActionController::ParamsParser to make sure we return Bad Request when the parsing fails. This middleware has been renamed to ActionDispatch::ParamsParser. Easy fix :)

safe_helper removed?

We prepared our Rails 2 project a long time ago, and used the rails_xss plugin. We used the safe_helper all over our helper-methods, but apparently this is not supported in Rails 3. Bummer. So, before [ruby] def some_helper "<strong>something</strong>" end safe_helper :some_helper [/ruby] After: [ruby] def some_helper "<strong>something</strong>".html_safe end [/ruby] A bit annoying to do, a bit unfortunate, because we thought we were preparing ourselves for a smoother upgrade. Not entirely so.

The routes!

Only after those steps did my rails get far enough to discover my routes. I did not change anything about the routes, just placed inside the correct block. I deleted my index.html and put back my original application.html.haml and the first view was working.

The missing to_key

The to_key was missing inside the user_session model. I described that solution already in this blogpost. So i just needed to fix that.

Replacing ActionController::RecordIdentifier.singular_class_name

We used ActionController::RecordIdentifier.singular_class_name, in rails3 this is replaced by ActionController::RecordIdentifier.dom_class.

Missing translations

A feature we used a lot was I18n.t('.filter') and this would look for operators.filter.filter because the line was inside a partial _shared/_filter.html.haml and called from the operators/index.html.haml. Now this does not work anymore, and now instead I18n looks for _shared.filter.filter. I did not find an easy way to solve this, just moved some translations. Luckily we did not override the translations of a partial based on the context where it was rendered yet. Does anybody has any tips on that?

Upgrading javascript helpers

In rails3 unobtrusive is the way to go. So, a remote_form_for like [ruby] - form_remote_tag :url => update_url do [/ruby] becomes [ruby] - form_tag :url => update_url, :remote => true do [/ruby] Which seems easy enough. It does get more complicated when the :update tag is used. For example: [ruby] - remote_form_for post, :update => {:success => "result_#{id}"} do |form| [/ruby] becomes [ruby] - remote_form_for post, :remote => true, :html => {:class => 'remote-post-form', :'data-update' => "#result_#{id}"} do |form| [/ruby] The :update is no longer supported as before, and we have to perform some glueing ourselves. So i replaced the :update by data-update. And then inside javascript (e.g. application.js) we can do the following: [javascript] jQuery(function($) { $(".remote-post-form") .bind("ajax:success", function(data, status, xhr) { var update_selector = $(this).attr('data-update'); $(update_selector).html(status); }); }); [/javascript] If you need more elaborate example, check this question on stackoverflow.

master_helper_module

This has been replaced by _helpers.

active_layout

The active_layout method, of a controller, no longer exists inside rails3. To replace it you need to use two methods:

  • action_has_layout? returns true if a layout exists.
  • To get the layout-name, i have no better solution then calling the private method _layout. This can be done, as known, by doing controller.send(:_layout).

Upgrade rspec

I had to upgrade Rspec 1 to v2. First off in the Gemfile i added the correct version. I removed the rspec.rake file. I ran [ruby] rails g rspec:install [/ruby] But still all rake spec commands were missing. The fix was simple. In the Gemfile make sure the rspec-rails is also usable from development mode: [ruby] group :development, :test do gem 'rspec-rails' end [/ruby] Now on to fixing the tests!

Fixing the tests

In the upgrade from rspec1 to rspec2 a lot of things have changed. What i encountered:

  • replace all Spec:: by RSpec::
  • controller_name 'users' no longer exists, write a surrounding describe UsersController do instead (that is also clearer imho)
  • ...

Extending Rspec::Rails::ExampleGroup::ControllerExampleGroup

Before, in rspec1, ControllerExampleGroup was a class and you could add code to it. So for instance, we had a file like this in our support folder: [ruby] module RSpec module Rails module Example class ControllerExampleGroup let(:the_account ) { Factory(:account) } let(:the_user ) { Factory(:user)} end end end end [/ruby] A bit larger, but you get the picture: this allowed us to define a set of shared let definitions. In rspec-2 this is no longer possible this way, because ControllerExampleGroup is now a module. I handled that like this: [ruby] module Lets def self.included(base) base.let(:the_account ) { Factory(:account) } base.let(:the_user ) { Factory(:user)} end end [/ruby] and inside my spec_helper this file is automatically required (since it is stored in the support folder) and i just add [ruby] config.include(Lets) [/ruby]

Rspec: replace config.extend

I also noticed that using config.extend(ModuleName) dit not work anymore. Instead i had to write (on the same place, inside the configure block) : [ruby] Rspec.configure do |config| .. include ModuleName .. end [/ruby] and that worked for me.

More?

Do you have more hints to share? What bumps did you find and how did you overcome them?

More ...
Uncategorized ruby arrrrcamp ruby on rails
Arrrrcamp 29/10/2010

The fourth and most international of all arrrrcamp editions. Also the first paying edition. As i said in mypost about the previous edition, i have been to all editions, and it is awesome to see how it has grown. The schedule was amazing, with an amazing array of international speakers, of which for me especially Yehuda Katz i looked forward to. The biggest problem i had was that two of my collegues gave a talk at the same time, both of which i wanted to see. Choices choices choices :) Let me give a quick impression of the talks i did see:

Keynote by Carl Lerche:

To be frank, i had totally no idea who Carl was. But his talk was very nice, talking about the speed improvements Rails does, under the covers, unknown at least to me, to get your site visible as soon as possible. Also the speed improvements they will take in the next version 3.1 and 3.2 to improve this even further. In short, they look for ways to serve the HTML so that a browser can download the page and all the assets quicker. Very new to me, touched some very interesting subjects as automatic spriting, the cache manifest ... But in the end, there is one thing that Rails can't solve: latency. That is the core time it takes to reach a server and get back to the client. A mere ping. If you want to reduce latency, you either make sure your servers are really close to all clients, ... or ... you work in a different way, and let your client handle more stuff. In short: using a minimal HTML which is only downloaded once, using the cache manifest and lots of javascript: back to client side code? Hold that thought, we'll come back to that later.

Escaping the Sludgy Swamp of Slow Tests by Joseph Wilk

This is a problem we are getting into at work. We try to solve that by running our tests in parallel. Joseph explains the routes they had taken in their team.

  • First off: use a lot of EC2 instances to reduce time. They went from 4hours build time to 11minutes, cheering developers, but very angry boss :) EC2 is not cheap!
  • So then they introduced some kind of low-level caching, which will cache sequences of SQL commands and returned a cached result. This sounds very interesting as that is what you see most in tests: a lot of similar db-setup to actually test something small.
  • Thirdly a great idea was to divide your tests into different sets, and only run those that are most likely to fail. Those that always succeed you only run nightly, and the ones that sometimes fail you also seperate so you can more easily test those, check loggings, and hopefully fix them. I also remembered the suggestions to use capybara together with env.jsto be able to test your javascript pages quicker. Good tips, and i especially like the graphics (and humour) on the slides :D

Refactoring++ : Refactor Everything A.T.F.T by Alain Ravet

A talk by a collegue of mine (had to miss Elise's talk, bummmmer, but her talk is recorded so i hope to see that later). I know most of his refactoring tips, because we have paired extensively and i have learned a lot by doing that. Alain took a small piece of code from the internet, an example to solve the Towers of Hanoi: the code was small and compact and seemed to be ok. But then Alain was able to find and show a lot of improvements. That was great. Aside from the standard refactorings (from the book) Alain also stressed the scanability of the code. This is also a pet-pieve of mine. Code has to be formatted nicely and correctly. In teams it is preferred that classes follow a bit the same structure, e.g. inside rails it is easy to make agreements where to expect the filters, constructors, public methods, ... Also Alain stressed the point to know your tools and your language. Ruby is a very expressive and compact language: use that to your benefit! Know the tool you are using, whether it is Rubymine, Textmate or VIM. And practice. Do code kata's, download some code and refactor-refactor-refactor.

Making it an Anti-Pattern is Not Enough by Timothy Payton and Sebastian Roebke :

I saw these guys last time, and i was very impressed by them at that time. Probably because what they said struck a chord, and matched my own experiences. This time, i found them less persuasive. I think maybe because my expectations were too high, they re-iterated a lot they said last time (or so it felt), the title was not explained anywhere (or i missed that), and i guess they were also having troubles with the single microphone (being two speakers) that made them more uncomfortable. Still a very nice talk, and Xing seems to be a very nice place to work.

Lightning Talks

  • Friendly attributes: apparently, in mysql, adding a columns is a very expensive operation. So this guy looked for alternatives, and came up with friendly attributes. This could be a very nice tool for someone if you are forced to use MySql (e.g. by your hosting provider). Otherwise i would suggest to use Postgresql.
  • A postgres textsearch without any extra server: this seemed very interesting and promising, but also very non-existant at the moment. He was in the process of turning it into a gem. Wait and see.
  • Yehuda's 10 minutes about concurrency in MRI: inspired by Elise's talk about concurrency, Yehuda dug a bit deeper into MRI threads and possible advantages. Unfortunately none of the big servers (passenger or unicorn) make any use of that. Only thin --threaded would profit from that. This really was a lightning talk! A lot of information in a short span, very interesting!
  • @Defv's recipe for a good rails rumble: after his third Rails Rumble Jan gave us the recipe: 1) a knock-out idea but simple enough so any visitor/judge would get it, simple enough to implement in 48 hours, and 2) good design. With the next emphasis being: simple! simple! simple! Reminds me a bit of what 37signals always says.
  • Wicegrid: i have used this grid in a few big projects i did, and really liked it. Nice that Yuri showed it, hope some more people start using it.
  • Restart of BRUG: this was nice news too. I have seen that amsterdam.rb and rotterdam.rb exist, and was wondering why we don't have such a "working" thing in Belgium. But the guys from Openminds offered to revive it, they will support the first three sessions, and then other sponsors would need take over (volunteers from the public immediately jumped in). Meetings would take place in different cities, so i am very curious how this would work out. That would be very nice ;)

Closing Keynote by Yehuda Katz:

Yehuda recently switched jobs, and together with Carl Lerche they are now both actively working on a framework called Sproutcore. In short, Sproutcore (or SC) is a javascript MVC framework. So, MVC on the client. In the talk from Carl we learned that the big problem is latency, so one way to improve or remove that, is instead of developing your web-application in the Rails way, is to use a more client-centric way. Yehuda then showed us a few moving parts of Sproutcore, which he intends to extract in seperate libraries so you could use them more easily. They also stressed that Carl and Yehuda are aiming for a very tight integration with Rails in the future. Altough it is not entirely sure what or how that will be be. You would be using Rails to just serve json-data. Rails still has its very strong points to be used in the backend for something like that. His talk left me a bit baffled, to be honest. The big advantage for me of the Rails framework is that there is one language, one platform to develop in, to cover both server and client side. That is a big advantage. It is also a big advantage compared to using AIR or Silverlight on the client, because you remove the duplication of all the models on both sides (in Rails you only need them on server side). That said, i do believe the future lies in heavier clients, like gmail and twitter shows us. The bindings that Yehuda showed, reminded my very much of the bindings offered in WPF and Silverlight. Possible advantages of Silverlight: with Ironruby you have the option to run ruby in the client as well. But, as the video-section of arrrrcamp themselves show: Silverlight it is not ready for all platforms. It does not work on my ubuntu 10.10. I am thinking now would be a good time to revive the idea of a ruby vm on javascript. In no specific order:

  • Hotruby was very promising but seems dead. With the speed improvements in current javascript vm's it would seem awesome to get some ruby on javascript too.
  • rubyjs: compiles ruby to javascript to be run in the browser
  • Js.class could be an alternative approach: use the classes and paradigms of ruby in javascript.
  • red: writes like ruby and runs like javascript
  • coffeescript: not quite ruby, that compiles into javascript I will dig into these alternatives in a later post :) The biggest advantage of sproutcore over extjs, AIR or Silverlight is that sproutcore is truly open source. Exciting times ahead :)

To conclude

As usual I really enjoyed arrrrcamp, the organisation was great, i enjoyed seeing and talking to a lot like-minded people, and the talks were really though-provoking this year. Setting sail to the next edition!

More ...
Uncategorized ruby gemsets rvm rails3 ruby on rails
rails 2 and 3 simultaneously: gemsets to the rescue

I am developing several rails projects. Some are still rails 2.3.9, and some are rails3. But using those at the same time, on the same machine can cause some trouble. I use bundles for all my projects, so the gem dependencies are managed. But still, somehow, when running my tests, i get into trouble. If i run spec, it complains that it is deprecated. Rubymine doesn't support running tests in my rails 2 project. The solution? Use gemsets! Gemsets are a feature from rvm, the Ruby Version Manager. But with gemsets rvm does more than just manage your ruby version! A gemset is a set of gems, which you can switch at will. So i am using a gemset per project. Creating a gemset is easy: [ruby] rvm gemset create some_name [/ruby] Using a gemset is equally simple: [ruby] rvm gemset use some_name [/ruby] Showing which gemset is in use: [ruby] rvm gemset name [/ruby] Showing the list of possible gemsets [ruby] rvm gemset list [/ruby] By default, you are using an unnamed gemset, which contains all the gems for your ruby-version. Per project you can create a new gemset. Per gemset you have to re-install your gems, but luckily, using bundler, that is as simple as doing bundle install. Now comes the good part:

  • Rubymine supports using gemsets, so you can select your gemset to work with, and each time your project is opened, it uses the correct gemset and the correct corresponding scripts (e.g. spec)
  • If you place a .rvmrc file in your project-folder containing rvm default@projecta, every time you cd into that folder it will select the default ruby and the projecta gemset. Awesome!
More ...
Uncategorized ruby rspec
awesome rspec hints and tips

Read "Pure Rspec", a great slideshow by Jon "Lark" Larkowski. It contains some really cool rspec tips and hints, how to write your tests more readable and compact.

More ...
Uncategorized ruby jeweler gem
creating a new gem

I found a few articles that describe easier ways to create a gem. From the entire list of available tools, i want to highlight two: jeweler and (Mr.) bones. Mr. bones seems a very configurable route to take: it allows you to define your own skeletons (application templates) or use those of others, e.g. bort. On the other hand it also seems to do more than i need. Jeweler seems to be very specific in what i does for you, allowing to create a gem very easy and manage your gem locally. Also it is very configurable, so you can immediately create rspec and cucumber folders, fill the wanted rake tasks. It is awesome, and makes starting really easy. So i executed the following command: [ruby] D:\work-git\ruby>jeweler --rspec --cucumber --reek --roodi --create-repo word_automator create .gitignore create Rakefile create LICENSE create README.rdoc create .document create lib create lib/word_automator.rb create spec create spec/spec_helper.rb create spec/word_automator_spec.rb create spec/spec.opts create features create features/word_automator.feature create features/support create features/support/env.rb create features/step_definitions create features/step_definitions/word_automator_steps.rb Jeweler has prepared your gem in word_automator Jeweler has pushed your repo to http://github.com/nathanvda/word_automator [/ruby] which as you can tell created a folder, rspec and cucumber place-holders, prepared my gem and pushed my repository to github! Wow :) Now fill the gem with code :)

More ...
Uncategorized ruby rvm ubuntu
installing ubuntu for ruby development

I have made the complete switch. My home development machine is no longer Windows XP, no longer dual booting Ubuntu but a full-fledged Ubuntu. After installing the dual-boot, and my machine at work this is the third time to install an ubuntu machine, and getting everything ready for ruby development. I just want to archive my steps here, so a next time could be even faster :) Installing Ubuntu 10.04 itself is a piece of cake. My first step after the installation is to enable numlock on login screen (i always use numbers in my passwords) [bash] sudo apt-get install numlockx [/bash] Then run sudo gedit /etc/gdm/Init/Default and find the line [bash] exit 0 [/bash] and add the following code above that line [bash] if [-x /usr/bin/numlockx]; then /usr/bin/numlockx on fi [/bash] Secondly I install rvm for multiple rubies. We first need to install any ruby for that. Take the default ubuntu version (1.8). [bash] sudo apt-get install ruby rubygems [/bash] This does not install the latest version, but we don't need that yet. Rvm will solve this for us. Install rvm itself: [bash] sudo apt-get install curl bison build-essential zlib1g-dev libssl-dev libreadline5-dev libxml2-dev git-core bash < <( curl http://rvm.beginrescueend.com/releases/rvm-install-head ) [/bash] Then make sure rvm will work always [bash] sudo gedit .bashrc [/bash] and replace [-z $SP1] && return with [bash] if [[! -z $SP1]]; then .. original content that was below the && return line [[-s $HOME/.rvm/scripts/rvm]] && source $HOME/.rvm/scripts/rvm fi #EOF [/bash] Then rvm should be available. Install the needed rubies. We use ree at work, i like to work with 1.9.1/2 and i want to check out rubinius. So install your rubies through rvm [bash] rvm install ree rvm install 1.9.2 rvm install rbx [/bash] Installing ruby 1.9.1 was a bit harder, when i just tried to run the standard rvm install 1.9.1, i received the following error: [bash] .rvm/src/ruby-1.9.1-p429/lib/optparse.rb:1310: [BUG] Segmentation fault [/bash] and that was caused because i use a newer gcc version, which can't handle the -O3 optimisation. It took me a while to find how you can fix it, but in the end (as always) it was easy. Just type [bash] export optflags="-O0"; rvm install 1.9.1 [/bash] To end, set your default ruby version [bash] rvm ree --default [/bash] now all your new sessions you should be using your selected default version. After installing your favourite editor (Netbeans or rubymine), your favourite database (postgreSQL, sqlite, mysql ), and your list of gems you are ready to roll some ruby! I must say as an previously avid Windows user for ages, i am very impressed by Ubuntu. This is a free operating system, and while i was aware that everything just works better being linux (meaning processes and filesystem); but not only that: it even looks better and is very user-friendly. It is way more customisable looks-wise then silly windows. In Windows 7 for instance you have to use this very large font, and in Ubuntu i can set the size to anything i want (small!!!). Awesome :) And i guess it will amaze me for the next few days and weeks whilst finding out other new stuff. [UPDATE] For me it is confusing that the minimize, maximize and close buttons are on the left-side, i think it is done to be more apple-like. But the fix to move the buttons to the right is luckily very easy once you know it :)

More ...
Uncategorized ruby strings
use %q to create strings

In my gemspec created by jeweler I saw string creating using %Q. What? [ruby] gem.summary = %Q{TODO: one-line summary of your gem} gem.description = %Q{TODO: longer description of your gem} [/ruby] I found a pagedescribing ruby string creation, and it seems %Q is the equivalent of double quote delimited strings and %q is the equivalent of single quotes. While i was pondering what the advantage could be of writing it that way, i opened up irb and look and behold: [ruby] irb(main):001:0> test = %Q{ggg gggg ggg} => "ggg gggg ggg" irb(main):002:0> test2= "ff ff ff" => "ff ff ff" irb(main):003:0> test= %Q{%q{ffff ffff ffff}} => "%q{ffff ffff ffff}" irb(main):004:0> test= %Q{this is a "test", curious whether 'it' works :)} => "this is a "test", curious whether 'it' works :)" irb(main):005:0> test= %Q{this is a "test", i am curious whether #{test2} 'it' works :)} => "this is a "test", i am curious whether ff ff ff 'it' works :)" irb(main):006:0> [/ruby] Cool! It allows you to write your strings without having to think about escaping the quotes.

More ...
Uncategorized ruby mingw32 plugin git
script/plugin install from git fails

I am using ruby 1.8.7 on windows (mingw32), and all of a sudden i cannot run [ruby] c:\> ruby script/plugin install git://github.com/daphonz/dirty_associations.git Plugin not found: ["git://github.com/daphonz/dirty_associations.git"] [/ruby] the suggested variations also don't work, e.g. [ruby] ruby script/plugin install http://github.com/daphonz/dirty_associations.git ruby script/plugin install http://github.com/daphonz/dirty_associations.git/ [/ruby] all give the same error. But, apparently, it has something to do with the mingw32 platform. In C:\Ruby\lib\ruby\gems\1.8\gems\activesupport-2.3.5\lib\active_support\core_ext\kernel\reporting.rb the following line can be found in function silence_stream: [ruby] stream.reopen(RUBY_PLATFORM =~ /mswin/ ? 'NUL:' : '/dev/null') [/ruby] Replace that with the correct way to check for the windows platform, and then all should be fine again :) [ruby] stream.reopen(RUBY_PLATFORM =~ /mswin|mingw/ ? 'NUL:' : '/dev/null') [/ruby] I still needed to replace git:// with http:// but now it works :) Now investigate how this can be pushed to Rails codebase?

More ...
News ruby arrrrcamp ruby on rails
Arrrrcamp

Went to arrrrcamp last friday (Arrrr as in _R_uby, _R_ails, _R_adiant and, of course, _R_hum!). It was the third edition of this unique ruby-on-rails event, and the third time i visited it ;) So i am a regular :) The first year i was just starting ruby and my then-collegue and me learned a lot. The second time i took some new collegues along hoping to get them infected with the ruby virus. This year i went alone (so you can guess how well the infection spread :), but one advantage of being alone in a croud is that it is way easier to mingle. There's even a picture to prove it :) I saw some very interesting talks:

  • Something Something Mongo: I alrready had read about Mongo, and was interested. This speech interested me more than Radiant. Just another NoSQL database. Some things were not entirely clear, like how you can query stuff if all things are in the same "database". But it seems like something i should investigate more. I think there are a lot of possible applications, and the presenter showed a very good example, where the database is entirely configurable by the end-user, which is dead-easy in Mongo and MongoMapper, because there is no schema! Ha! :) Opens up possibilities indeed ;)
  • jQuery on Rails: at the same time there was a talk about the new things in Rails3. So this was a hard choice. But i am already using jQuery, in combination with Prototype, and was hoping to get some tips to do it better. The talk was very quick, but also very informative. The presenter did a very cool job, where he showed the same site in Prototype (using helpers) and jQuery (using unobtrusive javascript). Very nice. I still write most of my javascript inline, and am gradually switching over. I am still struggling with one problem. In most of unobtrusive javascript examples, i always see that all code is placed in the application.js. But that is not good enough for me. I want a js file per erb-file. I found a blogpost by Yehuda Katz, where he does something even smarter: only include the js-files which include the selectors from the current page. But unfortunately it is so old, the source is nowhere to be found anymore. when i asked the presenter, after the session, he pointed me to this article about Jzip, but on second look it is not quite what i am looking for.
  • Railties: what, why & how?: a very interesting talk, but i must admit, since Rails 3 territory is still very unknown to me (and a lot has changed apparently) a lot of it was unclear. In short: the old way to create rails plugins is replaced by Railties. Plugins and engines are supported, dependencies are more explicit. Something i still need to look into, to convert the plugin we use at work.
  • Something something Rack: actually i did not want to see this one, but rather the 12 hours to rate a rails website by Elise Huard, but because @Atog was late those two talks had switched. She confided, however, that i would get a second change at RailsConf :) The something-something-rack talk was very basic, but also enlightning. Rack provides a minimal interface between webservers supporting Ruby and Ruby frameworks. Rack applications can be stacked. Since Rails is a Rack application, it is now very easy to put Rack-apps in front of Rails, for instance to redirect to different sites or pages if the visitor uses a mobile device (Rack::MobileDetect), add google analytics to your pages automatically (Rack::GoogleAnalytics), or to block unallowed access (Rack::Warden). Very interesting. Also allows for a clean seperation of concerns. One last Rack middleware I really want to mention: Rack::ChromeFrame! This middleware will make sure the Google Chrome frame is automatically enabled. Cool :)
  • Learning to smile at your code: a talk by two german guys, who both work at Xing, about refactoring and to learn to actually enjoy it. Xing is a very big website, coded for the largest part in Rails. They have 22 developers working in Rails. Sebastian and Tim, the presenters, had to add features to the job-postings page/code and encountered a lot of problems doing so. I really liked this talk because i found it very recognisable and also because it was a talk focusing on the programming of an application as a whole. They used a lot of humour to convey their message, with success. Really-really compressed their message was: 1) seeing a lot of old, incomprehensible code can be demotivating; 2) breathe and relax; 3) starting to refactor it anyway, despite the obvious unwillingness at first, will make you smile because you can create something beautiful. They gave some examples which i guess barely even scratched the surface of the complexity they had to deal with. Nice :) After that the lightning talks came (short talks of about 10 minutes). I will highlight a few:
  • failtale: a notification framework/website by the guys from Mr. Henry. Impressive, because not only does it capture ruby/rails exceptions, but also ActionScript (flash) and Javascript soon. I am going to try that out! :) I am currently using Exception Notifier myself, curious how it compares.
  • The guys from 10-forward did three talks. First a demo of their application, which was incredibly impressive. Wow! Blew me away. A lot of javascript and ajax to make the website feel like a real application. Very powerful. Then they discussed a gem of theirs, and rspec and cucumber.
  • wallsome: Sebastian and Tim from Xing, who also did the Learning to smile talk, here presented their pet-project, using Rails 3 and jQuery: a wall to arrange your tasks from Basecamp like in Scrum or Kanban. I am looking forward to the next edition on the 29th of october! :)
More ...