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.
Related
I want to display reports that meet criteria and display them in a particular order.
Sort by user, then by report creation date of the report, newest on top
#report_results.order('created_at DESC, user_id')
Above is the code I use, however, when the data is displayed, toward the end of each user's reports, they start to show up out of order.
How do I Fix this?
View:
<% #report_results.order('created_at DESC, user_id').each do |report| %>
You could do:
variable = report_results.order('created_at DESC')
#report_results = variable.group_by(&:user_id)
This should return a hash of user_id with the respective reports ordered.
<% #report_results.order('user_id').order('created_at DESC').each do |report| %>
Not sure why this works, I thought the last order command would overwrite the previous, but it seems like it retains it.
Items now show up grouped by user_id, in descending chronological order.
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 general pattern that is recommended for building a "summary detail" type view? Say for example, you have an invoicing app with a reporting view that needs to list headings for every customer with a detail of every open invoice for that customer under the heading.
Here's how I've attempted to deal with it in the past (using the customer/invoice example), none of which has been very satisfactory:
Method #1:
Create a join query which joins the customer details with the invoice. In the view loop over the collection using an instance variable to keep track of the customer being looped over. Have a conditional in the loop code that compares the current iteration's customer with the last interation's customer. If they are different, add in a heading for the new customer.
Method #2:
Query for customers with an open invoice, then in the view iterate over the customers and nested the customer iteration, do another iteration over that customer's open invoices, e.g:
<% #customers.each do |customer| %>
<%= customer.name %>
<% customer.invoices.open.each do |invoice| %>
<%= invoice.details %>
<% end %>
<% end %>
So, yeah. Neither one of these feels great. Method #1 seems like a hack and Method #2 seems like it would generate too many queries though its the most readable in the code.
Looks like a classical case to use ActiveRecord includes option
http://apidock.com/rails/ActiveRecord/QueryMethods/includes
so in your controller where to find customers
Customer.includes(:invoices).where('customer.name = ?', 'example')
I would like to have a link that only displays the last 10 database submissions with a select number of tables per submission. Hope that makes sense. So in short a can click 'recent submissions' and it will display the last 10 via customer name, submission date, and id number . Currently in the controller i have the following just to test the link but of course it display every table.
<h2>LAST 10 SUBMISSIONS</h2>
<%= #posts.each do |post| %>
<%end%>
Sorry, this is more of a comment than an answer but I don't have enough rep to leave a comment.
You could retrieve a bunch of #posts, which will be an array of ActiveRecord Relations. That means you can use Ruby's nifty Array methods. Here's an example:
#sorted_posts = #posts.sort_by { |p| p.created_at }.take(20)
And then pass in #sorted_posts where you currently have #posts in the code you posted above. But for performance and good practice you should probably retrieve that data in the proper format from the query itself.
#last_twenty_posts = Post.order("created_at DESC").limit(20) # limit by whatever number you want
Hope that helps!
You can simply order the posts by some attribute specifying the submission time (e.g., created_on) and limit the results to a number you want. For example:
Post.order("created_on DESC").limit(10)
This would return the last 10 Post objects based on their created_on attribute, with the newest first.
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")