这是对其建模的一种方法。假设我们有一个模型“参与”,它有一个开始日期时间、结束日期时间和名称。通过另一个名为“user_engagements”的连接表(具有相应的 UserEngagement 模型),一个参与有许多用户。所以我们有
User
has_many :user_engagements
has_many :engagements, :through => :user_engagements
Engagement
#fields - starts_at, ends_at (both datetime)
has_many :user_engagements
has_many :users, :through => :user_engagements
UserEngagement
belongs_to :user
belongs_to :engagement
现在我们有了一个不错的简单架构。参与基本上是对正在发生的事情进行建模,而 user_engagements 对预定做那件事的用户进行建模。我们有一个假设(未写入代码),即当他们在做某事时,他们无权做其他任何事情。
我们的下一个任务是编写一个方法来返回给定时间段内可用的用户,即新的参与。因此,我们进行了参与,我们希望所有没有参与的用户都与我们的新参与交叉。我认为最简单的方法可能是找到所有确实有交叉参与的用户,然后返回所有不是他们的用户。如果你明白我的意思。更准确的说法是 e2 与 e1 交叉是 e2 在 e1 结束之前开始并且在 e1 开始之后结束。
让我们让它成为一个参与对象的方法,因为它完全依赖于参与的数据。
#in Engagement
def unavailable_user_ids
User.find(:all, :include => [:user_engagements], :select => "users.id", :conditions => ["user_engagements.starts_at < ? and user_engagements.ends_at > ?", self.ends_at, self.starts_at]).collect(&:id)
end
def available_users
User.find(:all, :conditions => ["id not in (?)", self.unavailable_user_ids])
end
我觉得有一种更有效的方法可以在一个查询中获取此信息,但我无法完全确定 sql。