Skip to content

Commit f738c0d

Browse files
authored
Merge pull request #931 from flippercloud/redis-with
Horrible hackish thing to fix redis less than 4.7 with active record 7.1
2 parents d498a1e + 5cd3b40 commit f738c0d

File tree

1 file changed

+56
-1
lines changed

1 file changed

+56
-1
lines changed

lib/flipper/adapters/redis_shared/methods.rb

Lines changed: 56 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,63 @@
11
module Flipper
22
module Adapters
33
module RedisShared
4+
private
5+
6+
# Safely executes a block with a Redis connection, handling compatibility
7+
# issues between different Redis client versions and Rails versions.
8+
#
9+
# This method exists to fix a compatibility issue between Rails 7.1.* and
10+
# Redis versions below 4.7.0. The issue occurs because:
11+
#
12+
# 1. In Redis versions below 4.7.0, the `with` method is not defined on
13+
# the Redis client, so Flipper would fall back to `yield(@client)`
14+
# 2. However, Rails 7.1.* introduced `Object#with` via ActiveSupport,
15+
# which shadows the Redis client's `with` method
16+
# 3. Rails 7.1.*'s `Object#with` doesn't pass `self` to the block parameter
17+
# (this was fixed in Rails 7.2.0), causing the block parameter to be `nil`
18+
#
19+
# This method ensures that:
20+
# - For Redis >= 4.7.0: Uses the Redis client's native `with` method
21+
# - For ConnectionPool: Uses the ConnectionPool's `with` method
22+
# - For Redis < 4.7.0: Falls back to `yield(@client)` to avoid the Rails
23+
# ActiveSupport `Object#with` method
24+
#
25+
# @see https://github.com/redis/redis-rb/blob/master/CHANGELOG.md#470
26+
# @see https://github.com/rails/rails/pull/46681
27+
# @see https://github.com/rails/rails/pull/50470
428
def with_connection(&block)
5-
@client.respond_to?(:with) ? @client.with(&block) : yield(@client)
29+
if client_has_correct_with_method?
30+
@client.with(&block)
31+
else
32+
yield(@client)
33+
end
34+
end
35+
36+
# Determines if the Redis client has a safe `with` method that can be used
37+
# without conflicts with Rails ActiveSupport's `Object#with`.
38+
#
39+
# This method checks for:
40+
# 1. ConnectionPool instances (which have their own `with` method)
41+
# 2. Redis instances with version >= 4.7.0 (which have a proper `with` method)
42+
#
43+
# The method caches its result to avoid repeated checks.
44+
#
45+
# @return [Boolean] true if the client has a safe `with` method, false otherwise
46+
def client_has_correct_with_method?
47+
return @client_has_correct_with_method if defined?(@client_has_correct_with_method)
48+
49+
@client_has_correct_with_method = @client.respond_to?(:with) && (client_is_connection_pool? || client_is_redis_that_has_with?)
50+
rescue
51+
@client_has_correct_with_method = false
52+
end
53+
54+
def client_is_connection_pool?
55+
defined?(ConnectionPool) && @client.is_a?(ConnectionPool)
56+
end
57+
58+
def client_is_redis_that_has_with?
59+
@client.is_a?(::Redis) && defined?(::Redis::VERSION) &&
60+
::Gem::Version.new(::Redis::VERSION) >= ::Gem::Version.new('4.7.0')
661
end
762
end
863
end

0 commit comments

Comments
 (0)