【问题标题】:Rails Validations with Redis使用 Redis 进行 Rails 验证
【发布时间】:2012-01-24 04:27:47
【问题描述】:

我有一堆 Redis 的 getter 和 setter,比如

def share_points= p
  $redis.set("store:#{self.id}:points:share", p) if valid?
end

问题是,ActiveRecord 的验证不会阻止值被插入到 redis 中。如果不在每个二传手上添加if valid?,我该如何做呢? valid? 每次调用时都会计算验证。

【问题讨论】:

    标签: ruby-on-rails ruby-on-rails-3 activerecord redis


    【解决方案1】:

    如果您正在编辑的模型是从 active_record 派生的,那么您可能希望对 redis 进行特定的封装调用来为您进行验证。例如

    class Foo < ActiveRecord::Base
      def rset(key,value)
        $redis.set("store:#{self.id}:key", value) if valid?
      end
      def share_points=(p)
         rset("points:share", p)
      end
    end
    

    你也可以把它放在一个模块中并包含它。

    如果您不是从 AR:Base 派生的,您可能希望使用 ActiveModel 提出更类似于 AR::Base 的结构,如下所述:http://purevirtual.de/2010/04/url-shortener-with-redis-and-rails3/

    【讨论】:

    • 哦,我想你可以做的另一件事是猴子修补 $redis.set 上的一些别名,但这会影响对 $redis.set 的所有调用,所以它可能不合适
    • 我在同一模型上使用 MongoDB (mongoid) 和 Redis。使用有效的问题?是它每次调用时都会运行所有模型验证(源代码:github.com/rails/rails/blob/master/activemodel/lib/active_model/…)。如果我更新 4 个 redis 属性,它将运行验证 5 次。
    • 如果验证的计算成本不高,这有关系吗?
    • IIRC,mongoid 有 after_save 回调,所以你可以使用 mset (redis.io/commands/mset) 而不是其中之一。
    • 您需要在某处列出基于 redis v. mongo 的参数列表。这是一个要点(假设 mset 需要一个哈希......):gist.github.com/c9d4b0e4c016a72beec6 我不确定这是一个好主意,因为它涉及覆盖 update_attributes,但我认为它可以完成这项工作。
    【解决方案2】:

    切换到after_save 回调方法怎么样,您可以在其中存储所有已更改的字段并将它们一次性保存到redis。

    类似:

    class Foo < ActiveRecord::Base
    
      after_save :persist_to_redis
      attr_accessor :redis_attributes
    
      def share_points=(p)
        @redis_attributes ||= {}
        @redis_attributes[:share_points] = p
      end
    
      def something_else=(p)
        @redis_attributes ||= {}
        @redis_attributes[:something_else] = p
      end
    
      private
    
      def redis_store_share_points(value)
        $redis.set("store:#{self.id}:key", value)
      end
    
    
      def redis_store_something_else(value)
        $redis.set("something_else:#{self.id}", value)
      end
    
      def persist_to_redis
        $redis.multi do
          @redis_attributes.each_pair do |key, value|
            send("redis_store_#{key}".to_sym, value)
          end
        end
      end
    
    end
    

    我认为即使这样也可以重构和清理,但你明白了。

    【讨论】:

    • 谢谢。这就是我今天提出的解决方案,只是做了一些小的改动。 multi 比一个一个做的快吗?
    • 您仍在逐一进行,但multi 可以使客户端能够通过管道处理请求并将它们作为事务的一部分进行。
    猜你喜欢
    • 2017-10-21
    • 2011-06-21
    • 1970-01-01
    • 2011-12-17
    • 2015-10-03
    • 2023-04-10
    • 1970-01-01
    • 1970-01-01
    • 2018-03-16
    相关资源
    最近更新 更多