I have the parent model of user and user has_many :events. From the user view, how can I find the most recent datetime (event.time) of event?
I'm thinking that a find_by will work, but I'm not sure on how to do that.
Something like this.
user.events.find(:first, :order => "time DESC")
You can read more here:
http://api.rubyonrails.org/classes/ActiveRecord/Base.html#M001777
user.events.find(:all, :order => 'time desc', :limit => 100)
where limit is number of recent events you need or:
user.events.find(:first, :order => 'time desc')
if you need one most recent event.
user.events.find(:first, :order => 'time desc').time
like this you can get the event time
Just in case anyone stumbles upon this, the find first helper:
user.events.find(:first, :order => 'time desc').time
is now deprecated and removed as of Rails 3.2. You should use
user.events.order("time desc").first.try(:time)
instead.
Related
I am new to Rail and trying to make a query in ActiveRecord. I am trying to get all of the records with the status of 'Landed', that are over 60 days old. My query works up to the point of getting all of the projects with the status of 'Landed'. When I add in the last condition of "created_at < ? ", then I always get an empty relation. I know that I have projects that fit that description, so I am doing something wrong in my query and dont understand. I believe my error is in the date comparison, but I am not sure.
1. Projects
belongs_to :status
has_many :project_status_histories
2. Status
has_many :projects
has_many :project_status_histories
3. Project_Status_Histories
belongs_to :status
belongs_to :project
Project.find(:all, :joins => [:project_status_histories, :status], :conditions => {:projects => {:status_id => Status.where(:name => 'Landed').first.id }, :project_status_histories => {:created_at => ["created_at < ?", (Date.today - 60.days)]}})
I have tried to build the query, step by step, with the dbconsole and am not having any luck. Thanks for all the help in advance.
I don't think it's the date arithmetic. One nice way to do this would be with named scopes. Add the following to project.rb:
scope :landed, joins(:status).where('statuses.name' => 'Landed')
scope :recent, lambda \
{ joins(:project_status_histories) \
.where('project_status_histories.created_at < ?', Date.today - 60.days) }
Then you can retrieve the relevant records/objects with:
Project.landed.recent
This worked for me in my test. You should also check out the rails guide, from which I stole most of this:
http://guides.rubyonrails.org/active_record_querying.html#scopes
Your query is a little bit complicated...
I would rather do it like this:
Project.where("status.name = ? AND project_status_histories.created_at < ?", "Landed", Time.now.day - 60.days)
I think this should work better. Let me know if it doesn't, maybe I've wrote something wrong, unfortunately I can't test it right now...
[Edit]
You also might want to see what is the generated SQL, use the "explain" method for that, just add it to the end of your query and print the result, for instance with your query:
Project.find(:all, :joins => [:project_status_histories, :status], :conditions => {:projects => {:status_id => Status.where(:name => 'Landed').first.id }, :project_status_histories => {:created_at => ["created_at < ?", (Date.today - 60.days)]}}).explain
What I would like to find is all Events, where event.event_date is in the future, and only get the top 3 events sorted by how many Users the event has associated with it. Events and Users are joined by a HABTM relationship. Here's what I tried:
#popular_events = Event.where("event_date >= ?", Time.now)
.find(:all,
:joins => :users,
:group => 'event_id',
:order => "users.count DESC",
:limit => 10 )
I've tried a few other things with no luck. It is saying users.count is not a valid column.
believe it or not, this is a pain in the b*tt to do this with ActiveRecord. You will more or less have to rely on raw SQL to do it. Some answers here : http://www.tatvartha.com/2009/03/activerecord-group-by-count-and-joins/
For Example, I want to know the User have many posts. So, I can get back post using this :
#user.posts
but I don't want to get all the posts back. I would like to limite the result, for example, top ten created, or may be sorted by some column. How can I do so? Thank you.
You can always make a generic scope to handle the limit, such as putting this in an initializer:
class ActiveRecord::Base
named_scope :limit, lambda { |*limit| {
:limit => limit[0] || 10,
:offset => limit[1]
}}
end
This makes limiting queries easy:
# Default is limited to 10
#user.posts.limit
# Pass in a specific limit
#user.posts.limit(25)
# Pass in a specific limit and offset
#user.posts.limit(25, 25)
For something more robust, you might want to investigate will_paginate.
Try this:
#user.posts(:limit => 10, :order => "created_at DESC")
http://guides.rubyonrails.org/active_record_querying.html
You should take a look at the options available for the has_many association.
You could try something like this:
class User < ActiveRecord::Base
has_many :posts
has_many :top_ten_posts, { :class_name => "Post", :order => :some_rating_column, :limit => 10 }
end
Is there any way I can use the :limit and :order options in the find method. I'm trying to sort activities by descending order, such that the newest activities are shown. However, when I try to use the (:all, :limit => 5, :order=> 'Date desc) I get an error. I need to limit to only 5 records, and when I disregard the order option, it works but not what I need...
Thanks
I think you missed a quote in your example.
Model.find(:all, :limit => 5, :order=> 'created_at desc')
Make sure that a date column exists in your table.
Is your date column actually called date? First, I would change that, date is the name of a function in most databases, that could be the cause of the error you are seeing. Rails uses created_at, updated_at, etc, so following that naming scheme will make your code more readable to future maintainers.
You could try to quote the column name in back-ticks:
:order => "`date` desc"
My Account model has the following two associations:
has_many :expenses,
:order => 'expenses.dated_on DESC',
:dependent => :destroy
has_many :recent_expenses,
:class_name => 'Expense',
:conditions => "expenses.dated_on <= '#{Date.today}'",
:order => 'dated_on DESC',
:limit => 5
In one of my views I'm rendering recent expenses like so:
<% #account.recent_expenses.each do |expense| %>
...
<% end %>
On my development machine, on the staging server (which runs in production mode) and also on the production console, #account.recent_expenses returns the correct list. However, on our live production server, the most recent expenses are not returned.
If I replace #account.recent_expenses with #account.expenses in the view, the most recent expenses are displayed, so my guess is that the #{Date.today} part of the conditions clause is somehow being cached the first time it is executed. If I restart the production Mongrel cluster, all the latest expenses are returned correctly.
Can anyone think why this would occur and how might I change the :recent_expenses query to prevent this from happening?
I'm using Rails 2.1.0.
Rails is building the query when loaded and then will re-use that query every time you call #account.recent_expenses which is exactly what you're experiencing.
If you're using Rails 2.1 you can use named_scope to achieve what you're looking for.
in your Expense model, put the following:
named_scope :recent, lambda { {:conditions => ["expenses.dated_on <= ?", Date.today], :order => 'dated_on DESC', :limit => 5 } }
The lambda is used to ensure rails rebuilds the query each time.
from your Account remove:
has_many :recent_expenses ...
and then call:
<% #account.expenses.recent.each do |expense| %>
...
<% end %>
Like Andrew said, association macros are read at application startup, so any dynamic bits (like Date.today) are parsed at that point. His solution works if you're on Rails 2.1 or later; for earlier versions, you can use the has_finder gem, or just create the following method on the Expense model:
def self.recent
find(:all, :conditions => ['dated_on <= ?', Date.today], :limit => 5, :order => 'dated_on DESC')
end
Class methods like this are exposed to associations, and are properly scoped - the difference between them and named_scopes is that you can't chain them.
Here is what it would look like in Rails 3:
scope :recent, lambda { where("expenses.dated_on <= ?", Date.today).order('dated_on DESC').limit(5) }
WARNING: Watch out for chained scopes that are not wrapped in lambda. You may think that part of the chain is evaluated at runtime, but it may be evaluated at app server startup. Make sure you lambda wrap any scope that will use these other scopes. Explanation here:
http://www.slashdotdash.net/2010/09/25/rails-3-scopes-with-chaining/