2013-07-10 24 views
0

我有一个Rails站点,记录简单的操作,例如人们上传和下载信息的时间。对于每个新操作,都会创建EventLog如何查询许多字段,允许为NULL

如果用户改变了主意,该怎么办?我有一个after_create回调,它查找补充操作并删除它们,如果它找到最近的一对。为了清楚起见,我的意思是说,如果某人上传了某些内容并很快取消,则两个event_logs都将被删除。接下来是我的回调。

# Find duplicate events by searching nearly all the fields in the EventLog table 
@duplicates = EventLog.where("user_id = ? AND event = ? AND project_id = ? AND ...,).order("created_at DESC") 

if @duplicates.size > 1 
    @duplicates.limit(2).destroy_all 
end 

上面的代码完全不是那么回事,因为如果任何字段恰好是零,该查询返回[]

我该如何编写这段代码,以便它可以处理空值,和/或是否有更好的方法来完成此操作?

+0

那么它只是SQL,所以你可以添加'user_id IS NULL或user_id =?'键入每个参数的语法。这对你的情况适合吗? – Matt

回答

0

如果我理解这一点正确,

某些字段可以为空,你想找到具有相同user_ID的活动日志,同PROJECT_ID或项目ID可以是零。

所以我想这个查询应该为你工作。

ActivityLog.where(user_id: <some_id> AND activity: <complementary_id> AND :project_id.in => [<some_project_id>, nil] ....) 

这样你会得到互补事件日志,其中user_id是相同的,并且项目ID可能会或可能不会出现

class ActivityLog 
    QUERY_HASH = Proc.new{ {user_id: self.user_id, 
         activity: complementary_id(self.id), 
         and so on.... 
    } } 
+0

在我的情况下,这些字段的任何组合都可以是空白的,因为记录已保存 - 我可以在每个字段中使用您的方法,但它会变得很长。 – sscirrus

+0

然后问题是生成查询哈希。您可以将查询作为proc存储在常量中,然后实例在运行时对其进行评估。 – nightf0x

0

如何:

# event_log.rb 

def duplicate_attr_map 
    { 
    :user_id, 
    :project_id 
    } 
end 

def duplicates 
    attribs = duplicate_attr_map.reject_if(&:blank?) 

    query = attribs.map { |attr| "#{attr} = ?" }.join(' AND ') 
    values = attribs.map { |attr| self.send(attr) } 

    EventLog.where(query, *values).order("created_at DESC") 
end 

def delete_duplicates(n) 
    duplicates.limit(n).delete_all if duplicates.size > 1 
end 

# usage: 
# EventLog.find(1).delete_duplicates(2) 

没有测试,可以改进