×

ruby · level 3 · unit 7 · lesson 2

  1. meet it
  2. guess first
  3. your turn
  4. fix it
  5. nailed it

Tap a green word if you get lost.

meet it

A declares its validations, then checks itself.

A model is a class for one kind of thing your app stores, such as a user or an order. Instead of checking data by hand everywhere, a model declares each , a rule its data must follow, with a class macro. Rails writes validates :email, presence: true. Ours takes a message and a block.

The macro only stores the rule. errors runs each stored rule on the object with instance_eval, uses reject to drop the rules that pass, and keeps the messages of the rest. is then errors.empty?, the question Rails asks before every save.

class Signup < Struct.new(:email, :age, keyword_init: true)
  RULES = []
  def self.validates(message, &rule)
    RULES << [message, rule]
  end
  validates("email needs an @") { email.include?("@") }
  validates("age must be 13 or over") { age >= 13 }
  def errors
    RULES.reject { |message, rule| instance_eval(&rule) }.map(&:first)
  end
end
signup = Signup.new(email: "sam.example.com", age: 15)
p signup.errors
p Signup.new(email: "ana@example.com", age: 15).errors.empty?

class Signup < Struct.new(...) inherits named fields from a struct, so the model needs no initialize of its own.