diff --git a/.rubocop.yml b/.rubocop.yml index 3684aa5..9b135d8 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -1,7 +1,38 @@ -inherit_from: .rubocop_todo.yml +AllCops: + DisplayCopNames: true + Exclude: + - 'Rakefile' + - 'vendor/**/*' -FileName: +Naming/FileName: Enabled: false -DoubleNegation: +Style/DoubleNegation: Enabled: false + +Metrics/BlockLength: + Exclude: + - 'spec/**/*.rb' + +Layout/LineLength: + Max: 100 + +Metrics/ClassLength: + Max: 120 + +Security/MarshalLoad: + Enabled: false + +Style/FrozenStringLiteralComment: + Enabled: false + +Style/PercentLiteralDelimiters: + Enabled: false + +Style/SafeNavigation: + Enabled: false + +Style/YodaCondition: + # temporary work around for rubocop bug 'An error occurred while Style/YodaCondition...' (v0.49.1) + Exclude: + - 'spec/redis_session_store_spec.rb' diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml deleted file mode 100644 index ffba99a..0000000 --- a/.rubocop_todo.yml +++ /dev/null @@ -1,12 +0,0 @@ -# This configuration was generated by -# `rubocop --auto-gen-config` -# on 2016-07-02 09:22:22 -0400 using RuboCop version 0.41.1. -# The point is for the user to remove these configuration records -# one by one as the offenses are removed from the code base. -# Note that changes in the inspected code, or installation of new -# versions of RuboCop, may require this file to be generated again. - -# Offense count: 1 -# Configuration parameters: CountComments. -Metrics/ClassLength: - Max: 108 diff --git a/.travis.yml b/.travis.yml index e563daa..3ff098e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,12 +1,16 @@ language: ruby -sudo: false cache: bundler rvm: -- 2.3.1 -- jruby-9.1.1.0 +- 2.3 +- 2.4 +- 2.5 +- 2.6 +- ruby-head +- jruby-9.2.12.0 matrix: allow_failures: - - rvm: jruby-9.1.1.0 + - rvm: ruby-head + - rvm: jruby-9.2.12.0 notifications: email: false deploy: @@ -17,4 +21,4 @@ deploy: on: tags: true repo: roidrage/redis-session-store - rvm: 2.3.1 + rvm: 2.6.6 diff --git a/AUTHORS.md b/AUTHORS.md index 0bd8d7f..64438a6 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -7,6 +7,7 @@ Redis Session Store authors - Edwin Cruz - Gonçalo Silva - Ian C. Anderson +- Jesse Doyle - Jorge Pardiñas - Justin McNally - Mathias Meyer @@ -15,3 +16,10 @@ Redis Session Store authors - Olek Poplavsky - Tim Lossen - Todd Bealmear +- Aleksey Dashkevych +- Olle Jonsson +- Nicolas Rodriguez +- Sergey Nebolsin +- Anton Kolodii +- Peter Karman +- Zach Margolis diff --git a/CHANGELOG.md b/CHANGELOG.md index 4c63a58..1412dfc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,42 @@ ## [Unreleased] +## [0.11.3] - 2020-07-23 +### Fixed +- https://github.com/roidrage/redis-session-store/issues/121 + +## [0.11.2] - 2020-07-22 +### Changed +- Silence deprecation warning when using with redis gem v4.2+ + +## [0.11.1] - 2019-08-22 +### Changed +- Remove the `has_rdoc` parameter from the `.gemspec` file as it has been deprecated. +- Actionpack to '>= 3', remove upper dependency + +## [0.11.0] - 2018-08-13 +### Changed +- JRuby to jruby-9.2.0.0 +- Travis Ruby support: 2.3.7, 2.4.4, 2.5.1 + +### Added +- :ttl configuration option + +## [0.10.0] - 2018-04-14 +### Changed +- JRuby to jruby-9.1.15.0 +- Redis to '>= 3', '< 5' +- Actionpack to '>= 3', '< 6' +- Rake to 12 + +### Added +- with_indifferent_access if defined ActiveSupport + +## [0.9.2] - 2017-10-31 +### Changed +- Actionpack to 5.1 +- Travis use jruby 9.1.13.0 + ## [0.9.1] - 2016-07-03 ### Added - More specific runtime dependencies @@ -201,7 +237,11 @@ ### Added - first working version -[Unreleased]: https://github.com/roidrage/redis-session-store/compare/v0.9.1...HEAD +[Unreleased]: https://github.com/roidrage/redis-session-store/compare/v0.11.1...HEAD +[0.11.1]: https://github.com/roidrage/redis-session-store/compare/v0.11.0...v0.11.1 +[0.11.0]: https://github.com/roidrage/redis-session-store/compare/v0.10.0...v0.11.0 +[0.10.0]: https://github.com/roidrage/redis-session-store/compare/v0.9.2...v0.10.0 +[0.9.2]: https://github.com/roidrage/redis-session-store/compare/v0.9.1...v0.9.2 [0.9.1]: https://github.com/roidrage/redis-session-store/compare/v0.9.0...v0.9.1 [0.9.0]: https://github.com/roidrage/redis-session-store/compare/v0.8.1...v0.9.0 [0.8.1]: https://github.com/roidrage/redis-session-store/compare/v0.8.0...v0.8.1 diff --git a/README.md b/README.md index e8d1fbc..fd3594c 100644 --- a/README.md +++ b/README.md @@ -33,13 +33,13 @@ See `lib/redis-session-store.rb` for a list of valid options. In your Rails app, throw in an initializer with the following contents: ``` ruby -My::Application.config.session_store :redis_session_store, { +Rails.application.config.session_store :redis_session_store, { key: 'your_session_key', redis: { expire_after: 120.minutes, # cookie expiration ttl: 120.minutes, # Redis expiration, defaults to 'expire_after' key_prefix: 'myapp:session:', - url: 'redis://host:12345/2', + url: 'redis://localhost:6379/0', } } ``` @@ -50,7 +50,7 @@ If you want to handle cases where Redis is unavailable, a custom callable handler may be provided as `on_redis_down`: ``` ruby -My::Application.config.session_store :redis_session_store, { +Rails.application.config.session_store :redis_session_store, { # ... other options ... on_redis_down: ->(e, env, sid) { do_something_will_ya!(e) } redis: { @@ -70,7 +70,7 @@ custom serializer: * `CustomClass` - You can just pass the constant name of any class that responds to `.load` and `.dump` ``` ruby -My::Application.config.session_store :redis_session_store, { +Rails.application.config.session_store :redis_session_store, { # ... other options ... serializer: :hybrid redis: { @@ -89,7 +89,7 @@ custom callable handler may be provided as `on_session_load_error` which will be given the error and the session ID. ``` ruby -My::Application.config.session_store :redis_session_store, { +Rails.application.config.session_store :redis_session_store, { # ... other options ... on_session_load_error: ->(e, sid) { do_something_will_ya!(e) } redis: { @@ -100,6 +100,10 @@ My::Application.config.session_store :redis_session_store, { **Note** The session will *always* be destroyed when it cannot be loaded. +### Other notes + +It returns with_indifferent_access if ActiveSupport is defined + ## Rails 2 Compatibility This gem is currently only compatible with Rails 3+. If you need diff --git a/lib/redis-session-store.rb b/lib/redis-session-store.rb index e86003b..89d020c 100644 --- a/lib/redis-session-store.rb +++ b/lib/redis-session-store.rb @@ -3,16 +3,17 @@ # Redis session storage for Rails, and for Rails only. Derived from # the MemCacheStore code, simply dropping in Redis instead. class RedisSessionStore < ActionDispatch::Session::AbstractStore - VERSION = '0.9.1'.freeze + VERSION = '0.11.3'.freeze # Rails 3.1 and beyond defines the constant elsewhere unless defined?(ENV_SESSION_OPTIONS_KEY) - if Rack.const_defined?(:RACK_SESSION_OPTIONS) - ENV_SESSION_OPTIONS_KEY = Rack::RACK_SESSION_OPTIONS - else - ENV_SESSION_OPTIONS_KEY = Rack::Session::Abstract::ENV_SESSION_OPTIONS_KEY - end + ENV_SESSION_OPTIONS_KEY = if Rack.release.split('.').first.to_i > 1 + Rack::RACK_SESSION_OPTIONS + else + Rack::Session::Abstract::ENV_SESSION_OPTIONS_KEY + end end + USE_INDIFFERENT_ACCESS = defined?(ActiveSupport).freeze # ==== Options # * +:key+ - Same as with the other cookie stores, key name # * +:redis+ - A hash with redis-specific options @@ -26,12 +27,12 @@ class RedisSessionStore < ActionDispatch::Session::AbstractStore # # ==== Examples # - # My::Application.config.session_store :redis_session_store, { + # Rails.application.config.session_store :redis_session_store, { # key: 'your_session_key', # redis: { # expire_after: 120.minutes, # key_prefix: 'myapp:session:', - # url: 'redis://host:12345/2' + # url: 'redis://localhost:6379/0' # }, # on_redis_down: ->(*a) { logger.error("Redis down! #{a.inspect}") } # serializer: :hybrid # migrate from Marshal to JSON @@ -66,7 +67,7 @@ def session_exists?(env) !!( value && !value.empty? && - redis.exists(prefixed(value)) + key_exists?(value) ) rescue Errno::ECONNREFUSED, Redis::CannotConnectError => e on_redis_down.call(e, env, value) if on_redis_down @@ -74,6 +75,16 @@ def session_exists?(env) true end + def key_exists?(value) + if redis.respond_to?(:exists?) + # added in redis gem v4.2 + redis.exists?(prefixed(value)) + else + # older method, will return an integer starting in redis gem v4.3 + redis.exists(prefixed(value)) + end + end + def verify_handlers! %w(on_redis_down on_session_load_error).each do |h| next unless (handler = public_send(h)) && !handler.respond_to?(:call) @@ -86,16 +97,15 @@ def prefixed(sid) "#{default_options[:key_prefix]}#{sid}" end - def get_session(env, sid) - unless sid && (session = load_session_from_redis(sid)) - sid = generate_sid - session = {} - end + def session_default_values + [generate_sid, USE_INDIFFERENT_ACCESS ? {}.with_indifferent_access : {}] + end - [sid, session] + def get_session(env, sid) + sid && (session = load_session_from_redis(sid)) ? [sid, session] : session_default_values rescue Errno::ECONNREFUSED, Redis::CannotConnectError => e on_redis_down.call(e, env, sid) if on_redis_down - [generate_sid, {}] + session_default_values end alias find_session get_session @@ -103,7 +113,7 @@ def load_session_from_redis(sid) data = redis.get(prefixed(sid)) begin data ? decode(data) : nil - rescue => e + rescue StandardError => e destroy_session_from_sid(sid, drop: true) on_session_load_error.call(e, sid) if on_session_load_error nil @@ -111,7 +121,8 @@ def load_session_from_redis(sid) end def decode(data) - serializer.load(data) + session = serializer.load(data) + USE_INDIFFERENT_ACCESS ? session.with_indifferent_access : session end def set_session(env, sid, session_data, options = nil) @@ -121,10 +132,10 @@ def set_session(env, sid, session_data, options = nil) else redis.set(prefixed(sid), encode(session_data)) end - return sid + sid rescue Errno::ECONNREFUSED, Redis::CannotConnectError => e on_redis_down.call(e, env, sid) if on_redis_down - return false + false end alias write_session set_session diff --git a/redis-session-store.gemspec b/redis-session-store.gemspec index 040dfd1..9b35c65 100644 --- a/redis-session-store.gemspec +++ b/redis-session-store.gemspec @@ -8,7 +8,6 @@ Gem::Specification.new do |gem| gem.homepage = 'https://github.com/roidrage/redis-session-store' gem.license = 'MIT' - gem.has_rdoc = true gem.extra_rdoc_files = %w(LICENSE AUTHORS.md CONTRIBUTING.md) gem.files = `git ls-files -z`.split("\x0") @@ -16,12 +15,12 @@ Gem::Specification.new do |gem| gem.version = File.read('lib/redis-session-store.rb') .match(/^ VERSION = '(.*)'/)[1] - gem.add_runtime_dependency 'redis', '~> 3' - gem.add_runtime_dependency 'actionpack', '>= 3', '< 5.2' + gem.add_runtime_dependency 'actionpack', '>= 3', '< 7' + gem.add_runtime_dependency 'redis', '>= 3', '< 5' - gem.add_development_dependency 'fakeredis', '~> 0.5' - gem.add_development_dependency 'rake', '~> 11' + gem.add_development_dependency 'fakeredis', '~> 0.8' + gem.add_development_dependency 'rake', '~> 13' gem.add_development_dependency 'rspec', '~> 3' - gem.add_development_dependency 'rubocop', '~> 0.41' - gem.add_development_dependency 'simplecov', '~> 0.11' + gem.add_development_dependency 'rubocop', '~> 0.81' + gem.add_development_dependency 'simplecov', '~> 0.17' end diff --git a/spec/redis_session_store_spec.rb b/spec/redis_session_store_spec.rb index 19c3ff6..5767603 100644 --- a/spec/redis_session_store_spec.rb +++ b/spec/redis_session_store_spec.rb @@ -519,7 +519,7 @@ def self.dump(_value) end context 'when callable' do - let(:options) { { :"#{h}" => ->(*) { !nil } } } + let(:options) { { "#{h}": ->(*) { true } } } it 'does not explode at init' do expect { store }.to_not raise_error @@ -527,7 +527,7 @@ def self.dump(_value) end context 'when not callable' do - let(:options) { { :"#{h}" => 'herpderp' } } + let(:options) { { "#{h}": 'herpderp' } } it 'explodes at init' do expect { store }.to raise_error(ArgumentError)