Counter mit Ruby on Rails

Eine der ersten Anforderungen von Kunden an eine Webseite ist: Wie viele Besucher tummeln sich auf meiner Seite? Dazu baut man einen sogenannten Zugriffszähler (oder auch counter) in seine Applikation ein. In meinen Anfängen schon oft mit PHP gemacht, nie aber mit Rails. Das soll dieser Artikel ändern. Er ist aber auch eine (Gedanken-)Stütze für mich, wenn ich mal wieder drüber nachdenke, wie man einen solchen Counter schreibt oder erweitern kann.

Eigentlich ist es recht einfach, einen Counter in Rails zu erstellen. Wir erzeugen zuerst ein Model ‚visit‘, welches einen Besuch eines Nutzers darstellt.

script/generate model visit

Dann schreiben wir noch die migrations um und migrieren unsere Datenbank auf die neueste Version.

class CreateVisits < ActiveRecord::Migration
  def self.up
    create_table :visits do |t|
      t.string :ip
      t.string :referrer
      t.string :browser_agent
      t.string :page
      t.timestamps
    end
  end
 
  def self.down
    drop_table :visits
  end
end
rake db:migrate

Dann brauchen wir noch eine Methode, in der wir neue User in die DB packen. Ich habe das ganze über eine Methode in meinem PagesController (der meine Seiten verwaltet) gelöst. Diese Methode wird in einem before_filter aufgerufen.

class PagesController < ApplicationController   
before_filter :write_statistics 
 
# ... andere Logik  
 
protected   
def write_statistics     
# Suche nach Einträgen von heute mit passender IP und Browser Agent     
visit = Visit.find(:first, :conditions =>{
      :ip => request.remote_ip.to_s,
      :browser_agent => request.env['HTTP_USER_AGENT'],
      :updated_at => DateTime.now.beginning_of_day..DateTime.now.end_of_day
    })
    if visit.nil?
      # eintrag existiert noch nicht -> anlegen, fertig
      v = Visit.new({
          :ip => request.remote_ip.to_s,
          :browser_agent => request.env['HTTP_USER_AGENT'],
          :page => "#{params[:controller]}/#{params[:action]}",
          :referrer => request.env['HTTP_REFERRER']
        })
      # Logging
      logger.error "Fehler beim Speichern eines Visits" unless v.save
    end
  end
 
end

Den Inhalt der Methode kann man natürlich nach seinen Wünschen anpassen. In dem Fall wird jeder Besucher pro Tag einmal gespeichert. (Hinweis: Evtl. müssen die Parameter config.time_zone und config.active_record.default_timezone in der environment.rb auf die gewünschte Zeitzone angepasst werden)
Ergänzend dazu kann man nun einige Helper erstellen, die überall verwendet werden können:

module PagesHelper
 
  def visitors_today
    v = Visit.find(:all, :conditions => {
        :updated_at => DateTime.now.beginning_of_day..DateTime.now.end_of_day
      })
    v.size
  end
 
  # day as DateTime
  def visitors_on day
    v = Visit.find(:all, :conditions => {
        :updated_at => day.beginning_of_day..day.end_of_day
      })
    v.size
  end
 
  def visitors_total
    Visit.count
  end
 
end

Erweiterungsmöglichkeiten:

  • Alle Seiten speichern, die der Besucher aufruft, Vorteil: bessere Auswertungsmöglichkeiten (Welche Seiten werden häufig besucht, etc.), Nachteil: sehr schnell viele Daten – abhängig von Seitenzahl
  • Weitere Kontrollen einbauen: Cookies, Sessions, etc.
  • Helpermethoden in einem Partial zu einer „Statistik-Box“ zusammenfassen

Endlich die Lösung

Dies ist ein Update meines vorherigen Posts.

Ich habe lange gebraucht, um mal wieder was am Server mit RubyOnRails zu machen. Nun habe ich eine Lösung gefunden, wie ich auf meinem Ubuntu 8.04 Server, Ruby on Rails zur Verfügung stellen kann.

Ich habe mir überlegt, dass es sinnvoll wäre das von strato zur Verfügung gestellte Plesk zu nutzen, um Kunden auf dem vServer zu verwalten (pro Kunde soll es vorerst eine Rails-Applikation geben). Ich habe dann überlegt, wie man Ruby on Rails da integrieren kann. Ich stieß auf einige Doku-Seiten bei parallels, die zeigen, wie man RoR aktivieren kann. Allerdings arbeitet diese Variante mit fastcgi. Ich wollte aber mit mongrel, nginx oder (am liebsten) Phusion Passenger arbeiten. Außerdem bekam ich bei der dort gezeigten Variante einige schlecht nachvollziehbare Fehlermeldungen, die ich nicht lösen konnte.

Es musste also eine andere Lösung her: Ich habe dann einen etwas älteren Artikel gefunden, der zeigt, wie man RoR in Plesk integrieren und dabei Phusion Passenger nutzen kann.

Meine Schritte im Überblick:

  1. Erstellen eines Kunden in Plesk
  2. Manuelle Installation einer relativ aktuellen Ruby-Version (1.8.7) auf dem Server
  3. Installation einer aktuellen rubygems-Version
  4. Installation aller nötigen gems (rails, builder, etc.)
  5. Befolgen der Anweisungen aus dem oben genannten Artikel (passenger gem installieren, passenger Installation starten, vHost.conf erstellen und DocumentRoot eintragen, den Schritt mit RubyEnterprise habe ich weggelassen)
  6. Hochladen der Applikation (über angelegten Kundenaccount) per ftp
  7. Apache evtl. neustarten, Applikation aufrufen

Einige Hinweise noch:

  • Neustart der Rails-Applikation per touch der Datei  /tmp/restart.txt
  • diese Variante macht nur eine Rails-Applikation pro Nutzer möglich, das wollte ich aber bewusst so, im Artikel oben sind aber Hinweise zu finden, wie man Subdomains nutzen kann