问题
I am using sinatra and DataMapper to access an sqlite3 database. I always get an nil
when calling get(params[:id])
. But when I call get(params[:id].to_i)
I can get the right record. Is there anything wrong such that I have to do the conversion explicitly?
The sinatra app is simple:
class Record
include DataMapper::Resource
property :id, Serial
....
end
get '/list/:id' do
r = Record.get(params[:id])
...
end
回答1:
Obviously this is a problem with Datamapper (if you believe it should be casting strings to numbers for id's), but there are ways Sinatra can mitigate it. When params come in you need to check:
- They exist.
- They're the right type (or castable).
- They're within the range of values required or expected.
For example:
get '/list/:id' do
r = Record.get(params[:id].to_i)
# more code…
curl http://example.org/list/ddd
That won't work well, better to check and return an error message:
get '/list/:id' do |id| # the block syntax is helpful here
halt 400, "Supply an I.D. *number*" unless id =~ /\d+/
Then consider whether you want a default value, whether the value is in the right range etc. When taking in ID's I tend to use the regex syntax for routes, as it stops following sub routes being gobbled up too, while providing a bit of easy type checking:
get %r{/list/(\d+)} do |id|
Helpers are also useful in this situation:
helpers do
# it's not required to take an argument,
# the params helper is accessible inside other helpers
# it's but easier to test, and (perhaps) philosophically better.
def id( ps )
if ps[:id]
ps[:id].to_i
else
# raise an error, halt, or redirect, or whatever!
end
end
end
get '/list/:id' do
r = Record.get id(params)
回答2:
To clarify, the comment in the original question by @mbj is correct. This is a bug in dm-core with Ruby 2.0. It worked fine with ruby 1.9. You are likely on dm-core version 1.2 and need 1.2.1, which you can get by running 'gem update dm-core'.
来源:https://stackoverflow.com/questions/16304097/sinatra-matches-paramsid-as-string-type-additional-conversion-needed-to-matc