Prepared statements in ruby/rails with postgres - ruby-on-rails

I want to execute a rather nasty recursive update query in rails. This means I want to write some raw postgres sql, with parameters, and execute it inside a rails controller.
How do I do that? I can't find a PreparedStatement class in activerecord, there don't seem to be any methods named 'native', I have tried ActiveRecord::Base.connection.exec_delete, I have looked through the source - just cannot, cannot work it out.
I've looked everywhere - the documentation goes in circles.
How would I tell postgres to execute
delete from foo where foo.bar=?
bind 'baz' to the q-mark, and do it without using the active record objects, finders, you-beaut subset thingies and all the rest.
I just want to execute a prepared statement with some bindings. How hard can it be?
(PS, and no: I don't want to jam the parameters into the string myself and execute it as unparameterised sql. It's wrong and it means I have to worry about sanitising the data.)

See the discussion of PreparedStatements in Rails ('Using Prepared Statements') here - http://blog.daniel-azuma.com/archives/216 . Shows you which methods to call, and how to format your arguments.
UPDATE:
Paraphrased from the post:
For the delete method arguments use the template first, followed by a query name (which can be nil) and then an array of values to inject into the statement. So like this:
row_count = connection.delete("DELETE FROM foo WHERE foo.bar=$1", nil, [[nil, 'baz']])

Related

Ruby on Rails - using a block parameter as a method call

I'm having trouble with a little Ruby on Rails I'm building and need some help.
I have a Table with 20+ Columns and a corresponding XML File which can be parsed as some sort of hash with a gem. Every key would be mapped to a column and every value would be a data record in said column.
The way I access a specific value in the already parsed XML file is:
filename["crs","inputkeyhere"]
which returns the value, for example "52" or whatever.
What I am trying to do is upload the file, parse it with the gem and give each column the corresponding value.
My table (or model) is called "Attributeset" and I already know how I can access every column:
#attributeset = Attributeset.new
#attributeset.attributes.keys
So my thought process was:
Iterate over all the keys
Pass every key into a block called |a|
Use the rails possibilty to set attributes by calling the corresponding #attributeset.
Set colum attribute to the corresponding xml key
So my code would go something like this:
#attributeset.attributes.keys.each do |a|
#attributeset.a=filename["crs",a]
end
But my problem is, that ruby thinks ".a" is a method and apparently does not evaluate "a" to the block parameter.
I've read through lambdas and procs and whatnot but didn't really understand how they could work for my specific situation.
Coming from bash scripting maybe my thinking might be wrong but I thought that the .a might get evaluated.
I know I can run the block with yield, but this only works in methods as far as I know..
Any help is appreciated.
Thanks and stay healthy,
Alex
Thanks for the input!
I wanted to make it as clean as possible, and not using any temporary hashes to pass arguments.
I've found the method
write_attribute
which can be used like this:
#attributeset.write_attribute(a, xmp["crs",a])
worked perfectly for me.
You can use []= method to set values dynamically:
#attributeset.attribute_names.each do |attribute|
#attributeset[attribute] = filename["crs", attribute]
end

Ruby on Rails build query in pieces

There was a very similar question before but i still struggle.
Is it possible to build a query up in stages?
Let's say I have a search form with many text and select fields that may be chained with and/or or which could be blank.
So the sql statement should consist of several parts that are connected individually for each search.
I tried to create strings for every option and put them to a symbol? (i mean #options) and put that in the where clause (e.g. Product.where(#options) ). That works somehow but i have got troubles with this part: 'params[:query]' when it's in quotes. Either my sql statement says 'select products from products where (name like params[:query]') or if i try #{params[:query]} it says: select products from products (where 'name' like ''.)
So how can i chain different parts of a query?
I looking forward to your answers!
Never, ever, ever embed raw strings in your SQL. This is extremely bad form. You should always use the escaping mechanism provided by Rails or something equivalent to avoid ending up in serious trouble. Inserting content from params is very dangerous and should never be done as it only takes this to nuke your app: { :query => '\"-- DROP TABLE users;' }
Generally you use the helper methods provided by ActiveRecord to build up your query in stages:
scope = Product
if (params[:query].present?)
scope = scope.where([ 'name LIKE ?', "%#{params[:query]}%" ])
end
if (params[:example].present?)
scope = scope.where(:example => true)
end
#products = scope.all
You can build it up in stages like this, modifying the scope in-place each time, and then execute the final call to retrieve it. Generally that's when you use your paginator to split up the results.
It's okay to put pretty much anything in your options because it should be escaped by the time it hits the SQL phase, much as anything on the HTML side is escaped for you as well.
Don't confuse instance variables like #options with a symbol like :query. The two are very different things. Instance variables have the benefit of propagating to your view automatically, so they are often used extensively in controllers. Views should avoid modifying them whenever possible as a matter of style.

Iterating through array of Models in rails

Yet another ruby question but this is a bunch of questions in one. I'm really starting to like rails but there are some questions that I'd just like to ask straight out.
Right now, I'm implementing a queue in sqlite. I already have a scaffold setup with this working OK. The purpose is for a web crawler to read through the array and determine which links he should crawl next.
The architecture in the program is 2 controllers. one for Job and one for crawler. The Jobs has the standard Crud interface supplied by scaffold. Where I'm falling down is I'm still trying to understand how these things communicate with eachother.
The Job is formatted as a url:string and depth:decimal. The table is already populated with about 4 objects.
#sitesToCrawl = Job.all
#sitesToCrawl.each {|x|puts Job.url}
I have a bunch of questions about the above.
At the moment, this was supposed to display all the jobs and I foolishly thought it would display plain text but its actually a hexidecimal pointer to the object itself. What Im trying to do is iterate through the #sitesToCrawl and put out each Jobs url.
Questions start here:
1: I know ruby is dynamically typed. Will #sitesToCrawl become an array like i want it to be with each slot containing a job.
2: #sitesToCrawl.each is pretty straighforward and I'm assuming its an iterator.
is X the name od the method or what is the purpose of the symbol or string between |*|
3: Puts and print are more or less the same yes? if i say #x = puts 3 then would x be 3?
4: Job.url. Can objects be referenced this way or should I be using
##sitesToCrawl = db.execute("SELECT url FROM jobs;")
where db is a new database
As Rubish Gupta pointed out, in your block, you should do x.url, otherwise you're trying to access the url method on the class Job, not on instances of Job. In other words, in blocks, the items in the pipes are the arguments of the block, and each will iterate through your array, passing in one item at a time to your block. Check out the doc here.
Just to extend this idea, each on Hashes (associative arrays, maps, whatever you know them as) will pass two variables to your block: a key and a value, like this:
a_hash.each {|key_var, val_var| puts "#{key_var} is associated with #{val_var}"}
Also, it's been a bit since I've done plain ActiveRecord models, but you might look into doing
#sitesToCrawl = Job.all.to_a
since Job.all is a lazy finder in that it's building a query in potentia: you've essentially built a query string saying SELECT * FROM jobs, but it might not be executed until you try to access the items. each might do that, I can't remember off the top of my head, but if you're using a debugger to look at it, I know you need to_a to get it to run the query.
You should absolutely be using job_instance.url - that's the beauty of ActiveRecord, it makes database access easy, provided everything gets set up right :)
Finally, puts and print are almost the same - the difference is that puts "string" is essentialy print "sting"; STDOUT.flush - it flushes at the end of the statement.

Does ActiveRecord::Base.connection.execute only execute a single statement at a time?

I have a bunch of SQL statements to execute on a database. (I'm doing things that Rails doesn't provide methods for, as far as I know: creating views, adding foreign keys, etc. It's mostly for non-Rails interaction with the data.) In essence, I'm doing the following:
sql = "statement_1; statement_2; statement_3; etc;"
ActiveRecord::Base.connection.execute(sql)
Or with newlines, like so:
sql = <<EOF
statement_1;
statement_2;
statement_3;
etc;
EOF
ActiveRecord::Base.connection.execute(sql)
(Obviously, these statements are just place holders, but I don't think their content matters, according to my tests.)
In either case, only the first statement is executed and the others seem to be ignored. Is that what's going on? I'm only seeing the effects of the first statement whenever I try more than one at a time. Do I need to execute each one separately? One set of statements is coming from a file, so it'd be nice to just load the contents of the file and execute. If there are better strategies I could adopt, I'd be interested in them.
I was hoping the documentation on execute would shed some light, but besides using the singular ("statement"), it doesn't. Perhaps it's because of the database engine I'm using? (For reference, I'm using SQLite at the moment.)
UPDATE: I ended up writing a method that does the following:
def extract_sql_statements(sql)
statements = []
sql.split(';').each do |statement|
statement.strip!
unless statement.empty?
statement += ';'
statements << statement
end
end
return statements
end
...and then looping over statements. It's fixed the problem, but if there are more elegant solutions, I would be interested in hearing about them.
If you look at the rails code then you will find that execute method runs the passed sql, so it should essentially run all your queries as long as they are ';' separated and valid.
EDIT: Sorry! No it won't because it will add ';' in between your query string and complain about wrong syntax

Sanitizing data at active record

I want to sanitize the data coming from my form in ActiveRecord. Especially the apostrophe before its actually included into the SQL query. I want it to be something raghu'\s if raghu's is been inputed. I have already tried using:
sanitize_sql_array
sanitize_sql_for_assignment
sanitize_sql_for_conditions
sanitize_sql_hash_for_assignment
sanitize_sql_hash_for_conditions
But none of these seem to escape the apostrophe there by failing my SQL query.
Rails will handle a lot of the santizing for you if you use the following format for performing finds. It'll run the necessary sub methods to ensure that nothing potentially destructive is inserted into the database. Not sure about the single inverted comma, but it's worth a shot.
Model.find(:all, :condition => ["text_value = ?", params[:form_input])
You might want to have a look at this thread - Strip & Sanitize BEFORE saving data from the Ruby Forum - I haven't tried any of the solutions mentioned but it might get you going in the right direction

Resources