diff --git a/.gitignore b/.gitignore index 44eea09..fe67b76 100644 --- a/.gitignore +++ b/.gitignore @@ -28,6 +28,7 @@ /tmp/storage/* !/tmp/storage/ !/tmp/storage/.keep +dump.rdb # Ignore master key for decrypting credentials and more. /config/master.key diff --git a/.rubocop.yml b/.rubocop.yml index a8841c9..b46dd59 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -13,6 +13,7 @@ AllCops: ################### Custom/PrivateMethodStyle: Enabled: true + AutoCorrect: true ################### # End Custom Cops # ################### @@ -28,6 +29,7 @@ Lint/UnusedMethodArgument: Metrics/AbcSize: Exclude: - "app/models/application_record.rb" + - "lib/rubocop/cop/custom/*.rb" Metrics/CyclomaticComplexity: Exclude: - "lib/rubocop/cop/custom/*.rb" diff --git a/Gemfile b/Gemfile index d5d95e8..9a3dc20 100644 --- a/Gemfile +++ b/Gemfile @@ -14,6 +14,8 @@ gem "pg", "~> 1.1" gem "faker" gem "money-rails" gem "puma", ">= 5.0" +gem "redis" +gem "redis-rails" # Build JSON APIs with ease [https://github.com/rails/jbuilder] # gem "jbuilder" diff --git a/Gemfile.lock b/Gemfile.lock index f942826..91420cd 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -162,18 +162,8 @@ GEM net-smtp (0.5.0) net-protocol nio4r (2.7.3) - nokogiri (1.16.6-aarch64-linux) - racc (~> 1.4) - nokogiri (1.16.6-arm-linux) - racc (~> 1.4) nokogiri (1.16.6-arm64-darwin) racc (~> 1.4) - nokogiri (1.16.6-x86-linux) - racc (~> 1.4) - nokogiri (1.16.6-x86_64-darwin) - racc (~> 1.4) - nokogiri (1.16.6-x86_64-linux) - racc (~> 1.4) parallel (1.24.0) parser (3.3.1.0) ast (~> 2.4.1) @@ -231,6 +221,26 @@ GEM rake (13.2.1) rdoc (6.7.0) psych (>= 4.0.0) + redis (5.2.0) + redis-client (>= 0.22.0) + redis-actionpack (5.4.0) + actionpack (>= 5, < 8) + redis-rack (>= 2.1.0, < 4) + redis-store (>= 1.1.0, < 2) + redis-activesupport (5.3.0) + activesupport (>= 3, < 8) + redis-store (>= 1.3, < 2) + redis-client (0.22.2) + connection_pool + redis-rack (3.0.0) + rack-session (>= 0.2.0) + redis-store (>= 1.2, < 2) + redis-rails (5.0.2) + redis-actionpack (>= 5.0, < 6) + redis-activesupport (>= 5.0, < 6) + redis-store (>= 1.2, < 2) + redis-store (1.10.0) + redis (>= 4, < 6) regexp_parser (2.9.2) reline (0.5.9) io-console (~> 0.5) @@ -314,6 +324,8 @@ DEPENDENCIES pry-rails puma (>= 5.0) rails (~> 7.1.3, >= 7.1.3.4) + redis + redis-rails rspec-rails rubocop rubocop-rails diff --git a/config/application.rb b/config/application.rb index 6468bfb..d3c1b33 100644 --- a/config/application.rb +++ b/config/application.rb @@ -27,6 +27,7 @@ class Application < Rails::Application # not contain `.rb` files, or that should not be reloaded or eager loaded. # Common ones are `templates`, `generators`, or `middleware`, for example. config.autoload_lib(ignore: %w(assets tasks)) + config.autoload_paths << Rails.root.join('lib') # Configuration for the application, engines, and railties goes here. # diff --git a/config/environments/development.rb b/config/environments/development.rb index 43ff593..2bff298 100644 --- a/config/environments/development.rb +++ b/config/environments/development.rb @@ -19,14 +19,19 @@ # Enable/disable caching. By default caching is disabled. # Run rails dev:cache to toggle caching. - if Rails.root.join("tmp/caching-dev.txt").exist? - config.cache_store = :memory_store + + if Rails.root.join("tmp/caching-dev.txt").exist? || ENV['REDIS_URL'].present? + config.cache_store = :redis_cache_store, { + url: ENV['REDIS_URL'] || 'redis://localhost:6379/0', + namespace: 'app_cache', # Optional: Add a namespace for keys + expires_in: 1.day # Optional: Set expiration time for cached data + } + config.public_file_server.headers = { "Cache-Control" => "public, max-age=#{2.days.to_i}" } else config.action_controller.perform_caching = false - config.cache_store = :null_store end @@ -68,6 +73,10 @@ # Raise error when a before_action's only/except options reference missing actions config.action_controller.raise_on_missing_callback_actions = true + # config/environments/development.rb + config.cache_store = :redis_cache_store, { url: 'redis://localhost:6379/0' } + config.session_store :cache_store, key: '_myapp_session', expire_after: 1.week + config.generators.after_generate do |files| parsable_files = files.filter { |file| file.end_with?('.rb') } diff --git a/config/environments/production.rb b/config/environments/production.rb index 264ed17..f1f2266 100644 --- a/config/environments/production.rb +++ b/config/environments/production.rb @@ -58,7 +58,7 @@ config.log_level = ENV.fetch("RAILS_LOG_LEVEL", "info") # Use a different cache store in production. - # config.cache_store = :mem_cache_store + config.cache_store = :redis_cache_store, { url: ENV["REDIS_URL"] || "redis://localhost:6379/1" } # Use a real queuing backend for Active Job (and separate queues per environment). # config.active_job.queue_adapter = :resque diff --git a/config/initializers/redis.rb b/config/initializers/redis.rb new file mode 100644 index 0000000..a207df3 --- /dev/null +++ b/config/initializers/redis.rb @@ -0,0 +1,3 @@ +require './lib/cache/store' +redis_url = ENV["REDIS_URL"] || "redis://localhost:6379/1" +::Cache::Store.cache(Redis.new(url: redis_url)) \ No newline at end of file diff --git a/lib/cache/store.rb b/lib/cache/store.rb new file mode 100644 index 0000000..cda70e1 --- /dev/null +++ b/lib/cache/store.rb @@ -0,0 +1,26 @@ +# frozen_string_literal: true + +module Cache + class Store + def self.cache(store) + @cache ||= store + end + + def self.set(key, value, expires_in: 1.hour) + @cache.set(key, value) + @cache.expire(key, expires_in) + end + + def self.get(key) + @cache.get(key) + end + + def self.del(key) + @cache.del(key) + end + + def self.exists?(key) + @cache.exists(key) + end + end +end diff --git a/spec/lib/cache/store_spec.rb b/spec/lib/cache/store_spec.rb new file mode 100644 index 0000000..2512803 --- /dev/null +++ b/spec/lib/cache/store_spec.rb @@ -0,0 +1,39 @@ +# frozen_string_literal: true + +require "rails_helper" +require Rails.root.join("lib/cache/store") + +RSpec.describe Cache::Store do + describe ".set and .get" do + it "stores and retrieves data from Redis cache" do + key = "test_key" + value = "test_value" + + # Set value in cache + Cache::Store.set(key, value) + + # Get value from cache + cached_value = Cache::Store.get(key) + + expect(cached_value).to eq(value) + end + end + + describe ".del" do + it "deletes data from Redis cache" do + key = "test_key" + value = "test_value" + + # Set value in cache + Cache::Store.set(key, value) + + # Delete value from cache + Cache::Store.del(key) + + # Verify value is deleted + cached_value = Cache::Store.get(key) + + expect(cached_value).to be_nil + end + end +end