Boolean Attribut Validierung

Immer wieder taucht die Frage auf, wie Boolean Attribute validiert werden können.
Die Antwort darauf: Am Besten gar nicht.

Antipattern Boolean Validierung

Leider kommt viel zu oft die Empfehlung, Boolsche Attribute mit validates_inclusion_of zu validieren. Also, ob der Wert entweder true oder false ist:

class User < ApplicationRecord
  validates :receive_newsletter, inclusion: [true, false] 
end

und die Erwartungshaltung:

RSpec.describe User, type: :model do
  it { is_expected.to validate_inclusion_of(:receive_newsletter).in_array([true, false]) }
end

Allerdings warnt der Shoulda Matchers Test ausdrücklich vor der Boolean Validierung:

************************************************************************
Warning from shoulda-matchers:

You are using `validate_inclusion_of` to assert that a boolean column
allows boolean values and disallows non-boolean ones. Be aware that it
is not possible to fully test this, as boolean columns will
automatically convert non-boolean values to boolean ones. Hence, you
should consider removing this test.
************************************************************************

Lösung

Die Lösung ist sehr einfach: Am Besten gar keine Validierung der Boolean Werte.
Stattdessen sollte das 3-Status-Problem (Boolean Attribut mit den möglichen Zuständen true, false und nil) vermieden werden. Das heißt das Atribut darf nur 2 Zustände annehmen (true und false) und der undefinierte Zustand wird ausgeschlossen, indem auf Datenbankebene der Default Wert false konfiguriert ist:

class SetUsersReceiveNewsletterDefault < ActiveRecord::Migration
  change_column :users, :receive_newsletter, :boolean, default: false
end

Bein Einhaltung dieser Konvention, ist immer klar, dass der Default Wert immer false ist. Es sei denn, er soll true, sein. Dann sollte dies explizit in einem before_create Callback gesetzt werden.
Bei diesem Ansatz, braucht niemand die Default Wert Einstellung auf Datenbankebene nachzuschauen und auf Validierungen des Attributes kann verzichtet werden.

Akzeptanzvalidierung (Boolean Attribute)

Ein andere Fall sind Validierungen von Boolean Attributen, bei denen die Eingabe geprüft wird, ob der erwartete Wert (true) auch tatsächlich gesetzt wurde.
Das trifft zum Beispiel auf das ausdrückliche Akzeptieren der AGB zu.
Dafür gibt es in RubyOnRails einen gesonderten Validator, den ActiveModel::Validations::AcceptanceValidator:

class User < ApplicationRecord
  validates :terms_and_conditions, acceptance: true
end