ruby · level 3 · unit 7 · lesson 2
- meet it
- guess first
- your turn
- fix it
- 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.
guess first
A pet with a blank name and twelve legs. What will this show?
Guess before you run it. Wrong guesses are how you learn, and nothing is marked.
class Pet < Struct.new(:name, :legs, keyword_init: true)
RULES = []
def self.validates(message, &rule)
RULES << [message, rule]
end
validates("name can't be blank") { !name.strip.empty? }
validates("legs must be 0 to 8") { legs.between?(0, 8) }
def errors
RULES.reject { |message, rule| instance_eval(&rule) }.map(&:first)
end
end
p Pet.new(name: " ", legs: 12).errors
your turn
Your turn. Add a validation for product names.
Write a message for the name rule in the first blank, then choose a minimum name length of 2 or 3. A mug should pass every rule.
fix it
A perfectly good email crashes the check. Fix the rule.
- The error says
include?was called onnil. Why is@emailempty? - A struct keeps its fields itself, not in instance variables, so
@emailisnil. Use the reader. - On line 6, change
@emailtoemail, then press run.
nailed it
your model checks itself now. :D
- A model declares its validations with a class macro.
errorsruns every rule and keeps the failures' messages.valid?is true only whenerrorsis empty.
new words in your collection
- model
- validation
- valid?
This lesson isn’t saved. A free account remembers every lesson you finish.