Rails Devise:如何(内存)缓存用户对象的数据库请求?
每次我点击经过身份验证的页面时,我都会注意到设计发出一条 SQL 语句:
User Load (0.2ms) SELECT users
.* FROM users
WHERE (users
code>.id
= 1) LIMIT 1
(顺便说一句,我正在使用 Rails 3 .. 所以cache_money 似乎是一个解决方案,尽管进行了大量搜索,但我没有找到替代品)。
我在用户模型中尝试了许多重写,但似乎只调用了 find_by_sql 。其中传递了整个 SQL 语句的字符串。像 find_by_id 或 find 这样直观的东西似乎没有被调用。我“可以”覆盖这个方法并收集用户 ID 并从中创建一个合理的缓存系统 - 但这非常丑陋。
我还尝试覆盖authenticate_user,我可以拦截一次SQL尝试,但随后调用current_user似乎会再试一次。
简而言之,我的用户对象很少发生变化,并且为此不断访问数据库而不是内存缓存解决方案是一种悲伤的状态。 (假设我愿意承担使用 :after_save 作为该解决方案的一部分但不是全部使所述缓存失效的所有责任)
Every time I hit an authenticated page, I notice devise issuing an SQL statement :
User Load (0.2ms) SELECT users
.* FROM users
WHERE (users
.id
= 1) LIMIT 1
(I'm using Rails 3 btw .. so cache_money seems out as a solution and despite a lot of searching I've found no substitute).
I tried many overrides in the user model and only find_by_sql seems called. Which gets passed a string of the entire SQL statement. Something intuitive like find_by_id or find doesn't seem to get called. I 'can' override this method and glean the user-id and do a reasonable cache system from that - but that's quite ugly.
I also tried overriding authenticate_user which I can intercept one SQL attempt but then calls to current_user seems to try it again.
Simply, my user objects change rarely and its a sad state to keep hitting the db for this instead of a memcache solution. (assume that I'm willing to accept all responsibility for invalidating said cache with :after_save as part but not all of that solution)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
以下代码将通过 id 缓存用户并
每次修改后使缓存失效。
The following code will cache the user by its id and
invalidate the cache after each modification.
警告:很可能有更好/更聪明的方法来做到这一点。
几个月前我就解决了这个问题。我发现——或者至少,我想我发现——Devise 在此处加载用户对象:
https://github.com/plataformatec/devise /blob/master/lib/devise/rails/warden_compat.rb#L31
我为该反序列化方法创建了一个猴子补丁/initializers/warden.rb 执行缓存获取而不是 get。这感觉又脏又错,但它确实有效。
WARNING: There's most likely a better/smarter way to do this.
I chased this problem down a few months back. I found -- or at least, I think I found -- where Devise loads the user object here:
https://github.com/plataformatec/devise/blob/master/lib/devise/rails/warden_compat.rb#L31
I created a monkey patch for that deserialized method in /initializers/warden.rb to do a cache fetch instead of get. It felt dirty and wrong, but it worked.
我也一直在为此苦苦挣扎。
一种不太复杂的方法是将此类方法添加到您的 User 模型中:
请注意,我将模型名称添加到传入的对象 ID 中,以便从缓存中存储/检索对象;您可以使用任何适合您需要的方案。
当然,唯一需要担心的是,当某些内容发生变化时,缓存中的用户会失效。如果使用会话 ID 作为键的一部分将 User 存储在缓存中,那就太好了,但会话在模型类中不可用,并且不会由 Devise 传递给此方法。
I've been struggling with this, too.
A less convoluted way of doing this is to add this class method to your User model:
Note that I'm prepending the model name to the object ID that is passed in for storing/retrieving the object from the cache; you can use whatever scheme fits your needs.
The only thing to worry about, of course, is invalidating the user in the cache when something changes. It would have been nice instead to store the User in the cache using the session ID as part of the key, but the session is not available in the model class, and is not passed in to this method by Devise.