2012/01/28

Authentifizierung mit Rails und Authlogic

Man braucht sie heutzutage in jeder Applikation: die Benutzeranmeldung. Darin liegt auch die erste Hürde. Ein Controller muss die Anmeldung übernehmen, und der ApplicationController muss dafür sorgen, dass angemeldete Nutzer bei jedem Request aus der Session geladen werden. In jedem Controller muss festgelegt werden, für welche Actions man angemeldet sein muss.

Ein Tool, welches die meisten benötigten Funktionen abdeckt und relativ leicht zu installieren ist, ist authlogic. (Schnellanleitung: https://github.com/binarylogic/authlogic_example/blob/master/README.rdoc)


Mögliche Fehler nach der Installation:

undefined method `valid_password?' for #...

Nachdem ich die Spalte crypted_password der Tabelle hinzugefügt hatte, war das Problem gelöst.
Authlogic benötigt mindestens drei Felder, die meist automatisch erkannt werden. Benutzername/Email, Passwort und Passwortbestätigung. In meinem Fall musste ich in meinem _form.html.erb das Feld für die Passwortbestätigung :passwort_confirmation nennen, damit es funktioniert hat.
Wenn man nun authlogic soweit installiert hat, lässt sich ein nicht authentifizierter Besucher ganz einfach mit dem Aufruf eines before_filters in dem Ziel-Controller aussperren:


class UsersController < ApplicationController
  before_filter :require_no_user, :only => [:new, :create]
  before_filter :require_user, :only => [:show, :edit, :update]
[...]

2012/01/17

Einbinden von Styles und Scripts


Nach der vierten Auflage von "Agile Web Development with Rails" - und damit vermutlich nach den Konventionen von Rails < 3.1 - gehören Stylesheets und Javascripts in den /public/stylesheets Ordner und wird mit folgendem Methodenaufruf in das Layout geladen:
<%= stylesheet_link_tag "application" %>

Der String-Parameter "application" gibt an, welche CSS geladen wird.
Leider verlinkt der ausgegebene Link-Tag nicht auf den Ordner /public sondern /assets
Nach einer schnellen Suche im Ruby on Rails Guide ist eine Funktion namens Asset Pipeline per default eingeschaltet: http://guides.rubyonrails.org/asset_pipeline.html
Diese Funktion erlaubt es, Javascript und CSS zu bündeln und zu komprimieren um die Applikation zu optimieren.
Ebenso interessant dieser Funktion ist in Kapitel 2 des obigen Links nachzulesen: Es ermöglicht dem Entwickler, beispielsweise CSS nur dann zu laden, wenn es auch wirklich gebraucht wird. Dies wird über Controller definiert.
Der Scaffold-Befehl wird automatisch für jeden Controller in /assets/stylesheets/ eine CSS Datei erstellen.
Wenn man aber nun statt application.css eine andere CSS-Datei einbinden möchte, trifft man auf folgenden Fehler: 
Sprockets::CircularDependencyError in Controllername::Actionname

Um diesen Fehler zu umgehen, muss man die application.css löschen.
Damit immer nur das nötigste geladen wird lässt sich nun mit
<%= stylesheet_link_tag params[:controller] %>

die jeweilige CSS zum aufgerufenen Controller laden. Diese werden, wie schon erwähnt, mit jedem Scaffold automatisch erstellt und mit dem Suffix .css.scss in /assets/stylesheets/ abgelegt. 
Auf anhieb hat dies bei mir nicht funktioniert, aber nach einem Neustart des Servers wurden dann nur die nötigen CSS-Dateien geladen.

2012/01/15

Selbstverweisende Objekte - Tree Models

Mit Rails ist es relativ einfach Objekte zu erstellen, die rekursiv auf sich selbst verweisen können. Die repräsentieren meistens einen Kategoriebaum oder auch Beziehungen zwischen User (z.B. die Follower bei Twitter).

Man braucht dazu ein Model mit einem Datenbankfeld, welches sein eigenes Parent-Objekt speichert.
Mit den Methoden belongs_to und has_many lassen sich solche Beziehungen dann folgendermaßen darstellen:

  belongs_to  :parent_object,
                     :foreign_key  => "parent",
                     :class_name => "Category"
  has_many   :children,
                     :foreign_key  => "parent",
                     :class_name => "Category",
                     :order  => "name ASC",
                     :dependent => :delete_all

Nun lässt sich ganz einfach mit einer Instanz der Klasse, dessen Kinder aufrufen:

@category.children

Ebenso ist es möglich das Parent-Objekt aufzurufen:

@category.parent_object


Definiert werden diese Methoden mit dem ersten Parameter der belongs_to und has_many Definitionen. Man kann diese also nach belieben benennen.

2012/01/07

Rails Internationalisierung, Übersetzungsfehler für Datumformate

Wenn man sich eine Übersetzung einrichtet und dabei auf einen Fehler wie unten trifft, liegt dies vermutlich daran, dass Rails ein Datum nicht übersetzen kann.

Sehr aussagekräftig ist die Fehlermeldung nicht, deshalb habe ich die Lösung erst mit Google gefunden.

Die Lösung ist einfach:
Ruby on Rails fehlen für die Übersetzung von Datumformaten die korrekten Einträge in der Übersetzungsdatei (in meinem Fall config/locales/de.yml). Damit diese Datei für deutsche Datumformate vollständg ist, sollte man auf fertige Vorlagen zurückgreifen: https://github.com/svenfuchs/rails-i18n/tree/master/rails/locale

Die besagte Fehlermeldung:


undefined method `-' for "translation missing: de.date.order":String

2012/01/04

Fehler beim updaten der rails gems: coffee-rails

Wenn man versucht ein update der gems durchzuführen und dabei folgender Fehler auftritt:
Updating coffee-rails
ERROR:  While executing gem ... (NoMethodError)
    undefined method `call' for nil:NilClass
kann man ihn mit einem Update von den RubyGems wieder beheben. Auf der Umgebung lief Rails 3.1 und RubyGems 1.3.7. Nach dem Update auf RubyGems 1.8.13 lief das Update sauber durch.
# gem install rubygems-update
Falls danach beim Update Fehler - ähnlich wie diese - auftauchen sollten:
Invalid gemspec in [/usr/local/ruby/lib/ruby/gems/1.9.1/specifications/therubyracer-0.9.8.gemspec]: invalid date format in specification: "2011-10-07 00:00:00.000000000Z" Invalid gemspec in [/usr/local/ruby/lib/ruby/gems/1.9.1/specifications/json-1.6.1.gemspec]: invalid date format in specification: "2011-09-18 00:00:00.000000000Z" Invalid gemspec in [/usr/local/ruby/lib/ruby/gems/1.9.1/specifications/rack-cache-1.0.3.gemspec]: invalid date format in specification: "2011-08-27 00:00:00.000000000Z"
kann man diese folgendermaßen beheben.
  1. Die entsprechende Datei in der Fehlerausgabe in einem Editor öffnen.
  2. Die Zeile mit s.date = suchen
  3. Den Zeitwert 00:00:00.000000000Z löschen, sodass die Zeile so wie diese aussieht:  s.date = %q{2011-10-07}