From 6ca0cf36ea995db7b8f81c0e606d7088c9127491 Mon Sep 17 00:00:00 2001 From: Kakhorov Aziz Date: Tue, 13 Feb 2024 11:48:26 +0500 Subject: [PATCH] feat: cache for questions#index and questions#show --- Capfile | 25 ++++++------ Gemfile | 4 +- app/helpers/application_helper.rb | 7 ++++ app/models/answer.rb | 2 +- app/models/comment.rb | 2 +- app/models/link.rb | 2 +- app/models/reward.rb | 2 +- app/models/vote.rb | 2 +- app/views/questions/_question.html.slim | 7 ++-- app/views/questions/index.html.slim | 9 +++-- app/views/questions/show.html.slim | 38 ++++++++++--------- config/application.rb | 3 ++ config/deploy.rb | 15 ++++---- config/deploy/production.rb | 16 ++++---- config/deploy/staging.rb | 6 --- config/environments/development.rb | 2 +- config/environments/production.rb | 14 +++---- config/schedule.rb | 4 +- config/unicorn/production.rb | 24 +++++------- spec/features/thinking_sphinx/all_spec.rb | 2 +- spec/features/thinking_sphinx/answers_spec.rb | 2 +- .../features/thinking_sphinx/comments_spec.rb | 2 +- .../thinking_sphinx/questions_spec.rb | 2 +- 23 files changed, 98 insertions(+), 94 deletions(-) diff --git a/Capfile b/Capfile index ae09c8c..9a8f321 100644 --- a/Capfile +++ b/Capfile @@ -1,17 +1,16 @@ # Load DSL and set up stages -require "capistrano/setup" +require 'capistrano/setup' # Include default deployment tasks -require "capistrano/deploy" -require "capistrano/rvm" -require "capistrano/bundler" -require "capistrano/rails" -#require "capistrano/passenger" -require "capistrano/sidekiq" -require "thinking_sphinx/capistrano" -require "whenever/capistrano" -require "capistrano3/unicorn" - +require 'capistrano/deploy' +require 'capistrano/rvm' +require 'capistrano/bundler' +require 'capistrano/rails' +# require "capistrano/passenger" +require 'capistrano/sidekiq' +require 'thinking_sphinx/capistrano' +require 'whenever/capistrano' +require 'capistrano3/unicorn' # Load the SCM plugin appropriate to your project: # @@ -21,7 +20,7 @@ require "capistrano3/unicorn" # require "capistrano/scm/svn" # install_plugin Capistrano::SCM::Svn # or -require "capistrano/scm/git" +require 'capistrano/scm/git' install_plugin Capistrano::SCM::Git install_plugin Capistrano::Sidekiq install_plugin Capistrano::Sidekiq::Systemd @@ -46,4 +45,4 @@ install_plugin Capistrano::Sidekiq::Systemd # require "capistrano/passenger" # Load custom tasks from `lib/capistrano/tasks` if you have any defined -Dir.glob("lib/capistrano/tasks/*.rake").each { |r| import r } +Dir.glob('lib/capistrano/tasks/*.rake').each { |r| import r } diff --git a/Gemfile b/Gemfile index e3608c1..3d57f0e 100644 --- a/Gemfile +++ b/Gemfile @@ -78,12 +78,12 @@ group :development do gem 'spring' gem 'capistrano', require: false + gem 'capistrano3-unicorn', require: false gem 'capistrano-bundler', require: false + gem 'capistrano-passenger', require: false gem 'capistrano-rails', require: false gem 'capistrano-rvm', require: false - gem 'capistrano-passenger', require: false gem 'capistrano-sidekiq', require: false - gem 'capistrano3-unicorn', require: false end group :test do diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index 8911582..3f70b99 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -7,4 +7,11 @@ def class_by_string(object, quantity = 1) def to_class(data) data.to_s.capitalize.constantize end + + def collection_cache_key_for(model) + klass = model.to_s.capitalize.constantize + count = klass.count + max_updated_at = klass.maximum(:updated_at).try(:utc).try(to_s) + "#{model.to_s.pluralize}/collection-#{count}-#{max_updated_at}" + end end diff --git a/app/models/answer.rb b/app/models/answer.rb index 84d5424..851ac98 100644 --- a/app/models/answer.rb +++ b/app/models/answer.rb @@ -3,7 +3,7 @@ class Answer < ApplicationRecord include Commentable has_many :links, dependent: :destroy, as: :linkable - belongs_to :question + belongs_to :question, touch: true belongs_to :author, class_name: 'User' accepts_nested_attributes_for :links, reject_if: :all_blank, allow_destroy: true diff --git a/app/models/comment.rb b/app/models/comment.rb index c3c7253..f0468e2 100644 --- a/app/models/comment.rb +++ b/app/models/comment.rb @@ -1,6 +1,6 @@ class Comment < ApplicationRecord belongs_to :user - belongs_to :commentable, polymorphic: true + belongs_to :commentable, polymorphic: true, touch: true validates :body, presence: true diff --git a/app/models/link.rb b/app/models/link.rb index a48ca90..55cbd76 100644 --- a/app/models/link.rb +++ b/app/models/link.rb @@ -1,6 +1,6 @@ class Link < ApplicationRecord GIST_URL = Regexp.new 'https://gist.github.com/\w+/\w+'.freeze - belongs_to :linkable, polymorphic: true + belongs_to :linkable, polymorphic: true, touch: true validates :name, :url, presence: true diff --git a/app/models/reward.rb b/app/models/reward.rb index 5428704..9a8f412 100644 --- a/app/models/reward.rb +++ b/app/models/reward.rb @@ -1,7 +1,7 @@ class Reward < ApplicationRecord has_one :giving_reward has_one :user, through: :giving_reward - belongs_to :rewardable, polymorphic: true + belongs_to :rewardable, polymorphic: true, touch: true has_one_attached :image diff --git a/app/models/vote.rb b/app/models/vote.rb index b9de715..00fb37f 100644 --- a/app/models/vote.rb +++ b/app/models/vote.rb @@ -1,6 +1,6 @@ class Vote < ApplicationRecord belongs_to :user - belongs_to :votable, polymorphic: true + belongs_to :votable, polymorphic: true, touch: true def self.rank_of_votable(votable) if votable.votes.empty? diff --git a/app/views/questions/_question.html.slim b/app/views/questions/_question.html.slim index b7aec1f..b98d1bf 100644 --- a/app/views/questions/_question.html.slim +++ b/app/views/questions/_question.html.slim @@ -7,9 +7,10 @@ = Vote.rank_of_votable(question) .voting = render 'shared/vote', votable: question - .question-content.col.col-md-6 - p #{question.body} - h6 #{question.title} + - cache question do + .question-content.col.col-md-6 + p #{question.body} + h6 #{question.title} .question-actions.col.col-md-2 p = link_to 'Show', question_path(question) diff --git a/app/views/questions/index.html.slim b/app/views/questions/index.html.slim index bd559f9..7f5d9ac 100644 --- a/app/views/questions/index.html.slim +++ b/app/views/questions/index.html.slim @@ -1,4 +1,5 @@ -- if can?(:create,Question) - p= link_to 'Ask question', new_question_path -.questions-list.question-edit-hide-form - = render @questions \ No newline at end of file +- cache collection_cache_key_for :question do + - if can?(:create,Question) + p= link_to 'Ask question', new_question_path + .questions-list.question-edit-hide-form + = render @questions \ No newline at end of file diff --git a/app/views/questions/show.html.slim b/app/views/questions/show.html.slim index 2dc9caa..8ba43ee 100644 --- a/app/views/questions/show.html.slim +++ b/app/views/questions/show.html.slim @@ -8,25 +8,27 @@ resource: @question, subscription: current_user.subscriptions.find_by(question: @question) - .question-comments id="#{class_by_string(@question)}-#{@question.id}" - .comments-list - = render 'comments/list', commentable: @question - .new-comment - = render 'comments/form', commentable: @question + - cache [@question, 'comment'] + .question-comments id="#{class_by_string(@question)}-#{@question.id}" + .comments-list + = render 'comments/list', commentable: @question + .new-comment + = render 'comments/form', commentable: @question - .question-reward - = render 'shared/reward_link', resource: @question + .question-reward + = render 'shared/reward_link', resource: @question - .answers.card.text-center - h2 Answers: - .answer-errors - = render 'shared/errors', resource: @answer - - if @best_answer - .best-answer.border.border-primary - = render 'answers/answer', answer: @best_answer - .other-answers - = render partial:'answers/answer', collection: @answers + - cache ['answers', @question] + .answers.card.text-center + h2 Answers: + .answer-errors + = render 'shared/errors', resource: @answer + - if @best_answer + .best-answer.border.border-primary + = render 'answers/answer', answer: @best_answer + .other-answers + = render partial:'answers/answer', collection: @answers - - if user_signed_in? - = render 'answers/form' + - if user_signed_in? + = render 'answers/form' diff --git a/config/application.rb b/config/application.rb index 6c9140d..c4f223e 100644 --- a/config/application.rb +++ b/config/application.rb @@ -22,5 +22,8 @@ class Application < Rails::Application helper_specs: false, controller_specs: true end + + config.cache_store = :redis_store, 'redis://localhost:6379/0/cache', { expires_in: 90.minutes } + config.active_record.cache_versioning = false end end diff --git a/config/deploy.rb b/config/deploy.rb index 140fe03..9ea2154 100644 --- a/config/deploy.rb +++ b/config/deploy.rb @@ -1,19 +1,20 @@ # config valid for current version and patch releases of Capistrano -lock "~> 3.18.0" +lock '~> 3.18.0' -set :application, "qna" -set :repo_url, "git@github.com:Azmandius21/qna.git" +set :application, 'qna' +set :repo_url, 'git@github.com:Azmandius21/qna.git' # Default deploy_to directory is /var/www/my_app_name -set :deploy_to, "/home/deployer/qna" -set :deploy_user, "deployer" +set :deploy_to, '/home/deployer/qna' +set :deploy_user, 'deployer' set :pty, false # Default value for :linked_files is [] -append :linked_files, "config/database.yml", 'config/master.key' +append :linked_files, 'config/database.yml', 'config/master.key' # Default value for linked_dirs is [] -append :linked_dirs, "log", "tmp/pids", "tmp/cache", "tmp/sockets", "public/system", "vendor", "storage", "public/uploads" +append :linked_dirs, 'log', 'tmp/pids', 'tmp/cache', 'tmp/sockets', 'public/system', 'vendor', 'storage', + 'public/uploads' after 'deploy:publishing', 'unicorn:restart' diff --git a/config/deploy/production.rb b/config/deploy/production.rb index eea833f..8f39675 100644 --- a/config/deploy/production.rb +++ b/config/deploy/production.rb @@ -3,10 +3,10 @@ # Defines a single server with a list of roles and multiple properties. # You can define all roles on a single server, or split them: -server "79.174.95.43", user: "deployer", roles: %w{app db web}, primary: true +server '79.174.95.43', user: 'deployer', roles: %w[app db web], primary: true set :rails_env, :production -#for sidekiq +# for sidekiq set :stage, :production # Custom SSH Options @@ -17,9 +17,9 @@ # # Global options # -------------- - set :ssh_options, { - keys: %w(/home/aziz/.ssh/id_rsa), - forward_agent: true, - auth_methods: %w(publickey password), - port: 2222 - } +set :ssh_options, { + keys: %w[/home/aziz/.ssh/id_rsa], + forward_agent: true, + auth_methods: %w[publickey password], + port: 2222 +} diff --git a/config/deploy/staging.rb b/config/deploy/staging.rb index 0a3f086..0532b5d 100644 --- a/config/deploy/staging.rb +++ b/config/deploy/staging.rb @@ -7,8 +7,6 @@ # server "example.com", user: "deploy", roles: %w{app web}, other_property: :other_value # server "db.example.com", user: "deploy", roles: %w{db} - - # role-based syntax # ================== @@ -21,8 +19,6 @@ # role :web, %w{user1@primary.com user2@additional.com}, other_property: :other_value # role :db, %w{deploy@example.com} - - # Configuration # ============= # You can set any configuration variable like in config/deploy.rb @@ -31,8 +27,6 @@ # http://capistranorb.com/documentation/getting-started/configuration/ # Feel free to add new variables to customise your setup. - - # Custom SSH Options # ================== # You may pass any option but keep in mind that net/ssh understands a diff --git a/config/environments/development.rb b/config/environments/development.rb index 03fbd18..0996357 100644 --- a/config/environments/development.rb +++ b/config/environments/development.rb @@ -20,7 +20,7 @@ config.action_controller.perform_caching = true config.action_controller.enable_fragment_cache_logging = true - config.cache_store = :memory_store + # config.cache_store = :memory_store config.public_file_server.headers = { 'Cache-Control' => "public, max-age=#{2.days.to_i}" } diff --git a/config/environments/production.rb b/config/environments/production.rb index a98edd7..a899c7a 100644 --- a/config/environments/production.rb +++ b/config/environments/production.rb @@ -65,17 +65,17 @@ # Mailer settings config.action_mailer.perform_caching = false config.action_mailer.default_url_options = { host: '79.174.95.43', port: 80 } - config.action_mailer.default_options = { from: "kaxopob.azizuz@gmail.com", reply_to: "kaxopob.azizuz@gmail.com" } + config.action_mailer.default_options = { from: 'kaxopob.azizuz@gmail.com', reply_to: 'kaxopob.azizuz@gmail.com' } config.action_mailer.delivery_method = :smtp # SMTP settings for gmail config.action_mailer.smtp_settings = { - :address => "smtp.gmail.com", - :port => 587, - :user_name => "kaxopob.azizuz@gmail.com", - :password => Rails.application.credentials[:gmail_password], - :authentication => "plain", - :enable_starttls_auto => true + address: 'smtp.gmail.com', + port: 587, + user_name: 'kaxopob.azizuz@gmail.com', + password: Rails.application.credentials[:gmail_password], + authentication: 'plain', + enable_starttls_auto: true } # Set this to true and configure the email server for immediate delivery to raise delivery errors. diff --git a/config/schedule.rb b/config/schedule.rb index 4e5718a..9a03169 100644 --- a/config/schedule.rb +++ b/config/schedule.rb @@ -14,11 +14,11 @@ # end # every 1.day do - runner "DailyDigestJob.perform_now" + runner 'DailyDigestJob.perform_now' end every 30.minutes do - rake "ts:index" + rake 'ts:index' end # Learn more: http://github.com/javan/whenever diff --git a/config/unicorn/production.rb b/config/unicorn/production.rb index 8ec41f7..a180104 100644 --- a/config/unicorn/production.rb +++ b/config/unicorn/production.rb @@ -1,5 +1,5 @@ # paths -app_path = "/home/deployer/qna" +app_path = '/home/deployer/qna' working_directory "#{app_path}/current" pid "#{app_path}/current/tmp/pids/unicorn.pid" @@ -7,41 +7,37 @@ listen "#{app_path}/shared/tmp/sockets/unicorn.qna.sock", backlog: 64 # logging -stderr_path "log/unicorn.stderr.log" -stdout_path "log/unicorn.stdout.log" +stderr_path 'log/unicorn.stderr.log' +stdout_path 'log/unicorn.stdout.log' # workers worker_processes 2 # use correct Gemfile on restarts -before_exec do |server| +before_exec do |_server| ENV['BUNDLE_GEMFILE'] = "#{app_path}/current/Gemfile" end # preload preload_app true -before_fork do |server, worker| +before_fork do |server, _worker| # the following is highly recomended for Rails + "preload_app true" # as there's no need for the master process to hold a connection - if defined?(ActiveRecord::Base) - ActiveRecord::Base.connection.disconnect! - end + ActiveRecord::Base.connection.disconnect! if defined?(ActiveRecord::Base) # Before forking, kill the master process that belongs to the .oldbin PID. # This enables 0 downtime deploys. old_pid = "#{server.config[:pid]}.oldbin" - if File.exists?(old_pid) && server.pid != old_pid + if File.exist?(old_pid) && server.pid != old_pid begin - Process.kill("QUIT", File.read(old_pid).to_i) + Process.kill('QUIT', File.read(old_pid).to_i) rescue Errno::ENOENT, Errno::ESRCH # someone else did our job for us end end end -after_fork do |server, worker| - if defined?(ActiveRecord::Base) - ActiveRecord::Base.establish_connection - end +after_fork do |_server, _worker| + ActiveRecord::Base.establish_connection if defined?(ActiveRecord::Base) end diff --git a/spec/features/thinking_sphinx/all_spec.rb b/spec/features/thinking_sphinx/all_spec.rb index aebb698..d4b5e6d 100644 --- a/spec/features/thinking_sphinx/all_spec.rb +++ b/spec/features/thinking_sphinx/all_spec.rb @@ -8,7 +8,7 @@ given!(:user) { create(:user, email: 'find_in_user@sphinx.ru') } given!(:question) { create(:question, title: 'find in question', body: 'sphinx') } given!(:answer) { create(:answer, body: 'find in answer sphinx') } - given!(:comment){ create(:comment, commentable: question, body: 'find in comment sphinx')} + given!(:comment) { create(:comment, commentable: question, body: 'find in comment sphinx') } background { visit questions_path } diff --git a/spec/features/thinking_sphinx/answers_spec.rb b/spec/features/thinking_sphinx/answers_spec.rb index a80a985..2a72081 100644 --- a/spec/features/thinking_sphinx/answers_spec.rb +++ b/spec/features/thinking_sphinx/answers_spec.rb @@ -7,7 +7,7 @@ describe 'User search for the answer', js: true do given!(:author) { create(:user, email: 'sphinx@test.ru') } given!(:answer1) { create(:answer, body: 'find in body sphinx') } - given!(:answer2){ create(:answer, author: author, body: 'find in author email')} + given!(:answer2) { create(:answer, author: author, body: 'find in author email') } background { visit questions_path } diff --git a/spec/features/thinking_sphinx/comments_spec.rb b/spec/features/thinking_sphinx/comments_spec.rb index 05831f6..6c557fc 100644 --- a/spec/features/thinking_sphinx/comments_spec.rb +++ b/spec/features/thinking_sphinx/comments_spec.rb @@ -8,7 +8,7 @@ given!(:author) { create(:user, email: 'sphinx@test.ru') } given!(:question) { create(:question) } given!(:comment1) { create(:comment, commentable: question, body: 'find in body sphinx') } - given!(:comment2){ create(:comment, commentable: question, user: author, body: 'find in author email')} + given!(:comment2) { create(:comment, commentable: question, user: author, body: 'find in author email') } background { visit questions_path } diff --git a/spec/features/thinking_sphinx/questions_spec.rb b/spec/features/thinking_sphinx/questions_spec.rb index ad14391..bc966e7 100644 --- a/spec/features/thinking_sphinx/questions_spec.rb +++ b/spec/features/thinking_sphinx/questions_spec.rb @@ -8,7 +8,7 @@ given!(:author) { create(:user, email: 'question@test.ru') } given!(:question1) { create(:question, title: 'find in body', body: 'question body') } given!(:question2) { create(:question, title: 'question title', body: 'find in title') } - given!(:question3){ create(:question, author: author, title: 'title3', body: 'find in author email')} + given!(:question3) { create(:question, author: author, title: 'title3', body: 'find in author email') } background { visit questions_path }