有三种型号:
# Table name: activities_people
#
# activity_id :integer not null
# person_id :integer not null
# date :date not null
# id :integer not null, primary key
#
# Table name: activities
#
# id :integer not null, primary key
# name :string(20) not null
# description :text
# active :boolean not null
# day_of_week :string(20) not null
# start_on :time not null
# end_on :time not null
第三种模式是人。 关联:
class Activity < ActiveRecord::Base
has_many :activities_people
has_many :people, through: :activities_people
end
class ActivitiesPerson < ActiveRecord::Base
belongs_to :person
belongs_to :activity
end
class Person < ActiveRecord::Base
has_many :activities, through: :activities_people
end
问题: 我不知道如何在ativities_person.rb中创建验证方法来保护加入活动,并及时重叠。
示例:
person_id:1加入活动,即08.08.2016(日期)和最后09:00(start_on) - 10:00(end_on)。 同一个人想要保存到另一个活动,也将是08.08.2016和最后09:30(start_on) - 10:30(end_on)。现在 验证应该抛出他在同一时间保存到其他活动的错误(时间范围重叠)。验证首先应检查日期是否匹配,接下来应检查活动的时间重叠。
我尝试了什么:
def check_join_client
# check if client joined to some activities in same date as current join
activities_date = person.activities_people.where(date: date)
if activities_date.any?
# get start_on and end_on for current activity and date
get_activities = person.activities.where(id: activities_date.pluck(:activity_id))
ol_activities = get_activities.where('((start_on <= :start_on AND
end_on >= :end_on) OR
(start_on <= :start_on AND
end_on <= :end_on AND
end_on >= :start_on) OR
(start_on >= :start_on AND
start_on <= :end_on AND
end_on >= :end_on))',
start_on: get_activities.pluck(:start_on),
end_on: get_activities.pluck(:end_on))
end
end
我的方法不正确。我很困惑如何解决我的问题。
答案 0 :(得分:3)
根据您的数据库类型,我认为使用Postgres可以使用OVERLAP函数来执行此类查询。
结果查询可能如下:
Activity.where("(start_on, end_on) OVERLAPS (?, ?)", start_on, end_on)
另一种与DB无关的方法,但我无法测试的是:
Activity.find_by_sql("SELECT e1.* FROM activities e1, activities e2 WHERE(e2.end_on >= e1.start_on AND e2.start_on < e1.start_on)")
但是上面的方法会返回一个数组,而不是ActiveRecord :: Relation,即你不能将AR方法链接到它。它未经测试,但我认为它应该有用!
<强>更新强>
现在可以使用像这样的方法进行验证
class Activity
scope :overlapping_activity, ->(activity) { where("(start_on, end_on) OVERLAPS (?, ?)", activity.start_on, activity.end_on) }
validate :not_overlapping_activity
def not_overlapping_activity
if Activity.overlapping_activity(self).any?
errors.add(:overlapping, "There is an overlapping activity for this period")
end
end
end
如果我能够提供帮助,请告诉我..