--
Posted via http://www.ruby-forum.com/.
Dynamic typing is wonderful, until it isn't. My hypothesis is that remote_ip
is not a Fixnum or Bignum but a custom class that overrides to_s. To test the
hypothesis, I'd run the following in the console of writing to the log.
puts request.remote_ip.class
puts request.remote_ip
puts request.remote_ip.to_s
puts "#{request.remote_ip}"
puts request.remote_ip.inspect
DocType.create(:name => request.remote_ip)
DocType.last
DocType.create(:name => request.remote_ip.to_s)
DocType.last
Somewhere in this, I expect the truth will be revealed.
A IPv4 address is a 32 bit, unsigned number. It is usually
represented/rendered in dotted quad notation, but 0x7F000001 or 2130706433 are
equally valid representations of the local or loopback interface's IPv4
address.
HTH,
Jeffrey
That seems like definitive proof that:
request.remote_ip != '127.0.01'
In fact you could test that:
if request.remote_ip == '127.0.0.1
puts 'yes'
else
puts 'no'
end
> inspect returns:
>
> ruby-1.9.2-p180 :009 > DocType.all.map {|d| d.name.inspect}
> DocType Load (1.4ms) SELECT "doc_types".* FROM "doc_types"
> => ["\"127.0.0.1\"", "\"127.0.0.1\""]
>
The output shows that the string is actually "127.0.0.1"--not 127.0.0.1.
For example:
data = [
%q{"127.0.0.1"},
%q{127.0.0.1}
]
data.each do |str|
p str
end
--output:--
"\"127.0.0.1\""
"127.0.0.1"
>
>> inspect returns:
>>
>> ruby-1.9.2-p180 :009 > DocType.all.map {|d| d.name.inspect}
>> DocType Load (1.4ms) SELECT "doc_types".* FROM "doc_types"
>> => ["\"127.0.0.1\"", "\"127.0.0.1\""]
>>
>
> The output shows that the string is actually "127.0.0.1"--not 127.0.0.1.
> For example:
>
I disagree, this output shows only that the `inspect` of the string is
(unquoted) "127.0.0.1", but the string itself is (unquoted) 127.0.0.1.
So this does not clarify the issue.
Alexey.
You probably cannot do this in console (request.remote_ip not defined),
so you'll have to test it all in controller.
Can you do it in 3 steps:
create two records in the database (with a string and with
request.remote_ip ),
see what is in the database,
verify that the records look identical, but find_by_ip returns only one?
This is what i would do.
If this does not fix it, than it looks like a bug to me.
I also have an application where i store IP addresses, but i didn't try
yet to find by ip, and the IP returned by `request.remote_ip` looked
like a string to me.
I would be interested to understand what's the difference.
I use rails 3.1rc6 and ruby 1.9.2
Alexey.
group :development do
gem 'sqlite3'
end
$ rails new test_ip
$ cd test_ip
$ rails generate model MyModel ip:string description:string
$ rake db:migrate
$ rails generate controller Writer write_records
app/controllers/writer_controller.rb:
class WriterController < ApplicationController
def write_records
MyModel.create!(:ip => request.remote_ip, :description => 'request')
MyModel.create!(:ip => '127.0.0.1', :description => 'string')
end
end
$ rails s
go to
http://localhost:3000/writer/write_records
$ rails c
> MyModel.all
MyModel Load (0.2ms) SELECT "my_models".* FROM "my_models"
=> [#<MyModel id: 1, ip: "127.0.0.1", description: "request",
created_at: "2011-08-30 09:42:09", updated_at: "2011-08-30 09:42:09">,
#<MyModel id: 2, ip: "127.0.0.1", description: "string", created_at:
"2011-08-30 09:42:09", updated_at: "2011-08-30 09:42:09">]
> MyModel.where(:ip => '127.0.0.1').all
MyModel Load (0.2ms) SELECT "my_models".* FROM "my_models" WHERE
"my_models"."ip" = '127.0.0.1'
=> [#<MyModel id: 2, ip: "127.0.0.1", description: "string",
created_at: "2011-08-30 09:42:09", updated_at: "2011-08-30 09:42:09">]
> MyModel.first.ip == '127.0.0.1'
MyModel Load (0.2ms) SELECT "my_models".* FROM "my_models" LIMIT 1
=> true
In the database for the first ip i have: X'3132372E302E302E31'
Okay, I agree with your disagree. I have no idea what this means,
though:
> this output shows only that the `inspect` of the string is
> (unquoted) "127.0.0.1", but the string itself is (unquoted) 127.0.0.1.
> So this does not clarify the issue.
>
> Alexey.
strings = [
"abc",
%q("abc")
]
results = strings.map do |str|
str.inspect
end
p results
results.each do |str|
puts str
end
--output:--
["\"abc\"", "\"\\\"abc\\\"\""]
"abc"
"\"abc\""
The second element in the array is hard to interpret: if you strip away
what inspect added to the first string, you get:
\\\"abc\\\"
I guess \\ is a literal slash and \' is an escaped quote.
Alexey.
Yes, Christoph linked to his sqlite dump, which showed the sane thing::
# dump shows:
sqlite> .dump doc_types
PRAGMA foreign_keys=OFF;
BEGIN TRANSACTION;
CREATE TABLE "doc_types" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT
NULL, "name" varchar(255), "description" varchar(255));
INSERT INTO "doc_types" VALUES(6,X'3132372E302E302E31','request');
INSERT INTO "doc_types" VALUES(7,'127.0.0.1','string');
It sure seems like an encoding issue. If you read the sqlite docs,
labeling a column as a certain type is not very rigid: you can insert
different types in a column. In fact, the sqlite2 docs say that having
typed columns is a "misfeature" of other databases. sqlite3 seems to
have backed off that statement because sqlite3 appears to provide loose
typing for columns. In any case, just because the column type is string
does not mean the types in the column are necessarily the same.
In the controller, instead of
MyModel.create!(:ip => request.remote_ip, :description => 'request')
do
model = MyModel.new
model.save # this is important!
model.ip = request.remote_ip
model.description = 'request'
model.save
then it works.
Alexey.
@remote_ip = request.remote_ip
@remote_ip_encoding = @remote_ip.encoding.name
@str_literal_encoding = '127.0.0.1'.encoding.name
and then displaying the variables in a view. ASCII-8BIT is a synonym
for 'binary', i.e. unknown encoding.
Actually, I don't think it has anything to do with ruby--rather it's how
sqlite3 compares the search string to the two strings in the sqlite3 db.
I don't know enough about rails to determine that. Encoding issues are
tricky.
>
> I have found out the difference between my application and this one.
>
> In the controller, instead of
>
> MyModel.create!(:ip => request.remote_ip, :description => 'request')
>
> do
>
> model = MyModel.new
> model.save # this is important!
> model.ip = request.remote_ip
> model.description = 'request'
> model.save
>
> then it works.
>
> Alexey.
I can't duplicate the op's problem: I can't get sqlite3 to show
X'3132372E302E302E31' for a string field. It doesn't matter if I use
create(), or new() and save(). I get the following in both cases:
sqlite> .dump users
BEGIN TRANSACTION;
CREATE TABLE "users" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
"name" varchar(255), "email" varchar(255), "created_at" datetime,
"updated_at" datetime, "last_sent_to" varchar(255));
INSERT INTO "users" VALUES(1,'127.0.0.1','request','2011-08-30
11:43:08.702303','2011-08-30 11:43:08.702303',NULL);
INSERT INTO "users" VALUES(2,'127.0.0.1','string','2011-08-30
11:43:08.710679','2011-08-30 11:43:08.710679',NULL);
COMMIT;
sqlite>
MyModel.create!(:ip => request.remote_ip.force_encoding('UTF-8'))
Apparently the sqlite adapter looks into the encoding before saving.
Still not clear if this should not be considered a bug.
Alexey.
class PagesController < ApplicationController
def home
@title = "Home"
@remote_ip = request.remote_ip
@remote_ip_encoding = @remote_ip.encoding.name
@str_literal_encoding = '127.0.0.1'.encoding.name
User.create!(:name => request.remote_ip, :email => 'request')
User.create!(:name => '127.0.0.1', :email => 'string')
model = User.new
model.save # this is important!
model.name = request.remote_ip
model.email = 'request'
model.save
model2 = User.new
model2.save
model2.name = '127.0.0.1'
model2.email = 'string'
model2.save
end
def about
@title = "About"
end
end
sqlite> .dump users
BEGIN TRANSACTION;
CREATE TABLE "users" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
"name" varchar(255), "email" varchar(255), "created_at" datetime,
"updated_at" datetime, "last_sent_to" varchar(255));
INSERT INTO "users" VALUES(1,'127.0.0.1','request','2011-08-30
12:04:18.230500','2011-08-30 12:04:18.230500',NULL);
INSERT INTO "users" VALUES(2,'127.0.0.1','string','2011-08-30
12:04:18.237719','2011-08-30 12:04:18.237719',NULL);
INSERT INTO "users" VALUES(3,'127.0.0.1','request','2011-08-30
12:04:18.302252','2011-08-30 12:04:18.302252',NULL);
INSERT INTO "users" VALUES(4,'127.0.0.1','string','2011-08-30
12:04:18.307215','2011-08-30 12:04:18.307215',NULL);
COMMIT;
sqlite>
> I can't duplicate the op's problem: I can't get sqlite3 to show
> X'3132372E302E302E31' for a string field. It doesn't matter if I use
> create(), or new() and save().
>
> $ rails -v
> Rails 3.0.9
>
> $ ruby -v
> ruby 1.9.2p180 (2011-02-18 revision 30909) [x86_64-darwin10.7.0]
>
> $ sqlite3 -version
> 3.6.12
Strange, maybe it is a difference between Rails 3.0.X and Rails 3.1?
When I do a bundle install, this is the only sqlite3 gem I see:
Using sqlite3 (1.3.3)
What version are you guys using? Also what version of ruby, rails and
sqlite? Mine are:
$ rails -v
Rails 3.0.9
$ ruby -v
ruby 1.9.2p180 (2011-02-18 revision 30909) [x86_64-darwin10.7.0]
$ sqlite3 -version
3.6.12
--
Posted via http://www.ruby-forum.com/.
> What version are you guys using? Also what version of ruby, rails and
> sqlite?
$ rails -v
Rails 3.1.0.rc8
$ ruby -v
ruby 1.9.2p290 (2011-07-09 revision 32553) [x86_64-darwin10.8.0]
$ sqlite3 -version
3.7.7.1 2011-06-28 17:39:05
Alexey,
I faced with the similar problem in slightly different environment:
(in simply controller)
...
hash = Digest::SHA2.hexdigest
[params[:document][:file].original_filename, current_user.email,
version].join
...
if current_user.documents.create :path => file.to_s, :hashref =>
hash, :version => version,
...
(logs and dump)
...
INSERT INTO "documents" ("created_at", "description", "hashref",
"mimetype", "path", "updated_at", "user_id", "version") VALUES (?, ?, ?,
?, ?, ?, ?, ?) [["created_at", Tue, 13 Sep 2011 17:43:16 UTC +00:00],
["description", nil],
> ["hashref", "18da91cbfadb74e43d9ca4231555462d"],
["mimetype", "[text/plain]"], ["path", "y1.txt"], ["updated_at", Tue, 13
Sep 2011 17:43:16 UTC +00:00], ["user_id", 1], ["version", 0]]
sqlite> .dump documents
INSERT INTO "documents"
VALUES(13,1,'y1.txt',
> X'3138646139316362666164623734653433643963613432333135353534363264',
NULL,'[text/plain]','2011-09-13
17:43:16.214665','2011-09-13 17:43:16.214665',0);
So I can't refer to this record using hash value. But! If I add just a
little modification to hash string, just a single char other than
[0-9a-f] (say hash += "*"), everything works well:
sqlite> .dump documents
INSERT INTO "documents"
VALUES(14,1,'test-text',
> '6c9034ddb7f1f248e6a215a1d335ff94*',
'tt1','[]','2011-09-13
17:59:25.925458','2011-09-13 17:59:25.925458',0);
I'm using Rails 3.1, Ruby 1.9.2p290 and sqlite 3.7.7.1.