Model.find_by_sql vs connection.query, which one is better? - ruby-on-rails

In rails-
I need to execute a sql query against the database; the query is not related to any specific Model it can have mix data from multiple tables or from some other table. I have ways to do this=-
first is by executing query agains Model and capture the result like this-
res=User.find_by_sql("select * from customers joins and conditions")
res=User.find_by_sql("select * from [other table] joins and conditions")
Problem with this approach, I am not feeling comfortable with it because in User class objects I am capturing data of other table. like the first query result has data from customer table so in the user object I got customer's attribute. And more interesting problem is- if the resulting query has id attribute then
res.first.id will be id of customer and
if User model has relation with UserRoles model and if I access this relation with res.first.roles then it will fetch roles from UserRole for customer id, which is completely wrong.
And there might be may problems also.
So I think it has lot of chaos.
And good part is we dont not need to deal with connection and result would be an array of objects. so accessing object attributes with res.first.id is easier the hast like row["id"].
and second approach to use ActiveRecord connection and execute the query like
this res = ActiveRecord::Base.connection.query("sql query")
in place of query we can use select_one, select_all and can also make query parameterized.
The problem it has is it returns array of hash, but I need array of objects for easy accessibility in code. So I wrote a class to convert hash to object (I think rail does same thing in background) and is working fine.
So I need some suggestion on both the approach and need to decide which one is better.

First find_by_sql vs select_all
find_by_sql, This method returns an array of objects by initiating them.
users = User.find_by_sql("SELECT * FROM users"); #=> [#, #, #, # ....]
Accessing properties
users[0].name #Getting property in object oriented fashion
select_all, This method returns an array of objects but does not initiate them, and each object represents a row of database.
users = User.connection.select_all("SELECT * FROM users"); #=> #
Accessing properties
users[0]["name"] #Getting property in non-object oriented fashion
Whether find_by_sql is better, because of it is a simple way of custom querying to the database and returns instantiated objects

Related

Generic find_by_sql with typecasts without model methods

I want to run an arbitrary query against my database. For now I always resort to find_by_sql to make sure the results are converted into the proper type. The drawback of this method is that sometimes the Rails models have methods associated. If the fields returned by the find_by_sql method are present in the model, the methods of the model are used.
The alternative is to use ActiveRecord::Base.connection.execute or Model.connection.execute. Hover the results returned by that method are not properly mapped to ruby objects. For instance DateTime objects are returned as strings, not as real ruby objects.
How would you do it?
You can use find_by_sql but get real database by calling [:colum_name] instead of .column_name.
Example:
q = Question.find_by_sql('select * from questions limit 1').first
q.title
=> "1"
q[:title]
=> "How to convert MagicaVoxel to vector?"

Rails - Get records of a specific id and store it in an Array

How do I get records from a table with a specific ID and store these records in an Array?
For better understanding I try to explain it to you more clear:
Imagine a table with the following columns: (ID,FIX_ID,AMOUNT)
where ID is an unique ID which always will auto_incremented by 1.
FIX_ID is an ID which can appear multiple times in the table.
And AMOUNT is just a simple type which represents the amount of some "things".
So all I want to get now is every record from the table which have the FIX_ID that I am looking for.
Remember: The FIX_ID is not unique => it can appear multiple times.
And that's it. So imagine that I want to get all records with the FIX_ID of 10. All these records which I will get should be stored in an Array.
My question to you: Is it possible to realize this "request" to the database with ActiveRecord?
If so, then how?
You can get an ActiveRecord::Relation object like this:
ModelName.where('FIX_ID = ?', 10)
Relation object will perform a database query as soon as you call methods like all, each or any? on it. If you really need an array, call to_a on that Relation:
ModelName.where('FIX_ID = ?', 10).to_a

What's the best way to create a model associated to a query instead of a table

I'm trying to create a reporting app with Rails 4.
As a reporting system, it has a lot of SQL queries where the result is not like any table schema. I mean, a select query where I have some joins, unions and etc and the result will be something like a row with it's columns being result of subqueries, sums and etc.
Would it be possible to have a Model with no table associated, but I can use the "find_by_sql" on it, to instanciate an array of that model with the results of my query?
Something like:
Use "select table1.field1, sum(if(...,table2.field,...) as field2, as field3 from...." as query, and return a array of a model "Result", where I can call a
array_of_result.first.field3?
Sorry if I'm not writing clearly enough.
EDIT: until now, sparky's anwser(http://railscasts.com/episodes/193-tableless-model) was the closest one, beacuse I want to use some of the ActiveRecord features, like specify a connection in the class(or even in a super class).
For pure reporting, especially when the result column names span multiple models, one alternative is to just pass the query directly back and deal with the result set:
ActiveRecord::Base.connection.execute([raw SQL query])
You'll get back a result set, which is typically an enumerable set of row results, but check the documentation for your DB adapter to find out for sure what it's returning.
For example, if you're using PostgreSQL as your database with the pg gem, you'll get back an instance of PG::Result which you can then operate on in the following way:
> results = ActiveRecord::Base.connection.execute("SELECT COUNT(*) FROM customers")
=> <PG:Result >
> results.count
=> 63 # the number of customers I have in this contrived example
> results.first
=> { "count": "63" }
> results[0]
=> { "count": "63" }
> results[0]["count"]
=> "63"
You'll need to cast your return values to something other than strings. ActiveRecord will typically do this for you in your models since it knows the column types, but by doing a raw query you'll probably just get back strings that you'll have to cast yourself. If you're just doing a query to display it on a page somewhere maybe the strings will be sufficient.
I'm sure you'll be doing more sophisticated reports, but you'll notice in my simple example that the key count wound up being created as the accessor to the result of the SELECT COUNT... query. If you specify column names, or alias them, the keys in the resulting hash set will match the column names or the aliases you've set.
You can certainly create a Reporting model.
You would want to start off by creating a tableless model. Essentially, this can be as simple as a file in your models directory with
class Reporting
end
in it, and a controller with some appropriate actions and views. However, have a look at
http://railscasts.com/episodes/193-tableless-model
http://railscasts.com/episodes/219-active-model
which cover tableless models and what you can do with active model with respect to validations etc.
In your case, you say that you have some complex joins etc. Sometimes it's easier in the short term to SQLize these, but if you can use activerecord you should. Apart from anything else, this will allow you to define custom methods in your model which you can chain and make your Reporting controller much cleaner

RAILS: fill Object from Array

Array is filled from query using arbitrary SQL statement
#myarray = myObject.find_by_sql(sql)
SQL is designed in such way that each myarray item has same fields as myObject Model, e.g.
\#{myObject value: 100, day: 2013-06-15}
Ideally, I would like to have array of myObjects
Filled with data from Array;
Accessible for html;
Not saved to the database.
Is it at all possible?
From docs for ActiveRecord::Querying#find_by_sql:
Executes a custom SQL query against your database and returns all the results. The results will be returned as an array with columns requested encapsulated as attributes of the model you call this method from. If you call Product.find_by_sql then the results will be returned in a Product object with the attributes you specified in the SQL query.
So I don't really understand your question. AR will try to map fields returned from query to object fields.
It is accessible in views if you assign it to object variable.
Records never got saved unless you execute one of the methods that perform save.
EDIT:
Remember that AR will not be able to map resultset to records unless you return id column.

rails query serializable object

How do I query the database to find objects that contain one or more attributes that are stored as serializable?
For example, I have a concert which occurs only in certain cities. I want to make a Concert object with a column called cities and store an array of cities.
If I want to query my database to find all concerts that occur in 1 city (or all concerts that occur in an array of n cities), how do I do this?
The best way to do this isn't to store it in a serialized column, but a separate table called Cities. Then you can do this:
City.find_by_name('Cityname').concerts
One possible way to query would be to use SQL's LIKE condition. This would work for boolean conditions in serialized tables.
For example to find those Users with the 'notification' option on,
users=User.arel_table
User.where(users[:options].matches("%notification: true%"))
As for other type of variables this would not be as feasible.

Resources