Rails version - 6.0.3.6
I have one table subscription_attempts and it has one column attempt_token
which is unique random token for each record and it is generated based on rails's
When i tried to do this query with where got below exception
SubscriptionAttempt.where('id = ?', '5HqBToVVbFVL4T6TLzuuKju8')
ActiveRecord::StatementInvalid (PG::InvalidTextRepresentation: ERROR: invalid input syntax for type bigint: "5HqBToVVbFVL4T6TLzuuKju8")
LINE 1: ...empts".* FROM "subscription_attempts" WHERE (id = '5HqBToVVb...
I am assuming this is not how these methods should behave. It should give a nil
result if the value is not matching with database value. Can someone please give me the solution to this problem?
CodePudding user response:
ActiveRecord automatically does some type casting before querying the database. You can read more about it here. Basically, since ActiveRecord knows that the id
column is an integer, it will cast the value
passed to find_by(id: value)
to an integer and:
> '5HqBToVVbFVL4T6TLzuuKju8'.to_i
=> 5
Try switching the order:
def random_method(value)
find_by(attempt_token: value) || find_by(id: value)
end
This is still not a 100% bullet proof in case you have an instance with an attempt_token
of "1234"
and another instance with an id of 1234
. The former will always be returned even if you meant to fetch the latter.
Another solution would be to prepend a constant prefix to your attempt_token
:
ATTEMPT_TOKEN_PREFIX = 'at_'.freeze
def attempt_token_with_prefix
# provide this value to the user instead of just providing the raw attempt_token
"#{ATTEMPT_TOKEN_PREFIX}#{attempt_token}"
end
def random_method(value)
if value.starts_with?(ATTEMPT_TOKEN_PREFIX)
find_by(attempt_token: value[ATTEMPT_TOKEN_PREFIX.length..])
else
find_by(id: value)
end
end