Workshops am OCDW#3

Mein Kollege Franz macht alle paar Monate in seinem Haus, nahe Eisenstadt und eine knappe Stunde von Wien entfernt, Workshops zu Computerthemen die unter dem Label OCWD laufen. Beim dritten dieses Jahr durfte ich einen über die Programmiersprache Ruby und das Web-Framework Ruby on Rails halten was mir sehr viel Spass gemacht hat. Neben Franz und mir waren noch drei Lernwillige zu Gast von denen bisher nur einer am Rande was mit Webentwicklung zu hat.

Hier die Weblinks zu meinen zwei Slideshows wobei die zu Ruby on Rails dann in den praktischen Teil überfloss wo wir dann diverse Dinge ausprobiert haben.

I18n for the lazy

Why the heck didn’t I read this earlier in the Rails 2.3 docs for translate?

Second, it’ll scope the key by the current partial if the key starts with a period. So if you call translate(”.foo”) from the people/index.html.erb template, you’ll actually be calling I18n.translate(“people.index.foo”). This makes it less repetitive to translate many keys within the same partials and gives you a simple framework for scoping them consistently. If you don’t prepend the key with a period, nothing is converted.

Hire Austrians

This month Dr. Nic suggested Australians for your open job positions but I totally recommend Austrians. And here are my reasons for:

  • Austrians are more laid back than Australians. Actually they are so laid back that they are a few positions after Australia in your encyclopedia.
  • Austria is on the right, the top side of your globe (or Pizza). That means less travel costs if you like to spend your winter holidays in Norway.
  • Austria has no boring deserts like Australia but a great variety of desserts.
  • Austria is a safe place for everyone with kangaroos-phobia. And without a coastline you don’t have to fear sharks that kill hundreds of australian rails developers every year.
  • There are no dumb jokes about Austrians. They are in fact all true, sad stories.
  • Austrians are three-lingual. They talk Austrian, German (in theory) and English. And an Austrian talking English sounds much more funny than a Italian talking English while you still understand the Austrian. German is also in the same family of languages like English or the superior Norwegian.
  • Austria has a long and outstanding nautical history. They once owned an actual mediteranian city. Nowadays they retreated from the costly shipping business to concentrate on the rails-fu.
  • Austria has Sound of Music, Mozart and Falco. A lot better than Tamara Jaber, Joe Dolce or Jacko. Science says that rails developers write better rspec tests if they listen to Austrian music.
  • The Terminator is Austrian. And he’ll find you if you hire an Australian. Gov. Schwarzenegger’s latest action against the economic slowdown is sending californian php devs to austria to train them in ruby on rails.
  • Austrians are modest. They are so modest that they let the honor of starting two world wars to the german brothers in arms.
  • Austrian is a neutral country like Switzerland but with a higher density of open source ruby on rails developers.
  • For every Austrian you can get ten germans for free. Actually in Vienna there are 25% Austrians, 25% former jugoslavia and 50% German. Germans are well known for delivering 95% of code quality as Austrian developers but are 90% cheaper.
  • Austria has real alps and not only Australian Alps.
  • Vienna Rails developers are very urbane. Last time we went to a Australian pub and drank Belgian beer all night.
  • And: Austria is not an isolated island somewhere south.

Disclaimer: I’m German but was raised in a small valley surrounded by Austria and moved to Vienna last year which I’ll never regret.

route of destruction

It’s a common thing that you have a nice javascript-driven link in your rails app to delete an object. Of course you could use a proper button_to but for some reason the boss wants a link. But the usual problem is that with a link_to as rails does it, you will rely completely on Javascript, not nice for old or crappy mobile browsers. The only problem that rails gives you is a missing routes for accessing the destroy action of a controller with a GET request. But, viola, here’s the plugin to solve this: route of destruction. For more see the README.

Oh, and don’t use the plugin.

reading log files

I once worked in a company where the default environment.rb deactivated the log file, and I guess it was just because the were bored by long lines of output they didn’t want to read. The sweet advantages of having a DB admin who checks your db queries before they go live.

general facts and hints

First of all: The less lines per request the better. If you see lines that basically repeat, maybe only some id being different, then you have a problem and should think about eager loading, counter caches and other optimizations. Partial caching for sidebar elements might also be a possibility.

A few example log lines

In the example posted at railsforum.com there are four database queries, one on topics, three on posts (of which one is most likely a find_by_sql or count_by_sql ?). We only have to look at the Load lines, the Cache lines are totally ok unless they come in dozens or hunderts. It takes ActiveRecord some time to generate a final sql query, so try to cache common objects e.g. in an instance variable (See railscast #1) and reduce the Cache lines.

These following two lines are almost the same, time to check all related find and remove the differences so ActiveRecord can cache one of them.
1
2
Post Load (0.000185)   SELECT * FROM `posts` WHERE (topic_id = 3338) ORDER BY posts.id DESC LIMIT 1
Post Load (0.000132)   SELECT * FROM `posts` WHERE (`posts`.topic_id = 3338) ORDER BY posts.id DESC LIMIT
Do you know about counter caches? They are awesome four of three kids say. If you are in the index view and print out each topic with the number of posts then a counter cache will save you a lot of queries like this one:
1
2

SQL (0.000180)   SELECT count(*) AS count_all FROM `posts` WHERE (`posts`.topic_id = 3338)

more examples??? Please send them in.

Further logfile analysis

There are a few tools but I use only two: The RailsLogVisualizer to see which actions are called often in production mode. And I look at what the longest taking requests are. grep and sort nr are your friend, the logfile is your enemy ;) But at the end, the trick is just understanding the log, sorry about, no way around.

Thanks to a poster on railsforum.com for the idea to this blogpost.

adva_cms first release

It’s been quite a while since I blogged about adva_cms here and in November I even joined the dev team. Just yesterday we finally released the first version for the public and the next one coming soon with more features and fixes.

As I wrote in July and December adva_cms has grown from three applications using the Engines plugin. And while I worked on the event calendar that principle turned out to work quite well. As did for the brand-new engines newsletter and photo album. So, check it out and let us know if you find any bugs :)

rails is merging into merb

well, you coulda put it the other way around but as I didn’t try out merb so far I’m expecting to try rails 3 soon :)

OpenIdAuthentication in detail

I’m currently working on my own little project to fill photolog.at with something interesting and for this I decided to use OpenID only. Dr. Nic is a big fan of OpenID and of course I hearted his advice of allowing one account with many identities

The first OpenID plugin I tried was OpenIdAuthentication which would also support regular loging and I can say: it’s just perfect for me. The reason why I decided to allow OpenID login only is that the application will closely integrate into flickr, which is via Yahoo, one of the many OpenID providers. This way I save the obviously unnecessary authentication system, and a bunch of fields on the User model.

How OpenID works

The idea is very simple, you come to my website, type in your OpenID url, my website will forward you to your OpenID provider and there you might have to login. The OpenID provider then sends you back to my website and if nothing went wrong my website will know a few basic details about you, create an account if not existing yet and you are logged in. It’s very easy and quick, no need to type in data that you already stored at your provider.

In my webapplication most of those steps are automatically done by the OpenIdAuthentication plugin, but if you are sophisticated then you might want to change a few things from the example in the README. For instance, it doesn’t tell you anything about creating a new user, or – Dr. Nic’s favourite – how to assign multiple identities to one user. I’ve added all of those functions to my version of the SessionsController. But first a few lines from the models.

Models

The User model is quite simple, only login, name and email. All three will be gathered from the OpenID provider but you might want to add a edit form.

To comply with the mulitiple identities requirement I’ve added an Identity model which contains the identity_url (this quite replaces password and login in a normal user model) and user_id. A user has_many :identites and each Identity object belongs_to :user (just for the case you still have to look this up…).

The OpenIdAuthentication Plugin adds two models, OpenIdAuthentication::Association and OpenIdAuthentication::Nounce but we don’t touch these.

The SessionsController

Best is to follow OpenIdAuthentication’s README and then replace the SessionsController. Please read me comments and let me know what you think about it.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
class SessionsController < ApplicationController
  # sadly necessary
  skip_before_filter :verify_authenticity_token, :only => :create
  def create
    if using_open_id?
      # first difference: we explicitly pass the parameter. Much cleaner anyways than hiding it in the plugin...
      open_id_authentication(params[:openid_identifier] || params[:openid_url])
    end
  end

  protected
    def open_id_authentication(identity_url)
      # also possible for :required and :optional are %w( dob gender postcode country language timezone )
      # have a look here: http://openid.net/specs/openid-simple-registration-extension-1_0.html
      authenticate_with_open_id(identity_url,
          :required => [ :nickname, :email ],
          :optional => :fullname) do |result, identity_url, registration|
        if result.successful?
          # successful request, time to check wether the identity already exists
          identity = Identity.find_or_create_by_identity_url(identity_url)
          if identity.user.nil?
            # identity doesn't exist, but maybe the user? We use email as a unique key for this.
            if user = User.find_by_email(registration["email"])
              logger.debug("using user '%s'" % user)
              # assign identity to an existing user
              identity.user = user
              identity.save
            else
              logger.debug("creating new user '%s'" % registration["nickname"])
              # create a new user for the identity.
              identity.user = User.create!(:login => registration["nickname"],
                  :name => registration["fullname"], :email => registration["email"])
              identity.save
            end
          end
          # log the user in
          @current_user = identity.user
          successful_login
        else
          # oops. 
          failed_login result.message
        end
      end
    end
  
  private
    def successful_login
      session[:user_id] = @current_user.id
      redirect_to(root_url)
    end
  
    def failed_login(message)
      flash[:error] = message
      redirect_to(new_session_url)
    end
end

rails rumble 2008

so, it’s just one and a half hour to till this years rails rumble starts. it’s GMT this year, not PST like last year. sucks a bit as I’m already too tired. But this year I have a proper team, collegues from Lomo and I brought in a good idea for a projects. It’s about intertextuality and for the first time I hope to use it for song lyrics that have a lot of reference to all kinds of other songs or pop culture. a project with future :)

adva_cms

A few days ago I stumbled over Sven’s current project adva_cms which is a cms, mixed from mephisto, beast and signalwiki. The basis is mephisto, with all the pro and cons (aka page caching), everything else is included as plugins with Engine.

I hope to use it for a small community site this month and will post updates here on the experiences with adva_cms.

everything in plastic*

Last month I bought plasticpilots.com from Alex (from plasticshore.com), trashed the expression engine it was running on and wrote a completely new software called plasticairships. The new software is running on plasticpilots for a week now, a few of bugs have been fixed since and improvements in the design been made.

I’m not sure if anyone else will ever find good use for it. Alex and I did a redux version this week, for a workshop he does next month. The redux looks totally different of course, very minimalistic, and it has a few features from feedme (which will get some loving soon).

Btw, plasticairships is running on rails 2.1, so it’s totally covered with named_scopes, the new eager loading and other stuff.

single table inheritance in rails 2.1

With the new “rails 2.1” there was a small but for me important change in the STI that made my life easier. Thanks to divoxx for his enhancement. It didn’t show up in the docs yet but I’ll give you an example where.

The documentation’s example consists of the models Company, Firm and Client, very simple. My real life example (it will be on the new plasticpilots website) consists of a model Comment that I use as an association for Post and Site. So Post and Site have many comments. To save duplication I use STI of course and to keep the directories clean I have Site::Comment << Comment and Post::Comment << Comment (and maybe more in the far future of 2009). Old rails versions did a demodulize the class names so I would have Comment in my type column and a lot of confusion. With rails 2.1 it’s the full class name in the type column and I can kick all the work-arounds I had previously.

Btw, this behaviour is the new default, so I guess a few people will be pissed off, but can simply set: ActiveRecord::Base.store_full_sti_class = false

rails 2.1, goldberg but no postgres

Sure it’s a strange combination but mysql is most people’s favourite and goldberg is my very personal favourite.

Anyways, today I was upgrading to rails 2.1.0 and guess what, it didn’t work anymore cause some pg was being required which I don’t have. The problem has basically two causes. First the rails devs added a few lines to the postgresql connection adapter to enforce loading the pg or postgresql gem. Second, goldberg was a bit sloppy with its model monkeypatching. The fix is very simple, just a few changes to lib/goldberg/model.rb basically adding the check that goldberg is using in it’s migration extensions anyways.

You can find my patch over at goldberg’s rubyforge bugtracker

Update: A few more issues came up, so you might just want to git clone git://github.com/TomK32/goldberg.git my github repository into vendor/generators and use it like normal.

recent activities

I’ve been doing a lot of open source in the last two months and you might want to check out the results so far. And besides all that there’s the githorde of course.

FeedMe!

FeedMe! is a RSS planet that was started by Daniel Lindsley and I improved it to match my needs for salzburg-weblogs.net. It’s still incomplete and I will put a few more days of work into.

exabuch

exabuch is a german billing web-app and took over this one as well. I have quite big plans with it, also on a commercial level

plastipilots

My newest investment is this very old design website plasticpilots that I’m about to buy from a guy living nearby (yeah, very big internet). It’s getting a completely new software as replacement for expression engine and the new software will be open source as well: plasticairships. I think it will be very easy to customize for any kind of showcases or portfolio.

jaxdoc: Ruby on Rails docs on AJAX

Rails API with jaxdoc I became big fan of the jaxdoc generator for rdoc in the last months. It’s amazing to find out that you can extend rdoc to generate the docs (and I really love having docs on my local machine) the way you want it. Jaxdoc provides you with ajaxfied documentations which make searching in the docs much faster. Not to forget that you the source of the methods, just like normal rdoc. There are a few download packages at railsbrain.com and one for ruby core at rubybrain.com. But there’s no howto for creating your own docs, so I hope this example to generate for Rails 2.0.1 is complete enough for everyone. If not, please drop me a note. The exclusions could be defined a bit better I guess. And of course you can include other gems if you want a fat documenation.

1
2
3
4
sudo gem install jaxdoc
VERSION='2.2.2'
cd /opt/local/lib/ruby/gems/1.8/gems/
rdoc -S --op ~/docs/rails-$VERSION --fmt ajax --exclude .*generator.* --exclude .*test.* --include actionmailer-$VERSION activerecord-$VERSION actionpack-$VERSION activesupport-$VERSION activeresource-$VERSION rails-$VERSION