Rails 问一个关于在 rails scope 中 join 表查询设置时 where 条件的问题

zeekerpro · 2022年03月17日 · 最后由 zeekerpro 回复于 2022年03月18日 · 553 次阅读

有两个表,一个 user 表,一个 user 状态配置表,基本信息如下

users

settings

users 表中的 attend_at 表示 user 注册加入的时间,activated_at 是用户激活账号的时间,激活以后才能正常使用

settings 中的 activate_duration 限制用户成功加入后多少分钟内需要激活账号,超过则不允许激活

比如 user1 的激活最晚时间就是 User.first.attend_at + 80.minutes

需求是要列出现在(Time.now)还有激活机会的 users 有哪些。

请问要实现这个需求,在 ActiveRecord 中使用 scope 应该怎么写?

伪代码如下

class User < ApplicationRecord
  belongs_to :settings

  scope :can_activates, -> {
    where(:activated_at => nil).joins(:settings).where(:attended_at > # settings.activate_duration.minutes.ago # )
  }

end

求解惑:scope 的 lambda 应该怎么实现?万分感谢🙏!

joins(:settings).where("users.attended_at + interval '1 minute' * settings.activation_duration > now()")

大概是这么个方向,用 sql 比较时间差

zhengpd 回复

搞定了,谢谢老哥,不过貌似这种情况只能用 sql 字符串,用 Active Record Query Interface 好像就没法实现了。

上述设计有慢查询问题

在 settings 表加个用户激活账号截止时间 activate_end_at, 然后加个索引,查询时User.join(:setting).where('settings.activate_end_at > ?', Time.now)

插入 setting 时设置 activate_end_at = user.attend_at + activate_duration.minute

若业务已上线,可以先加字段批量设值再上业务代码

ThxFly 回复

这里在设计的时候 setting 和 user 时一对多的关系,setting 只是配置了 user 激活限制的时间。

比如 user1 关联的 setting1,那 user1 就需要在 attended_at 后 80 minutes 内激活账号。

如果 user1 改变了 setting 为 setting2,那 user1 就可以在 attended_at 后 90 minutes 内激活账号。

换言之就是 user 的 setting 是可控的,不过按找老哥的思路倒是可以在 user 上加一个 activate_end_at,当换 setting 的时候更新 user.activate_end_at,这样可以将原本需要逻辑计算的直接映射成数据存下来,查询的时候也不要 join 了。。。

scope :can_activates, -> {
  where(':activate_end_at  > ?',  Time.now() )
}
5 楼 已删除
需要 登录 后方可回复, 如果你还没有账号请 注册新账号