execute sql query and loop through result set in rails - ruby-on-rails

In my rails app, i have the following function in one of my controller page.
def tree
#jstree = ActiveRecord::Base.connection.execute("Select sequence, depth, node, imageid, range from.....several joins")
end
I now want to loop through the resultset and display the sequence only in my view page tree.html.erb. I tried the following code, it does not seem to work.
<% #jstree.each do |tree| %>
<%= tree.sequence %>
<% end %>
I am getting the error message: undefined method 'sequence' for #<Array:0x60e0088>.
Is there a way of looping through the result set of the sql query executed and displaying each column value?
Many many thanks for all suggestion provided :)

Keeping the same syntax as the OP
<% #jstree.each do |tree| %>
<%= tree[0] %>
<% end %>
would accomplish what you were looking for.

You get this error because what you get in #jstree is a raw DB adapter result. If you want to query for some objects by issuing raw SQL queries then use find_by_sql. Example:
Client.find_by_sql("SELECT * FROM clients INNER JOIN orders ON clients.id = orders.client_id ORDER clients.created_at desc")

Related

Create an array with different sales created at the same time Ruby on Rails

Were trying to create an array grouping sales by the time they were created at and the person who made the sale.
Here's what we have so far:
#sales = Sales.select("date(created_at) as ordered_date").group("DATE_PART('hour', created_at)")
We have a table with sales that has a created_at field with a timestamp. It also has a client_id where we can make sure that we are grouping by the person that made the sale.
How can we create an array that works?
We're fairly new to rails so easy explanations are appreciated.
Using: Ruby on Rails 4, PostreSQL
Following is the snapshot of the error. The code on top is the index and the bottom is the error.
If you want to group all of your sales you should be able to do:
Sales.all.group(:client_id, :created_at)
Or if you're trying to group by :created_at and then :client_id just switch the order. Though just a note, I would not recommend grouping by :created_at since, unless your processing tons of transaction, you will rarely have the duplicate times. You don't need to write raw SQL since ActiveRecord handles the SQL query based on what adapter you have defined in you database file.
In my experience, doing the group as part of the find never really gives me what i want. It's generally better to get them all and then group them afterwards using Array#group_by. Then, in the group you have a series of arrays which you can iterate over. Something like this:
#in Sale model - convenience method
def created_at_hour
Time.at((self.created_at.to_f / 1.hour).round * 1.hour)
end
#controller
#grouped_sales = Sales.order(:created_at).group_by(&:created_at_hour)
#view
<% #the hash keys *should* be in time order but just in case, let's order them %>
<% #grouped_sales.keys.sort.each do |time| %>
<div class="sale-group">
<h3><%= time.strftime("%H:00, %d/%m/%Y") %></h3>
<% #grouped_sales[time].each do |sale| %>
<div class="sale">
<!-- sale html -->
</div>
<% end %>
</div>
<% end %>
EDIT - whoops, forgot to close a div :)

Is there a a clean way to avoid a double query when testing for an empty ActiveRecord result?

In an .html.erb file, it is quite natural to write something like this:
<% unless #results.empty? %>
<ul>
<% #results.each do |result| %>
<li>
<%= link_to result.name, '#' %>
</li>
<% end %>
</ul>
<% end %>
Where #results is the result of an ActiveRecord .all query. Unfortunately this generates two queries to the database: the first looking for a count of the results (the unless condition), the second to retrieve actual results. In this case the query is particularly expensive.
I could simply convert results to an array (which would buffer the entire result set), or put complex logic in the .erb
Neither solution seems to fit the Rails/ActiveRecord design philosophy.
Is there a better way to eliminate the duplicate query?
Rails tries to be smart and not load a whole association/relation when it doesn't need it. As a result some methods on relations or associations look like their counterpart from Enumerable but will instead run some sql if the association is not loaded. first, any?, include? are examples of this.
The easiest way, when you know that this is a case when this optimisation is not paying off is to force the relation to be loaded. You could do this by converting to an array to_a but you might as well be more direct.
#results = Foo.where(...).load
This is also keeps #results as a relation rather than converting to an array.

How does the query method #group work?

I'm learning rails and have been trying to read through documentation, but I just don't get how #group
works.
The documentation says that it: "Returns an array with distinct records based on the group attribute".
How do you then retrieve the records that belong to a certain group?
Say I want to group Articles by the month in which they were created? How would I do that?
The group method is generally used with the select method to do aggregating queries. For instance, if you wanted to count your articles by month, you could do this:
by_month = Article.group(:month).select("month", "COUNT(*) as count")
In this case, COUNT is the SQL aggregate function that counts rows, and we're putting the count result into an output column called "count".
Note: This assumes you have a column called "month". Of course you can do SQL here, so you might have, e.g. MONTH(created_at) instead, or whatever makes sense in your case.
You could then do this to output the month and its associated article count:
by_month.each do |row|
puts "Month #{row.month}: #{row.count}"
end
This probably seems mysterious because your model has no column "count", but that's the way select works: It defines new output columns for the query on the fly, and ActiveRecord happily maps those for you in the resulting instance objects.
This kind of query is dramatically more efficient than loading all the records and counting them yourself because you're letting the database do the heavy data work, and that's what it's good at.
It is perfectly legal to use group without select but the result is not usually what you want. If you group your articles by month, you'll get one object in the result for each month. The columns available in each object vary by database back end, but in MySQL they will have the values from the "first" row encountered for each group. If you aren't sorting, "first" is essentially undefined.
If by "group Articles by the month in which they were created" you mean you want this kind of grouping on a web page result, then you'll have to do it yourself, e.g.:
<% last_month = nil %>
<% #articles.each do |article| %>
<% if last_month != article.month %>
<h2><%= article.month %></h2>
<% last_month = article.month %>
<% end %>
# [output the article]
<% end %>
If you do something like this, you'll need to be sure #articles is ordered by month.

Rails shows rows from model, which aren't created

I have this part of code:
<% current_user.meta_accounts.each do |meta_account| %>
<%= content_tag(:li, link_to(meta_account.name, 'javascript:void(0)')) %>
<% end %>
So, I want Rails to show all my MetaAccounts in list, but I get this:
<li>Wallet</li>
<li>Credit card</li>
<li>Debit card</li>
<li>Debts</li>
<li>javascript:void(0)</li> #This is the problem
So, it also shows me MetaAccount, which isn't created yet.
In my MetaAccounts table I have this. I'm using Postgres.
So, it also shows me the last row, where row_number is *. I don't know why, and how to avoid this.
Thanks for any help!
Try:
<% current_user.meta_accounts.select(&:persisted?).each do |meta_account| %>
<%= content_tag(:li, link_to(meta_account.name, 'javascript:void(0)')) %>
<% end %>
The * row you see in PostgreSQL is not an actual record, it's just a quick way to create new records. If you want to be sure, run the following query:
SELECT COUNT(*) FROM MetaAccounts WHERE user_id=1
It will return 4.
I think the problem comes from an unsaved MetaAccount object in current_user.meta_accounts. This could be the case for instance in a form, where you build an empty object bound to the form. Make sure you don't have a call to current_user.meta_accounts.build(...).
If so, you can simply skip in your each loop all MetaAccount objects with a blank name.

Get distinct values from table

I am trying to get distinct value from this controller. But I am not sure how to succeed.
Here the controller I have try this
#count = Present.where('event_id > ?', params[:id]).uniq.pluck(:customer_id)
But when I try to do this in my view
<% #count.each do | co | %>
<%= co.customer_id %>
<% end %>
I keep having this issues
Cannot visit Arel::Nodes::Distinct
I want to be able to preserve all Present Objects with the event_id equal to the id, but also being able to select only the one with distinct customer_id.
Update: after restarting the server i get the following error
undefined method `customer_id' for 1:Fixnum
Maybe you need to restart your rails server: https://github.com/rails/rails/issues/7399
Previous similar SO question
Update:
From the docs: When using pluck, "The values has same data type as column"
Change loop to:
<% #count.each %> do |i|
<%= i %>
<% end %>

Resources