Neue Star-Trek-Serie 2017

Eine Meldung die trotz großem Interesse fast an mir vorbeiging: Für das Jahr 2017 hat das amerikanische Medienunternehmen CBS eine neue Star-Trek-Serie angekündigt. Der verantwortliche Produzent Alex Kurtzman war allerdings schon bei den letzten beiden Pseudo-Star-Trek-Actionfilmen beteiligt. Misstrauen ist wie beim neuen Star-Wars-Film also angebracht. Zudem sollen die Folgen in den USA weitgehend über einen vergleichsweise wenig relevanten Streaming-Dienst angeboten werden. Auch das klingt nicht wirklich erfolgversprechend.

Viel mehr ist derzeit nicht bekannt. Wann und in welchem Paralleluniversum welches Schiff unterwegs sein wird darf also spekuliert werden.

Match API output with YAML fixture

A nice and simple approach to test you JSON APIs:

# spec/features/api/user_spec.rb

require 'rails_helper'

RSpec.feature 'User', type: :feature do
  it 'lists users' do
    user = create(:user, :as_admin)
    visit api_user_path(user, format: :json)
    expect(page).to match_yaml_fixture('api/user')
  end
end

This checks if the page source matches the data given in the fixture file. To make it more readable we format the expected JSON as YAML:

# spec/fixtures/api/user.yaml

---
user:
- id: 1
  first_name: Max
  last_name: Power
  role:
    id: 1
    name: Admin

„Match API output with YAML fixture“ weiterlesen

Overwriting and Overriding with define_method

Recently we stumbled upon this inheritance issue, which seemed very weird at the first:

class A
  def talk
    'A'
  end
end

class B < A
  def self.define_talk
    define_method :talk do
      super() << 'B'
    end
  end
end

class C < B
  define_talk
 
  def talk
    super << 'C'
  end
end

> C.new.talk
 => "AC"

The talk addition from class B doesn’t appear, even though define_talk is triggered by Class C. C’s super call seems to ignore its direct parent B.

„Overwriting and Overriding with define_method“ weiterlesen

Jump ’n‘ Run Maldita Castilla auf Ubuntu

Maldita Castilla ist sehr charmantes, kostenloses Jump ’n‘ Run à la Ghouls ’n Ghosts des spanischen Ein-Mann-Entwicklers Locomalito. Netterweise gibt es sogar eine Ubuntu-Version (die laut Entwickler möglicherweise auch auf anderen Distributionen läuft). Beim Start ergaben sich für mich jedoch kleinere Problemchen.

Maldita Castilla

„Jump ’n‘ Run Maldita Castilla auf Ubuntu“ weiterlesen

ActiveRecord: Klasse einer Model-Instanz ändern

ActiveRecord erlaubt das direkte Ändern der Klasse einer Model-Instanz mittels #becomes. Dies kann zum Beispiel hilfreich sein, wenn man für einen Spezialfall weitere Funktionen oder Validierungen zu einem Model hinzufügen will:

> company = Company.last
> company.persisted?
 => true
> company.valid?
 => true 
> company = company.becomes(RestrictedCompany)
> company.is_a?(RestrictedCompany)
 => true 
> company.is_a?(Company)
 => true 
> company.persisted?
 => true
> company.valid?
 => false

Ähnliches ließe sich zwar auch mit bedingten Validierungen erreichen, würde aber ab einem gewissen Umfang schlicht nicht mehr skalieren.

Ein weiterer, oft gesehener Ansatz wäre RestrictedCompany.find(company.id). Dieser ist jedoch von der Datenbank abhängig und somit vermutlich weniger performant. Zudem benötigt er wirklich persistierte Instanzen. Dies ist vor allem nervig, wenn man in Tests gerne Stubbing nutzt.

Zum Speichern der Klassenänderung kann man #becomes! verwenden. Dies passt auch die STI-Vererbungsspalte (in aller Regel type) an.

Action-Mailer-Previews im Spec-Verzeichnis

Die Mailer-Previews in Rails 4 sind ein Segen. Wer Rspec statt der üblichen Testsuite verwendet kann das Verzeichnis von test in spec ändern, so dass alle Testdateien zusammen bleiben:

# config/application.rb

# ...
config.action_mailer.preview_path = "#{Rails.root}/spec/mailers/previews"

Nach einem Serverneustart sollten die Previews gefunden werden:

# spec/mailers/previews/user_mailer_preview.rb

class UserMailerPreview < ActionMailer::Preview
  def send_invitation
    UserMailer.send_invitation(Invitation.first!)
  end
end

Die Vorschau kann man dann unter den üblichen URLs betrachten, z.B.:

http://localhost:3000/rails/mailers/user_mailer/send_invitation

Rails 4: Already initialized constant APP_PATH?

Ein Fehler, der mir in Rails-4-Projekten öfter unterkommt:

bin/rails:6: warning: already initialized constant APP_PATH

Dies deutet auf ein Problem mit Spring hin. Es kann daher helfen, die Projekt-Binaries neu zu generieren:

rake rails:update:bin

Dies ist oft schon die Lösung oder sollte zumindest eine Fehlermeldung liefern, anhand derer man das tatsächliche Problem finden kann.

Suchstatus in ActiveAdmin deaktivieren

Der Suchstatus des Active-Admin-Masters funktioniert momentan fehlerhaft. Weder Scope-Namen noch Ransack-Suchen werden korrekt übersetzt.

Suchstatus in ActiveAdmin

Da ich das Konzept ohnehin nicht sonderlich gewinnbringend finde, schalte ich es zentral im Active-Admin-Initializer ab:

Wer das Konzept, wie ich, nicht sonderlich gewinnbringend und eines umständlichen Workarounds wert findet, kann es zentral im Initializer von ActiveAdmin abschalten:

# config/initializers/active_admin.rb

ActiveAdmin.setup do |config|
  # ...
  config.current_filters = false
end

ActiveAdmin: Authentifizierung für Browser und API

Eine einfache API-Authentifizierung lässt sich in ActiveAdmin durch Wiederverwendung des Standard-Admin-Users im Initializer erreichen:

 # config/initializers/active_admin.rb
 ActiveAdmin.setup do |config|
   config.prepend_before_filter do
     if active_admin_config.namespace.name == :api
       authenticate_or_request_with_http_basic('API') do |name, password|
         user = AdminUser.find_by_email!(name)
         sign_in(:admin_user, user) if user.valid_password?(password)
       end
     end
   end

Dies erlaubt die Angabe des Benutzernamens und Passworts im Browser als Popup (HTTP-Basic-Authentication) und als Header für APIs:

curl -u admin@example.com:password http://localhost:3000/api/my_resources.json

„ActiveAdmin: Authentifizierung für Browser und API“ weiterlesen

API-Namespace für ActiveAdmin

In ActiveAdmin kann man neben dem Standard weitere Namespaces definieren. Hierfür wird bei der Ressourcen-Registrierung die entsprechende Option angegeben:

# app/admin/api/my_resource.rb

ActiveAdmin.register MyResource, namespace: :api do
 # ...

Das Namespace-Verzeichnis kann unter app/admin abgelegt werden, ohne das „admin“ Teil der URL, des Controller-Namens o. ä. wird:

rake routes
# ...
api_my_resources GET  /api/my_resources(.:format)  api/my_resources#index
# ...