Rails 4 AR `from` different than rails 3? - sql

In rails 3 if I write: Model.from('models') arel generates the following sql:
select "models".* from models
In rails 4 the same arel generates the following sql:
select "models".* from 'models', NULL
The table name is wrapped in quotes and ', NULL' is appended. How do I use arel to give me the same results as in rails 3?
I was leveraging the original behavior so I could run a fairly complex with recursive query against postgres. In rails4, postgres is choking when it gets to the single quote preceding value I give from.
Is there a better way to do a with recursive query? Or, is there a way to query with arel so it works as before?

This appears to be an incompatibility with the squeel gem (the master branch as of today).
EDIT I've sent a pull request to squeel's master branch. Fixes the issue for me.
EDIT 2: Merged into master

Related

How to make SQL query in ActiveRecord using alias for the table?

I want to make such a query for my Services ActiveRecord in Rails:
SELECT *
FROM "services" AS s
WHERE /* part using 's' alias */
Normally I'd write just Service.where(/* where part */), but I need to set my alias.
I tried to run ActiveRecord::Base.connection.execute(query), but result of that is not recognized as Service.
How can I handle it?
To use a table alias combine the select method with from:
Service.select("s.*").from("services s")
Which generates this SQL:
SELECT s.* FROM services s
And it returns an ActiveRecord::Relation which you can refine as needed.
Fortunately I found solution during writing this question. Service.find_by_sql(query) works well in my case.

Raills: Get SQL generated by delete_all

I'm not particularly familiar with Ruby on Rails, but I'm troubleshooting an issue we're experiencing with a rake job that is supposed to be cleaning database tables. The tables grow very large very quickly, and the query generated by ActiveRecord doesn't seem to be efficient enough to handle it.
The Ruby calls looks like this:
Source.where("id not IN (#{Log.select('DISTINCT source_id').to_sql})").delete_all
and this:
Log.joins(:report).where(:report_id => Report.where(cond)).delete_all
I'm trying to get at the SQL, so we can have our DBA's attempt to optimize it better. I've noticed if I drop the ".delete_all" I can add a ".to_sql" which gives me the SELECT statement of the query, prior to the call to ".delete_all". I'd like to see what SQL is being generated by that delete_all method though.
Is there a way to do that?
Another option is to use raw Arel syntax, similar to a simplified version of what ActiveRecord::Relation#delete_all does.
relation = Model.where(...)
arel = relation.arel
stmt = Arel::DeleteManager.new
stmt.from(arel.join_sources.empty? ? Model.arel_table : arel.source)
stmt.wheres = arel.constraints
sql = Model.connection.to_sql(stmt, relation.bound_attributes)
print sql
This will give you the generated delete sql. Here's an example using postgres as the sql adapter
relation = User.where('email ilike ?', '%#gmail.com')
arel = relation.arel
stmt = Arel::DeleteManager.new
stmt.from(arel.join_sources.empty? ? User.arel_table : arel.source)
stmt.wheres = arel.constraints
sql = User.connection.to_sql(stmt, relation.bound_attributes)
=> DELETE FROM "users" WHERE (email ilike '%#gmail.com')
From the fine manual:
delete_all(conditions = nil)
Deletes the records matching conditions without instantiating the records first, and hence not calling the destroy method nor invoking callbacks. This is a single SQL DELETE statement that goes straight to the database, much more efficient than destroy_all.
So a Model.delete_all(conditions) ends up as
delete from models where conditions
When you say Model.where(...).delete_all, the conditions for the delete_all come from the where calls so these are the same:
Model.delete_all(conditions)
Model.where(conditions).delete_all
Applying that to your case:
Source.where("id not IN (#{Log.select('DISTINCT source_id').to_sql})").delete_all
you should see that you're running:
delete from sources
where id not in (
select distinct source_id
from logs
)
If you run your code in a development console you should see the SQL in the console or the Rails logs but it will be as above.
As far as optimization goes, my first step would be to drop the DISTINCT. DISTINCT usually isn't cheap and IN doesn't care about duplicates anyway so not in (select distinct ...) is probably pointless busy work. Then maybe an index on source_id would help, the query optimizer might be able to slurp the source_id list straight out of the index without having to do a table scan to find them. Of course, query optimization is a bit of a dark art so these simple steps may or may not work.
ActiveRecord::Base.logger = Logger.new(STDOUT) should show you all the SQL generated by rails on your console.

Protecting against SQL injection in Rails

I'm trying to sort some records in rails and I'm passing something like created_at DESC as the param, and was wondering -- is the SQL properly escaped by ActiveRecord, or is this a bad way of doing it? I tried substituting with ? like I normally do with strings, but though I could get it to work in SQLite, PG threw an error.
Here's what I'm doing that works -- but wondering if it's safe?
if params[:by]
#photos = Photo.find(:all, :order => params[:by])
else
...
If you use the Active Record Query Interface like you did above, Rails will perform the SQL sanitization. See http://guides.rubyonrails.org/active_record_querying.html

How can I import a SQL file into a Rails database?

I've got a .sql file that I'd like to load into my Rails database using a Rake task. How can I do this?
The easiest way:
bundle exec rails db < $SQL_FILE
example:
bundle exec rails db < my_db.sql
The Easy Way
This works for simple cases.
ActiveRecord::Base.connection.execute(IO.read("path/to/file"))
Solution found on the Ruby On Rails mailing list from 2006 (but still works in 2011 on Rails 3.1).
Footnotes
This related question implied this solution, but rejected it for big imports. I wanted to show it explicitly, since it works for smaller ones.
The file I was trying to import contained a LOCK TABLES followed by an insert. The data was for a MySQL database. Mysql2 said it had an invalid SQL syntax error until I removed the lock and unlock statements.
On MySQL this gave me a syntax error. Splitting the sql into statements made it work.
sql = File.read(sql_file)
statements = sql.split(/;$/)
statements.pop # remove empty line
ActiveRecord::Base.transaction do
statements.each do |statement|
connection.execute(statement)
end
end

Formula after switching to NHibernate 3.2

I use this formula in NHibernate 3.1 :
.Formula("(SELECT b.Name FROM AdaptiveObjectModel.EntityType AS b WHERE (Structure = b.EntityTypeId))")
but after switching to NHibernate 3.2 receive this problem:
ambiguous column name Structure
The error comes from SQLserver, there are at least 2 tables with the column Structure. SQLserver does not know which one to chose. I guess that something changed in the way NHibernate interprets your query, and now sends all sql at once. Have a look in the logging or your profiler to see what the sql is your are sending to SQLserver. Then you can add the right alias before Structure.