
我应该跟踪我的某个模型中的“条纹”,还是应该在其他地方计算它们?不知道我应该在哪里做,或者如何正确地做到这一点,所以任何建议都会很精彩.
我很高兴包含您认为有用的任何代码,请告诉我.
解决方法 我不确定它是否是最好的方法,但这是在sql中实现它的一种方法.首先,看看以下查询.SELECT serIEs_date,COUNT(posts.ID) AS num_posts_on_dateFROM generate_serIEs( '2014-12-01'::timestamp,'2014-12-17'::timestamp,'1 day' ) AS serIEs_dateleft OUTER JOIN posts ON posts.created_at::date = serIEs_dateGROUP BY serIEs_dateORDER BY serIEs_date DESC;
我们使用generate_serIEs生成从2014-12-01开始到2014-12-17(今天)结束的日期范围.然后我们用posts表进行left OUTER JOIN.这为我们在范围内的每一天提供了一行,当天在num_posts_on_date列中有帖子数.结果看起来像这样(SQL Fiddle here):
serIEs_date | num_posts_on_date---------------------------------+------------------- December,17 2014 00:00:00+0000 | 1 December,16 2014 00:00:00+0000 | 1 December,15 2014 00:00:00+0000 | 2 December,14 2014 00:00:00+0000 | 1 December,13 2014 00:00:00+0000 | 0 December,12 2014 00:00:00+0000 | 0 ... | ... December,01 2014 00:00:00+0000 | 0
现在我们知道从12月14日到17日每天都有一个帖子,所以如果今天的12月17日我们知道当前的“连胜”是4天.我们可以做更多的sql来获得最长的连胜纪录,如described in this article,但由于我们只对“当前”连胜的长度感兴趣,所以只需稍作改动.我们所要做的就是更改查询以仅获取num_posts_on_date为0的第一个日期(SQL Fiddle):
SELECT serIEs_dateFROM generate_serIEs( '2014-12-01'::timestamp,'1 day' ) AS serIEs_dateleft OUTER JOIN posts ON posts.created_at::date = serIEs_dateGROUP BY serIEs_dateHAVING COUNT(posts.ID) = 0ORDER BY serIEs_date DESCliMIT 1;
结果如下:
serIEs_date--------------------------------- December,13 2014 00:00:00+0000
但是因为我们实际上想要从最后一天起没有帖子的天数,我们也可以在sql中做到这一点(SQL Fiddle):
SELECT ('2014-12-17'::date - serIEs_date::date) AS daysFROM generate_serIEs( '2014-12-01'::timestamp,'1 day' ) AS serIEs_dateleft OUTER JOIN posts ON posts.created_at::date = serIEs_dateGROUP BY serIEs_dateHAVING COUNT(posts.ID) = 0ORDER BY serIEs_date DESCliMIT 1; 结果:
days------ 4
你去!
现在,如何将它应用于我们的Rails代码?像这样的东西:
qry = <<-sql SELECT (CURRENT_DATE - serIEs_date::date) AS days FROM generate_serIEs( ( SELECT created_at::date FROM posts WHERE posts.user_ID = :user_ID ORDER BY created_at ASC liMIT 1 ),CURRENT_DATE,'1 day' ) AS serIEs_date left OUTER JOIN posts ON posts.user_ID = :user_ID AND posts.created_at::date = serIEs_date GROUP BY serIEs_date HAVING COUNT(posts.ID) = 0 ORDER BY serIEs_date DESC liMIT 1sqlPost.find_by_sql([ qry,{ user_ID: some_user.ID } ]).first.days # => 4 正如您所看到的,我们添加了一个条件来限制user_ID的结果,并用一个查询替换我们的硬编码日期,该查询获取用户的第一个帖子的日期(generate_serIEs函数内的子选择)作为范围的开头和CURRENT_DATE为范围的结尾.
最后一行有点搞笑,因为find_by_sql将返回一个Post实例数组,因此您必须在数组中的第一个上调用days来获取值.或者,您可以这样做:
sql = Post.send(:sanitize_sql,[ qry,{ user_ID: some_user.ID } ])result_value = Post.connection.select_value(sql)streak_days = Integer(result_value) rescue nil # => 4 在ActiveRecord中,它可以变得更干净:
class Post < ActiveRecord::Base USER_STREAK_DAYS_sql = <<-sql SELECT (CURRENT_DATE - serIEs_date::date) AS days FROM generate_serIEs( ( SELECT created_at::date FROM posts WHERE posts.user_ID = :user_ID ORDER BY created_at ASC liMIT 1 ),'1 day' ) AS serIEs_date left OUTER JOIN posts ON posts.user_ID = :user_ID AND posts.created_at::date = serIEs_date GROUP BY serIEs_date HAVING COUNT(posts.ID) = 0 ORDER BY serIEs_date DESC liMIT 1 sql def self.user_streak_days(user_ID) sql = sanitize_sql [ USER_STREAK_DAYS_sql,{ user_ID: user_ID } ] result_value = connection.select_value(sql) Integer(result_value) rescue nil endendclass User < ActiveRecord::Base def post_streak_days Post.user_streak_days(self) endend# And then...u = User.find(123)u.post_streak_days # => 4 以上是未经测试的,因此可能需要一些摆弄才能使其正常工作,但我希望它至少能指出正确的方向.
总结以上是内存溢出为你收集整理的ruby-on-rails – 计算在Rails中发布的连续天数全部内容,希望文章能够帮你解决ruby-on-rails – 计算在Rails中发布的连续天数所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)