开发者

Rails 3: How can I find an object with no children in it

开发者 https://www.devze.com 2023-03-28 06:02 出处:网络
I have a 3 models class Task < ActiveRecord::Base belongs_to :user, :dependent => :destroy has_many :clock_ins

I have a 3 models

class Task < ActiveRecord::Base
  belongs_to :user, :dependent => :destroy
  has_many :clock_ins

  accepts_nested_attributes_for :clock_ins, :allow_destroy => true
end

class ClockIn < ActiveRecord::Base
  belongs_to :task, :dependent => :destroy
  has_one :clock_out
end

class ClockOut < ActiveRecord::Base
  belongs_to :clock_in, :dependent => :destroy
end

Currently I can create a ClockIn for each Task.

When I start a new ClockIn, I want to create a ClockOut for whichever Task is c开发者_开发问答urrently open.

How do I search my tasks for one with a ClockIn that does not have a ClockOut?


Solution

  • Combine Models

  • Fix destroys

  • Iterate all tasks then update task.clocks.where(:clock_out => nil).first.update_attribute :clock_out, Time.now


As you have a one-to-one relation between clock_in and clock_out, switching has_one and belongs_to shouldn't make much difference. What is the data stored in clock_in and clock_out? if is is just a datetime you might want to consider merging the two models and using a single table. If you do not want to change any of the modeling LEFT OUTER JOIN is the way to go. So you have three options:

  • Merge the models:

    class Task < ActiveRecord::Base
      belongs_to :user
      has_many :working_hours
    
      accepts_nested_attributes_for :working_hours, :allow_destroy => true
    end
    
    class WorkingHour < ActiveRecord::Base
      belongs_to :task
    
      # has two columns clock_in_time and clock_out_time
    end
    
    task.working_hours.where(:clock_out_time => nil).first.update_attribute(:clock_out_time => Time.now)
    
  • Switch has_one and belongs_to

    class ClockIn < ActiveRecord::Base
      belongs_to :task
      belongs_to :clock_out
      # now clock_ins will have column check_out_id
    end
    
    class ClockOut < ActiveRecord::Base
      has_one :clock_in
      # doen't have any check_in_id
    end
    
    task.clock_ins.where(:clock_out_id => nil).first.create_clock_out(:time => Time.now)
    
  • Go with the outer join

    class ClockIn < ActiveRecord::Base
      belongs_to :task
      has_one :clock_out
    
      scope :has_no_check_out, {
        :joins => "LEFT OUTER JOIN clock_outs ON clock_ins.id = clock_outs.clock_in_id"
        :conditions => "clock_outs.clock_in_id IS NULL"
      }
    end
    
    task.clock_ins.has_no_check_out.first.create_clock_out(:time => Time.now)
    

Please note that your :dependent => :destroy definitions don't look very good. Currently if you destroy a clock_out, corresponding clock_in will be destroyed, resulting in corresponding task being destroyed and leaving other clock_ins related with the task orphaned. Also when the task is destroyed, it will result in user being destroyed. This seems to be very odd chain of events. Destroying a clock_out, results in destroying a user, Ouch!

You should use :dependent => :destroy like following:

# user.rb
has_many :tasks, :dependent => :destroy

# task.rb
has_many :clock_ins, :dependent => :destroy

# clock_in.rb
has_one :clock_out, :dependent => :destroy
0

精彩评论

暂无评论...
验证码 换一张
取 消