Calvin
Calvin

Reputation: 3312

Activerecord find_by_id strange behavior

Consider I have a show method in controller like this:

class ThingsController < ApplicationController
    def show
        thing = Thing.find_by_id(params[:id])
        render json: 'Not Found', status: :not_found and return if !thing
        render json: thing.to_json, status: :ok
    end
end

There is only 1 record in database with id=1.

Now, here is my test:

  1. When I call /things/1 I can get the record.
  2. When I call /things/2 I get 404.
  3. When I call /things/a1 I get 404.
  4. When I call /things/1a I am expecting error but it gives me record with id=1.

Is #4 normal? How to prevent that?

Rails Version: 4.2.6

Upvotes: 1

Views: 136

Answers (2)

Long Nguyen
Long Nguyen

Reputation: 373

Because type of id is integer, so active record will convert it to integer before create query string by using to_i function. If you don't want user go to details with link like this, there are many ways to prevent, some e.g for you:

1.Validate params[:id] is number in ThingsController

2.Create class method find_by_id in Thing

class class Thing < ActiveRecord::Base   
  def self.find_by_id(id)
    validate_type_id!(id) # Have to define the function to raise not found exception if invalid format type
    super   
  end
end

Upvotes: 1

Uzbekjon
Uzbekjon

Reputation: 11823

.find_by_id() method is converting passed in argument to integer and because 1a.to_i is 1, it is returning a record value.

If you want to prevent that, you'd have to check that the passed in param[:id] contains only digits.

'1a' !~ /\D/                # false
'12' !~ /\D/                # true

# So, use it in the if
params[:id] !~ /\D/

Upvotes: 2

Related Questions