nitturu.baba
Tue Nov 26 2024
Optimizing Validations with Caching
When we have a
1. The user exists or not.
2. The user has enough coins to complete the operation.
The basic validation will look like this (with
But the problem here is, We query the database twice to fetch the same
To avoid redundant queries, we can cache the
The optimized code looks like this:
#ruby on rails
When we have a
Member
model where each user has a specific number of coins. When performing operations like capturing or deducting coins, we want to validate:1. The user exists or not.
2. The user has enough coins to complete the operation.
The basic validation will look like this (with
dry-validation
gem)
class CoinsValidator < Dry::Validation::Contract
params do
required(:user).filled(:integer)
required(:coins).filled(:integer, gt?: 0)
end
rule(:user) do
member = Member.find_by(unique_id: value) // querying database for member details
key.failure("does not exist") if member.nil?
end
rule(:coins, :user) do
member = Member.find_by(unique_id: values[:user]) // querying database for member details
if member && member.coins < values[:coins]
key(:coins).failure("are insufficient")
end
end
end
But the problem here is, We query the database twice to fetch the same
Member
object once in the :user
rule and again in the :coins
rule. This redundant querying increases database load and slows down validation, especially in high-traffic applications.To avoid redundant queries, we can cache the
Member
object using the values
hash provided by the dry-validation
gem. The values
hash allows us to store intermediate results, making them accessible to other validation rules.The optimized code looks like this:
class CoinsValidator < Dry::Validation::Contract
params do
required(:user).filled(:integer)
required(:coins).filled(:integer, gt?: 0)
end
rule(:user) do
values[:member] = Member.find_by(unique_id: value) // Caching the member object
key.failure("does not exist") if values[:member].nil?
end
rule(:coins) do
member = values[:member] // accessing the cached Member from values[:member] rather than querying the database again.
if member && member.coins < value
key.failure("are insufficient")
end
end
end
#ruby on rails