Khi gọi method không tồn tại, Ruby leo lên method lookup chain, không tìm thấy thì gọi method_missing trên object đó.
class DynamicFinder
def method_missing(name, *args)
if name.to_s.start_with?("find_by_")
field = name.to_s.sub("find_by_", "")
puts "Finding by #{field} = #{args.first}"
else
super # PHẢI gọi super để các error thực sự vẫn bubble up
end
end
def respond_to_missing?(name, include_private = false)
name.to_s.start_with?("find_by_") || super
end
end
DynamicFinder.new.find_by_email("x@y.com") # => Finding by email = x@y.comLưu ý bắt buộc:
1. Luôn super trong nhánh không xử lý để giữ NoMethodError.
2. Luôn override respond_to_missing? kèm theo — không thì respond_to? trả sai.
3. method_missing chậm hơn method thật (không được cache). Cân nhắc dùng define_method khi biết trước tên method.
When a method is called on an object and not found anywhere in the lookup chain, Ruby calls method_missing on that object.
class DynamicFinder
def method_missing(name, *args)
if name.to_s.start_with?("find_by_")
field = name.to_s.sub("find_by_", "")
puts "Finding by #{field} = #{args.first}"
else
super # MUST call super to propagate real NoMethodErrors
end
end
def respond_to_missing?(name, include_private = false)
name.to_s.start_with?("find_by_") || super
end
end
DynamicFinder.new.find_by_email("x@y.com") # => Finding by email = x@y.comRequired caveats:
1. Always call super in unhandled branches so real NoMethodErrors still propagate.
2. Always override respond_to_missing? alongside it — otherwise respond_to? lies.
3. method_missing is slower than real methods (not cached). Consider define_method when method names are known in advance.