Is there a better way to write this Rails model code?

0 views
Skip to first unread message

Michael Dippery

unread,
Dec 13, 2009, 4:16:41 PM12/13/09
to techva...@googlegroups.com
I am working on an application that contains two models: Machine and MachineUpdate. A Machine has_many :machine_updates. The MachineUpdate class has a date field.

I want to find all Machines that do not have a MachineUpdate record for more than 2 weeks. Currently, I am using the following method on the Machine class to do so:

  def self.machines_to_check
    updates = MachineUpdate.find(:all, :conditions => "date < '#{UPDATE_THRESHOLD.days.ago}'")
    return nil unless updates.length > 0
    machines = []
    updates.each { |u| machines << u.machine }
    machines.uniq
  end

However, since a Machine is already connected to its updates via its machine_updates attribute, I wonder if there's a better way to do this? Also, the method doesn't work 100% correctly, as it won't find Machines that have had no updates (these machines should also be returned by the method).

Can anyone offer suggestions on how to clean this up?


Thanks,
-- Michael

Nick Quaranto

unread,
Dec 13, 2009, 4:33:43 PM12/13/09
to techva...@googlegroups.com
You could make a named scope for this...

class MachineUpdate
  named_scope :past, { :conditions => ["date < ?", UPDATE_THRESHOLD.days.ago] }
end

Then you should be able to do something like:  Machine.first.machine_updates.past

Definitely look more into named scopes if you haven't yet: http://api.rubyonrails.org/classes/ActiveRecord/NamedScope/ClassMethods.html

--

You received this message because you are subscribed to the Google Groups "TechValley Ruby Brigade" group.
To post to this group, send email to techva...@googlegroups.com.
To unsubscribe from this group, send email to techvalleyrb...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/techvalleyrb?hl=en.

Nathan Fixler

unread,
Dec 13, 2009, 4:48:03 PM12/13/09
to techva...@googlegroups.com
A named scope on the Machine class could definitely do it.

class Machine < ActiveRecord::Base
  has_many :machine_updates
  named_scope :with_updates, :include => :machine_updates, 
    :conditions => ["machine_updates.date < ?",UPDATE_THRESHOLD.days.ago]
end

Then just call Machine.with_updates.  Fewer SQL queries, and it returns an empty array instead of nil if there are no updates (as would be my preference).

Marnen Laibow-Koser

unread,
Dec 13, 2009, 5:08:21 PM12/13/09
to techva...@googlegroups.com
You're doing in the application something that should be done in the DB.  Also, some databases choke on "date" as a field name, and anyway, you should perhaps consider Rails' _at or _on magic...

Anyway, for your query...in SQL, what you want is this:

SELECT * FROM machines m LEFT JOIN machine_updates u ON (u.machine_id = m.id)
WHERE u.date > {cutoff date} AND u.machine_id IS NULL

(I know that looks self-contradictory, but that's really how left joins work...)

You could also use count(*) and HAVING, which might possibly be faster if you don't care about the individual dates. 

Turning these into AR finds is left as an exercise... :)


Can anyone offer suggestions on how to clean this up?


Thanks,
-- Michael


Best,
-- 
Marnen Laibow-Koser

scott stewart

unread,
Dec 14, 2009, 6:56:51 AM12/14/09
to TechValley Ruby Brigade
+1 for the named_scope suggestion (Nathan)

On Dec 13, 5:08 pm, Marnen Laibow-Koser <mar...@marnen.org> wrote:

Michael Dippery

unread,
Dec 15, 2009, 10:07:36 AM12/15/09
to techva...@googlegroups.com
Thanks for the tips about named_scopes — didn’t know anything about them, and not only did they do the trick in this case, but I also managed to find a couple other uses for them in my app that have simplified the code a bit. Mucho gracias!


— Michael
Reply all
Reply to author
Forward
0 new messages