Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

\' (backslash, single quote) in a Ruby string

I am using Ruby 1.8.7, trying to generate a string with the \' characteres, in order to create a script for running in MySQL. The result should be like this:

INSERT INTO table (name, description) values ('Joana d\'Arc', '')

But i can't get just one backslash in a ruby string. Using the following code:

string = "INSERT INTO table (name, description) values ('Joana d\\'Arc', '')"

I got the following string:

INSERT INTO table (name, description) values ('Joana d\\'Arc', '')

And with:

string = "INSERT INTO table (name, description) values ('Joana d\'Arc', '')"

I got this string:

INSERT INTO table (name, description) values ('Joana d'Arc', '')
like image 360
klidebharrow Avatar asked Nov 25 '11 16:11

klidebharrow


2 Answers

I recommend avoiding writing raw SQL, and, in this age, I'd use an ORM, even for simple DB use. I highly recommend using the Sequel gem. Borrowing from an example in the Sequel docs:

sequel sqlite://temp
Your database is stored in DB...

Using SQLite, that started the sequel ORM in interactive mode, and created the SQLite database called "temp".

ruby-1.9.2-p290 :001 > require 'logger'
 => true 
ruby-1.9.2-p290 :002 > DB.loggers << Logger.new(STDOUT)
 => [#<Logger:0x0000010160bc40 @progname=nil, @level=0, @default_formatter=#<Logger::Formatter:0x0000010160bc18 @datetime_format=nil>, @formatter=nil, @logdev=#<Logger::LogDevice:0x0000010160bbc8 @shift_size=nil, @shift_age=nil, @filename=nil, @dev=#<IO:<STDOUT>>, @mutex=#<Logger::LogDevice::LogDeviceMutex:0x0000010160bba0 @mon_owner=nil, @mon_count=0, @mon_mutex=#<Mutex:0x0000010160bb50>>>>] 

That enabled logging so we can see what Sequel will do as it talks to the database.

ruby-1.9.2-p290 :003 > items = DB[:items] # Create a dataset
 => #<Sequel::SQLite::Dataset: "SELECT * FROM `items`"> 
ruby-1.9.2-p290 :004 > DB.tables
I, [2011-11-25T10:17:13.056311 #10130]  INFO -- : (0.000501s) SELECT * FROM `sqlite_master` WHERE (type = 'table' AND NOT name = 'sqlite_sequence')
 => [] 

Doh! I forgot to create the table...

ruby-1.9.2-p290 :005 > DB.create_table :items do
ruby-1.9.2-p290 :006 >       primary_key :id
ruby-1.9.2-p290 :007?>     String :name
ruby-1.9.2-p290 :008?>     Float :price
ruby-1.9.2-p290 :009?>   end
I, [2011-11-25T10:17:20.985851 #10130]  INFO -- : (0.002372s) CREATE TABLE `items` (`id` integer PRIMARY KEY AUTOINCREMENT, `name` varchar(255), `price` double precision)
 => nil 

The table is created.

ruby-1.9.2-p290 :010 > items = DB[:items] # Create a dataset
 => #<Sequel::SQLite::Dataset: "SELECT * FROM `items`"> 

That created a dataset, which is just a convenient way to talk to a table.

And, that's the payoff:

ruby-1.9.2-p290 :011 > items.insert(:name => "Joan d'Arc")
I, [2011-11-25T10:17:45.186945 #10130]  INFO -- : (0.001981s) INSERT INTO `items` (`name`) VALUES ('Joan d''Arc')
 => 1

The ORM automatically escapes the characters for you. Your job is simplified greatly.

ORMs are DBM aware, so they know when to escape for a particular database. Your code doesn't change. It's trivial to switch from SQLite to MySQL, Postgres, or even non-SQL databases.

like image 133
the Tin Man Avatar answered Sep 28 '22 07:09

the Tin Man


The reason puts works is that it shows what is actually in the string. The bare console is showing the string escaped. Try this on the console:

"Joana d\\'Arc".size

You will get back 12. If both backslashes were there you should get 13.

Hauleth's answer should work.

like image 32
seph Avatar answered Sep 28 '22 05:09

seph