diff --git a/Gemfile b/Gemfile index e6e89a5b5..6c7588a4e 100644 --- a/Gemfile +++ b/Gemfile @@ -14,7 +14,7 @@ end gem "actionpack-action_caching", "~> 1.2" gem "active_record_union", "~> 1.3" -gem "acts-as-taggable-on", "~> 5.0" +gem "acts-as-taggable-on", "~> 6.0" gem "acts_as_follower", github: "thepracticaldev/acts_as_follower", branch: "master" gem "addressable", "~> 2.5", ">= 2.5.2" gem "administrate", "~> 0.11" @@ -25,6 +25,7 @@ gem "algorithmia", "~> 1.0" gem "ancestry", "~> 3.0" gem "autoprefixer-rails", "~> 9.4" gem "aws-sdk-lambda", "~> 1.16" # Just Lambda. For more, install aws-sdk gem +gem "bootsnap", ">= 1.1.0", require: false gem "bourbon", "~> 5.1" gem "buffer", "~> 0.1" gem "carrierwave", "~> 1.3" @@ -73,7 +74,7 @@ gem "pusher", "~> 1.3" gem "pusher-push-notifications", "~> 1.0" gem "rack-host-redirect", "~> 1.3" gem "rack-timeout", "~> 0.5" -gem "rails", "~> 5.1.6" +gem "rails", "~> 5.2", ">= 5.2.3" gem "rails-assets-airbrake-js-client", "~> 1.5", source: "https://rails-assets.org" gem "rails-observers", "~> 0.1" gem "recaptcha", "~> 4.13", require: "recaptcha/rails" diff --git a/Gemfile.lock b/Gemfile.lock index f2ab67819..8ef94dd41 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -19,53 +19,57 @@ GEM remote: https://rails-assets.org/ specs: CFPropertyList (2.3.6) - actioncable (5.1.6.2) - actionpack (= 5.1.6.2) + actioncable (5.2.3) + actionpack (= 5.2.3) nio4r (~> 2.0) - websocket-driver (~> 0.6.1) - actionmailer (5.1.6.2) - actionpack (= 5.1.6.2) - actionview (= 5.1.6.2) - activejob (= 5.1.6.2) + websocket-driver (>= 0.6.1) + actionmailer (5.2.3) + actionpack (= 5.2.3) + actionview (= 5.2.3) + activejob (= 5.2.3) mail (~> 2.5, >= 2.5.4) rails-dom-testing (~> 2.0) - actionpack (5.1.6.2) - actionview (= 5.1.6.2) - activesupport (= 5.1.6.2) + actionpack (5.2.3) + actionview (= 5.2.3) + activesupport (= 5.2.3) rack (~> 2.0) rack-test (>= 0.6.3) rails-dom-testing (~> 2.0) rails-html-sanitizer (~> 1.0, >= 1.0.2) actionpack-action_caching (1.2.0) actionpack (>= 4.0.0, < 6) - actionview (5.1.6.2) - activesupport (= 5.1.6.2) + actionview (5.2.3) + activesupport (= 5.2.3) builder (~> 3.1) erubi (~> 1.4) rails-dom-testing (~> 2.0) rails-html-sanitizer (~> 1.0, >= 1.0.3) active_record_union (1.3.0) activerecord (>= 4.0) - activejob (5.1.6.2) - activesupport (= 5.1.6.2) + activejob (5.2.3) + activesupport (= 5.2.3) globalid (>= 0.3.6) - activemodel (5.1.6.2) - activesupport (= 5.1.6.2) + activemodel (5.2.3) + activesupport (= 5.2.3) activemodel-serializers-xml (1.0.2) activemodel (> 5.x) activesupport (> 5.x) builder (~> 3.1) - activerecord (5.1.6.2) - activemodel (= 5.1.6.2) - activesupport (= 5.1.6.2) - arel (~> 8.0) - activesupport (5.1.6.2) + activerecord (5.2.3) + activemodel (= 5.2.3) + activesupport (= 5.2.3) + arel (>= 9.0) + activestorage (5.2.3) + actionpack (= 5.2.3) + activerecord (= 5.2.3) + marcel (~> 0.3.1) + activesupport (5.2.3) concurrent-ruby (~> 1.0, >= 1.0.2) i18n (>= 0.7, < 2) minitest (~> 5.1) tzinfo (~> 1.1) - acts-as-taggable-on (5.0.0) - activerecord (>= 4.2.8) + acts-as-taggable-on (6.0.0) + activerecord (~> 5.0) addressable (2.5.2) public_suffix (>= 2.0.2, < 4.0) administrate (0.11.0) @@ -96,7 +100,7 @@ GEM algoliasearch (1.26.0) httpclient (~> 2.8, >= 2.8.3) json (>= 1.5.1) - algoliasearch-rails (1.21.0) + algoliasearch-rails (1.22.0) algoliasearch (>= 1.17.0, < 2.0.0) json (>= 1.5.1) algorithmia (1.0.1) @@ -109,7 +113,7 @@ GEM thor (~> 0.18) archive-zip (0.11.0) io-like (~> 0.3.0) - arel (8.0.0) + arel (9.0.0) ast (2.4.0) autoprefixer-rails (9.4.3) execjs @@ -146,6 +150,8 @@ GEM bindex (0.5.0) binding_of_caller (0.8.0) debug_inspector (>= 0.0.1) + bootsnap (1.4.2) + msgpack (~> 1.0) bourbon (5.1.0) sass (~> 3.4) thor (~> 0.19) @@ -610,6 +616,8 @@ GEM lumberjack (1.0.13) mail (2.7.1) mini_mime (>= 0.1.1) + marcel (0.3.3) + mimemagic (~> 0.3.2) memoist (0.16.0) memoizable (0.4.2) thread_safe (~> 0.3, >= 0.3.1) @@ -618,6 +626,7 @@ GEM mime-types (3.2.2) mime-types-data (~> 3.2015) mime-types-data (3.2018.0812) + mimemagic (0.3.3) mini_mime (1.0.1) mini_portile2 (2.4.0) minitest (5.11.3) @@ -635,7 +644,7 @@ GEM connection_pool (~> 2.2) netrc (0.11.0) nio4r (2.3.1) - nokogiri (1.10.1) + nokogiri (1.10.2) mini_portile2 (~> 2.4.0) notiffany (0.1.1) nenv (~> 0.1) @@ -706,17 +715,18 @@ GEM rack-test (1.1.0) rack (>= 1.0, < 3) rack-timeout (0.5.1) - rails (5.1.6.2) - actioncable (= 5.1.6.2) - actionmailer (= 5.1.6.2) - actionpack (= 5.1.6.2) - actionview (= 5.1.6.2) - activejob (= 5.1.6.2) - activemodel (= 5.1.6.2) - activerecord (= 5.1.6.2) - activesupport (= 5.1.6.2) + rails (5.2.3) + actioncable (= 5.2.3) + actionmailer (= 5.2.3) + actionpack (= 5.2.3) + actionview (= 5.2.3) + activejob (= 5.2.3) + activemodel (= 5.2.3) + activerecord (= 5.2.3) + activestorage (= 5.2.3) + activesupport (= 5.2.3) bundler (>= 1.3.0) - railties (= 5.1.6.2) + railties (= 5.2.3) sprockets-rails (>= 2.0.0) rails-assets-airbrake-js-client (1.5.0) rails-dom-testing (2.0.3) @@ -726,12 +736,12 @@ GEM loofah (~> 2.2, >= 2.2.2) rails-observers (0.1.5) activemodel (>= 4.0) - railties (5.1.6.2) - actionpack (= 5.1.6.2) - activesupport (= 5.1.6.2) + railties (5.2.3) + actionpack (= 5.2.3) + activesupport (= 5.2.3) method_source rake (>= 0.8.7) - thor (>= 0.18.1, < 2.0) + thor (>= 0.19.0, < 2.0) rainbow (3.0.0) rake (12.3.2) rb-fsevent (0.10.3) @@ -951,7 +961,7 @@ GEM webpush (0.3.7) hkdf (~> 0.2) jwt (~> 2.0) - websocket-driver (0.6.5) + websocket-driver (0.7.0) websocket-extensions (>= 0.1.0) websocket-extensions (0.1.3) xml-simple (1.1.5) @@ -966,7 +976,7 @@ PLATFORMS DEPENDENCIES actionpack-action_caching (~> 1.2) active_record_union (~> 1.3) - acts-as-taggable-on (~> 5.0) + acts-as-taggable-on (~> 6.0) acts_as_follower! addressable (~> 2.5, >= 2.5.2) administrate (~> 0.11) @@ -980,6 +990,7 @@ DEPENDENCIES aws-sdk-lambda (~> 1.16) better_errors (~> 2.5) binding_of_caller (~> 0.8) + bootsnap (>= 1.1.0) bourbon (~> 5.1) brakeman (~> 4.4) buffer (~> 0.1) @@ -1051,7 +1062,7 @@ DEPENDENCIES pusher-push-notifications (~> 1.0) rack-host-redirect (~> 1.3) rack-timeout (~> 0.5) - rails (~> 5.1.6) + rails (~> 5.2, >= 5.2.3) rails-assets-airbrake-js-client (~> 1.5)! rails-observers (~> 0.1) rb-fsevent (~> 0.10) diff --git a/app/controllers/internal/users_controller.rb b/app/controllers/internal/users_controller.rb index b0b0541ae..9963a2911 100644 --- a/app/controllers/internal/users_controller.rb +++ b/app/controllers/internal/users_controller.rb @@ -27,7 +27,7 @@ class Internal::UsersController < Internal::ApplicationController def show @user = if params[:id] == "unmatched_mentee" - MentorRelationship.unmatched_mentees.order("RANDOM()").first + MentorRelationship.unmatched_mentees.order(Arel.sql("RANDOM()")).first else User.find(params[:id]) end diff --git a/app/controllers/pages_controller.rb b/app/controllers/pages_controller.rb index 2bb672576..51798a2f9 100644 --- a/app/controllers/pages_controller.rb +++ b/app/controllers/pages_controller.rb @@ -62,10 +62,12 @@ class PagesController < ApplicationController def shecoded @top_articles = Article.tagged_with(%w[shecoded shecodedally theycoded], any: true). - where(published: true, approved: true).where("published_at > ? AND score > ?", 3.weeks.ago, 28).order("RANDOM()"). + where(published: true, approved: true).where("published_at > ? AND score > ?", 3.weeks.ago, 28). + order(Arel.sql("RANDOM()")). includes(:user).decorate @articles = Article.tagged_with(%w[shecoded shecodedally theycoded], any: true). - where(published: true, approved: true).where("published_at > ? AND score > ?", 3.weeks.ago, -8).order("RANDOM()"). + where(published: true, approved: true).where("published_at > ? AND score > ?", 3.weeks.ago, -8). + order(Arel.sql("RANDOM()")). where.not(id: @top_articles.pluck(:id)). includes(:user).decorate render layout: false diff --git a/app/labor/sticky_article_collection.rb b/app/labor/sticky_article_collection.rb index 18100f7ae..668acb731 100644 --- a/app/labor/sticky_article_collection.rb +++ b/app/labor/sticky_article_collection.rb @@ -27,7 +27,7 @@ class StickyArticleCollection where(published: true). where.not(id: article.id, user_id: article.user_id). where("featured_number > ?", 5.days.ago.to_i). - order("RANDOM()"). + order(Arel.sql("RANDOM()")). limit(8) end @@ -40,7 +40,7 @@ class StickyArticleCollection where(published: true). where.not(id: article.id, user_id: article.user_id). where("featured_number > ?", 5.days.ago.to_i). - order("RANDOM()"). + order(Arel.sql("RANDOM()")). limit(10 - tag_articles.size) end diff --git a/app/labor/unread_notifications_emailer.rb b/app/labor/unread_notifications_emailer.rb index e544ca9c9..936a06230 100644 --- a/app/labor/unread_notifications_emailer.rb +++ b/app/labor/unread_notifications_emailer.rb @@ -5,7 +5,7 @@ class UnreadNotificationsEmailer # This will run once a day (defined outside the app) # only to users who have made at least one comment or article. # We can change this up later. - users = User.where("comments_count > ? OR reactions_count > ?", 0, 0).order("RANDOM()").limit(num) + users = User.where("comments_count > ? OR reactions_count > ?", 0, 0).order(Arel.sql("RANDOM()")).limit(num) users.find_each do |user| UnreadNotificationsEmailer.new(user).send_email_if_appropriate rescue StandardError => e diff --git a/app/liquid_tags/tweet_tag.rb b/app/liquid_tags/tweet_tag.rb index 84cbe20e1..f8d3bee33 100644 --- a/app/liquid_tags/tweet_tag.rb +++ b/app/liquid_tags/tweet_tag.rb @@ -11,10 +11,11 @@ class TweetTag < LiquidTagBase def render(_context) media_div = "" quote_div = "" + if @tweet.extended_entities_serialized.present? && @tweet.extended_entities_serialized[:media] && @tweet.extended_entities_serialized[:media].size == 1 media_item = @tweet.extended_entities_serialized[:media].first if media_item[:type] == "animated_gif" || media_item[:type] == "video" - play_butt = image_tag("/assets/play-butt.svg", class: "ltag__twitter-tweet__play-butt") + play_butt = image_tag("/assets/play-butt.svg", class: "ltag__twitter-tweet__play-butt", alt: "Play butt") preview_div = "
#{play_butt}
" video_div = "
" media_div = "
#{preview_div}#{video_div}
" @@ -31,6 +32,7 @@ class TweetTag < LiquidTagBase quoted_status = @tweet.full_fetched_object_serialized[:quoted_status] quote_div = "
@#{quoted_status[:user][:screen_name]}
#{quoted_status[:full_text]}
" end + "
'\ +media_div + \ @@ -47,9 +49,9 @@ class TweetTag < LiquidTagBase '
' + @tweet.tweeted_at.strftime("%H:%M %p - %d %b %Y") + "
"\ +quote_div + \ '
'\ - '"\ - '" + @tweet.retweet_count.to_s + \ - '" + @tweet.favorite_count.to_s + \ + '"\ + '" + @tweet.retweet_count.to_s + \ + '" + @tweet.favorite_count.to_s + \ "
"\ ""\ "
" diff --git a/app/models/chat_channel.rb b/app/models/chat_channel.rb index 6d93daf6f..abb220ce8 100644 --- a/app/models/chat_channel.rb +++ b/app/models/chat_channel.rb @@ -143,10 +143,6 @@ class ChatChannel < ApplicationRecord obj end - def pending_users_select_fields - pending_users.select(:id, :username, :name) - end - def channel_mod_ids mod_users.pluck(:id) end @@ -161,4 +157,10 @@ class ChatChannel < ApplicationRecord id: membership.user_id } end + + private + + def pending_users_select_fields + pending_users.select(:id, :username, :name, :updated_at) + end end diff --git a/app/models/html_variant.rb b/app/models/html_variant.rb index a169ff26d..f4439b926 100644 --- a/app/models/html_variant.rb +++ b/app/models/html_variant.rb @@ -30,7 +30,7 @@ class HtmlVariant < ApplicationRecord end def self.find_random_for_test(tags_array, group) - where(group: group, approved: true, published: true, target_tag: tags_array).order("RANDOM()").first + where(group: group, approved: true, published: true, target_tag: tags_array).order(Arel.sql("RANDOM()")).first end private diff --git a/app/services/suggester/articles/classic.rb b/app/services/suggester/articles/classic.rb index 481b090c5..a07496272 100644 --- a/app/services/suggester/articles/classic.rb +++ b/app/services/suggester/articles/classic.rb @@ -29,7 +29,7 @@ module Suggester where(published: true, featured: true). where("positive_reactions_count > ?", MIN_REACTION_COUNT). where("published_at > ?", 10.months.ago). - order("RANDOM()") + order(Arel.sql("RANDOM()")) end end diff --git a/app/services/suggester/articles/high_quality.rb b/app/services/suggester/articles/high_quality.rb index b92764c6f..fab38b476 100644 --- a/app/services/suggester/articles/high_quality.rb +++ b/app/services/suggester/articles/high_quality.rb @@ -11,7 +11,7 @@ module Suggester Article.where(published: true, featured: true). includes(:user). where("positive_reactions_count > ?", MIN_HQ_REACTION_COUNT). - order("RANDOM()"). + order(Arel.sql("RANDOM()")). limited_column_select. where.not(id: @not_ids). limit(num) diff --git a/app/services/suggester/users/sidebar.rb b/app/services/suggester/users/sidebar.rb index c85c3b570..784c7b48f 100644 --- a/app/services/suggester/users/sidebar.rb +++ b/app/services/suggester/users/sidebar.rb @@ -20,7 +20,7 @@ module Suggester group_one = User.select(:id, :name, :username, :profile_image, :summary).where(id: user_ids). order("reputation_modifier DESC").limit(20).to_a group_two = User.select(:id, :name, :username, :profile_image, :summary).where(id: user_ids). - order("RANDOM()").limit(20).to_a + order(Arel.sql("RANDOM()")).limit(20).to_a (group_one + group_two).uniq end end diff --git a/app/views/articles/_sidebar.html.erb b/app/views/articles/_sidebar.html.erb index a68880a5b..258b94d51 100644 --- a/app/views/articles/_sidebar.html.erb +++ b/app/views/articles/_sidebar.html.erb @@ -61,7 +61,7 @@ <% end %> <% cache("display-area-left-#{rand(5)}", expires_in: 5.minutes) do %> - <% @left_sidebar_ad = DisplayAd.where(approved: true, published: true, placement_area: "sidebar_left").order("RANDOM()").first %> + <% @left_sidebar_ad = DisplayAd.where(approved: true, published: true, placement_area: "sidebar_left").order(Arel.sql("RANDOM()")).first %> <% if @left_sidebar_ad %>
diff --git a/app/views/articles/_sidebar_additional.html.erb b/app/views/articles/_sidebar_additional.html.erb index d10dc875e..737d1bd81 100644 --- a/app/views/articles/_sidebar_additional.html.erb +++ b/app/views/articles/_sidebar_additional.html.erb @@ -19,7 +19,7 @@
<% end %> <% cache("main-article-right-sidebar-discussions-#{params[:timeframe]}", expires_in: (params[:timeframe].blank? ? 120 : 360).seconds) do %> - <% @sidebar_ad = DisplayAd.where(approved: true, published: true, placement_area: "sidebar_right").order("RANDOM()").first %> + <% @sidebar_ad = DisplayAd.where(approved: true, published: true, placement_area: "sidebar_right").order(Arel.sql("RANDOM()")).first %> <% if @sidebar_ad %>
diff --git a/bin/bundle b/bin/bundle index 9c2e5f741..524dfd3f2 100755 --- a/bin/bundle +++ b/bin/bundle @@ -11,91 +11,91 @@ require "rubygems" m = Module.new do - module_function + module_function - def invoked_as_script? - File.expand_path($0) == File.expand_path(__FILE__) + def invoked_as_script? + File.expand_path($0) == File.expand_path(__FILE__) + end + + def env_var_version + ENV["BUNDLER_VERSION"] + end + + def cli_arg_version + return unless invoked_as_script? # don't want to hijack other binstubs + return unless "update".start_with?(ARGV.first || " ") # must be running `bundle update` + bundler_version = nil + update_index = nil + ARGV.each_with_index do |a, i| + if update_index && update_index.succ == i && a =~ Gem::Version::ANCHORED_VERSION_PATTERN + bundler_version = a end + next unless a =~ /\A--bundler(?:[= ](#{Gem::Version::VERSION_PATTERN}))?\z/ + bundler_version = $1 || ">= 0.a" + update_index = i + end + bundler_version + end - def env_var_version - ENV["BUNDLER_VERSION"] + def gemfile + gemfile = ENV["BUNDLE_GEMFILE"] + return gemfile if gemfile && !gemfile.empty? + + File.expand_path("../../Gemfile", __FILE__) + end + + def lockfile + lockfile = + case File.basename(gemfile) + when "gems.rb" then gemfile.sub(/\.rb$/, gemfile) + else "#{gemfile}.lock" end + File.expand_path(lockfile) + end - def cli_arg_version - return unless invoked_as_script? # don't want to hijack other binstubs - return unless "update".start_with?(ARGV.first || " ") # must be running `bundle update` - bundler_version = nil - update_index = nil - ARGV.each_with_index do |a, i| - if update_index && update_index.succ == i && a =~ Gem::Version::ANCHORED_VERSION_PATTERN - bundler_version = a - end - next unless a =~ /\A--bundler(?:[= ](#{Gem::Version::VERSION_PATTERN}))?\z/ - bundler_version = $1 || ">= 0.a" - update_index = i - end - bundler_version - end + def lockfile_version + return unless File.file?(lockfile) + lockfile_contents = File.read(lockfile) + return unless lockfile_contents =~ /\n\nBUNDLED WITH\n\s{2,}(#{Gem::Version::VERSION_PATTERN})\n/ + Regexp.last_match(1) + end - def gemfile - gemfile = ENV["BUNDLE_GEMFILE"] - return gemfile if gemfile && !gemfile.empty? + def bundler_version + @bundler_version ||= begin + env_var_version || cli_arg_version || + lockfile_version || "#{Gem::Requirement.default}.a" + end + end - File.expand_path("../Gemfile", __dir__) - end + def load_bundler! + ENV["BUNDLE_GEMFILE"] ||= gemfile - def lockfile - lockfile = - case File.basename(gemfile) - when "gems.rb" then gemfile.sub(/\.rb$/, gemfile) - else "#{gemfile}.lock" - end - File.expand_path(lockfile) - end + # must dup string for RG < 1.8 compatibility + activate_bundler(bundler_version.dup) + end - def lockfile_version - return unless File.file?(lockfile) - lockfile_contents = File.read(lockfile) - return unless lockfile_contents =~ /\n\nBUNDLED WITH\n\s{2,}(#{Gem::Version::VERSION_PATTERN})\n/ - Regexp.last_match(1) - end + def activate_bundler(bundler_version) + if Gem::Version.correct?(bundler_version) && Gem::Version.new(bundler_version).release < Gem::Version.new("2.0") + bundler_version = "< 2" + end + gem_error = activation_error_handling do + gem "bundler", bundler_version + end + return if gem_error.nil? + require_error = activation_error_handling do + require "bundler/version" + end + return if require_error.nil? && Gem::Requirement.new(bundler_version).satisfied_by?(Gem::Version.new(Bundler::VERSION)) + warn "Activating bundler (#{bundler_version}) failed:\n#{gem_error.message}\n\nTo install the version of bundler this project requires, run `gem install bundler -v '#{bundler_version}'`" + exit 42 + end - def bundler_version - @bundler_version ||= begin - env_var_version || cli_arg_version || - lockfile_version || "#{Gem::Requirement.default}.a" - end - end - - def load_bundler! - ENV["BUNDLE_GEMFILE"] ||= gemfile - - # must dup string for RG < 1.8 compatibility - activate_bundler(bundler_version.dup) - end - - def activate_bundler(bundler_version) - if Gem::Version.correct?(bundler_version) && Gem::Version.new(bundler_version).release < Gem::Version.new("2.0") - bundler_version = "< 2" - end - gem_error = activation_error_handling do - gem "bundler", bundler_version - end - return if gem_error.nil? - require_error = activation_error_handling do - require "bundler/version" - end - return if require_error.nil? && Gem::Requirement.new(bundler_version).satisfied_by?(Gem::Version.new(Bundler::VERSION)) - warn "Activating bundler (#{bundler_version}) failed:\n#{gem_error.message}\n\nTo install the version of bundler this project requires, run `gem install bundler -v '#{bundler_version}'`" - exit 42 - end - - def activation_error_handling - yield - nil - rescue StandardError, LoadError => e - e - end + def activation_error_handling + yield + nil + rescue StandardError, LoadError => e + e + end end m.load_bundler! diff --git a/bin/rails b/bin/rails index 36b01a1ce..073966023 100755 --- a/bin/rails +++ b/bin/rails @@ -1,9 +1,4 @@ #!/usr/bin/env ruby -begin - load File.expand_path("spring", __dir__) -rescue LoadError => e - raise unless e.message.include?("spring") -end -APP_PATH = File.expand_path("../config/application", __dir__) -require_relative "../config/boot" -require "rails/commands" +APP_PATH = File.expand_path('../config/application', __dir__) +require_relative '../config/boot' +require 'rails/commands' diff --git a/bin/rake b/bin/rake index 660472a03..17240489f 100755 --- a/bin/rake +++ b/bin/rake @@ -1,9 +1,4 @@ #!/usr/bin/env ruby -begin - load File.expand_path("spring", __dir__) -rescue LoadError => e - raise unless e.message.include?("spring") -end -require_relative "../config/boot" -require "rake" +require_relative '../config/boot' +require 'rake' Rake.application.run diff --git a/bin/setup b/bin/setup index 9ac9032a4..5ff26024f 100755 --- a/bin/setup +++ b/bin/setup @@ -1,10 +1,9 @@ #!/usr/bin/env ruby -require "pathname" -require "fileutils" +require 'fileutils' include FileUtils # path to your application root. -APP_ROOT = Pathname.new File.expand_path("..", __dir__) +APP_ROOT = File.expand_path('..', __dir__) def system!(*args) system(*args) || abort("\n== Command #{args} failed ==") @@ -14,29 +13,24 @@ chdir APP_ROOT do # This script is a starting point to setup your application. # Add necessary setup steps to this file. - puts "== Installing dependencies ==" - system! "gem install bundler --conservative" - system("bundle check") || system!("bundle install") + puts '== Installing dependencies ==' + system! 'gem install bundler --conservative' + system('bundle check') || system!('bundle install') # Install JavaScript dependencies if using Yarn - system("bin/yarn") + system('bin/yarn') - # puts "\n== Copying sample files ==" - # unless File.exist?('config/database.yml') - # cp 'config/database.yml.sample', 'config/database.yml' - # end + puts "\n== Copying sample files ==" + unless File.exist?('config/database.yml') + cp 'config/database.yml.sample', 'config/database.yml' + end puts "\n== Preparing database ==" - system! "bin/rails db:setup" - - puts "\n== Resolve Rails 5.0 & 5.1 specfic issue (open bin/setup for more info) ==" - # This solution was found here https://github.com/rails/rails/issues/26731#issuecomment-302446525 - # This line is to remove manual need to run a separate manual migration upon calling rspec - system! "RAILS_ENV=test bin/rails db:environment:set" + system! 'bin/rails db:setup' puts "\n== Removing old logs and tempfiles ==" - system! "bin/rails log:clear tmp:clear" + system! 'bin/rails log:clear tmp:clear' puts "\n== Restarting application server ==" - system! "bin/rails restart" + system! 'bin/rails restart' end diff --git a/bin/update b/bin/update index db28935ec..58bfaed51 100755 --- a/bin/update +++ b/bin/update @@ -1,10 +1,9 @@ #!/usr/bin/env ruby -require "pathname" -require "fileutils" +require 'fileutils' include FileUtils # path to your application root. -APP_ROOT = Pathname.new File.expand_path("..", __dir__) +APP_ROOT = File.expand_path('..', __dir__) def system!(*args) system(*args) || abort("\n== Command #{args} failed ==") @@ -14,16 +13,19 @@ chdir APP_ROOT do # This script is a way to update your development environment automatically. # Add necessary update steps to this file. - puts "== Installing dependencies ==" - system! "gem install bundler --conservative" - system("bundle check") || system!("bundle install") + puts '== Installing dependencies ==' + system! 'gem install bundler --conservative' + system('bundle check') || system!('bundle install') + + # Install JavaScript dependencies if using Yarn + # system('bin/yarn') puts "\n== Updating database ==" - system! "bin/rails db:migrate" + system! 'bin/rails db:migrate' puts "\n== Removing old logs and tempfiles ==" - system! "bin/rails log:clear tmp:clear" + system! 'bin/rails log:clear tmp:clear' puts "\n== Restarting application server ==" - system! "bin/rails restart" + system! 'bin/rails restart' end diff --git a/bin/yarn b/bin/yarn index f09cacd1c..460dd565b 100755 --- a/bin/yarn +++ b/bin/yarn @@ -1,9 +1,11 @@ #!/usr/bin/env ruby -VENDOR_PATH = File.expand_path("..", __dir__) -Dir.chdir(VENDOR_PATH) do - exec "yarnpkg #{ARGV.join(' ')}" -rescue Errno::ENOENT - warn "Yarn executable was not detected in the system." - warn "Download Yarn at https://yarnpkg.com/en/docs/install" - exit 1 +APP_ROOT = File.expand_path('..', __dir__) +Dir.chdir(APP_ROOT) do + begin + exec "yarnpkg", *ARGV + rescue Errno::ENOENT + $stderr.puts "Yarn executable was not detected in the system." + $stderr.puts "Download Yarn at https://yarnpkg.com/en/docs/install" + exit 1 + end end diff --git a/config/boot.rb b/config/boot.rb index 282011619..988a5ddc4 100644 --- a/config/boot.rb +++ b/config/boot.rb @@ -1,3 +1,4 @@ ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__) require "bundler/setup" # Set up gems listed in the Gemfile. +require "bootsnap/setup" # Speed up boot time by caching expensive operations. diff --git a/config/cable.yml b/config/cable.yml index 38cd3a703..dffee2a7b 100644 --- a/config/cable.yml +++ b/config/cable.yml @@ -6,5 +6,5 @@ test: production: adapter: redis - url: redis://localhost:6379/1 + url: <%= ENV.fetch("REDIS_URL") { "redis://localhost:6379/1" } %> channel_prefix: practical_developer_production diff --git a/config/environments/development.rb b/config/environments/development.rb index e7ebe3a1c..c7ec48f0e 100644 --- a/config/environments/development.rb +++ b/config/environments/development.rb @@ -25,7 +25,7 @@ Rails.application.configure do config.cache_store = :memory_store config.public_file_server.headers = { - "Cache-Control" => "public, max-age=172800" + "Cache-Control" => "public, max-age=#{2.days.to_i}" } else config.action_controller.perform_caching = false @@ -42,6 +42,9 @@ Rails.application.configure do # Raise an error on page load if there are pending migrations. config.active_record.migration_error = :page_load + # Highlight code that triggered database queries in logs. + config.active_record.verbose_query_logs = true + # Debug mode disables concatenation and preprocessing of assets. # This option may cause significant delays in view rendering with a large # number of complex assets. diff --git a/config/environments/test.rb b/config/environments/test.rb index 85d96f7d6..5a6bad87c 100644 --- a/config/environments/test.rb +++ b/config/environments/test.rb @@ -17,7 +17,7 @@ Rails.application.configure do # Configure static file server for tests with Cache-Control for performance. config.public_file_server.enabled = true config.public_file_server.headers = { - "Cache-Control" => "public, max-age=3600" + "Cache-Control" => "public, max-age=#{1.hour.to_i}" } # Show full error reports and disable caching. @@ -29,6 +29,10 @@ Rails.application.configure do # Disable request forgery protection in test environment. config.action_controller.allow_forgery_protection = false + + # Store uploaded files on the local file system in a temporary directory + config.active_storage.service = :test + config.action_mailer.perform_caching = false # Tell Action Mailer not to deliver emails to the real world. diff --git a/config/initializers/application_controller_renderer.rb b/config/initializers/application_controller_renderer.rb index 51639b67a..89d2efab2 100644 --- a/config/initializers/application_controller_renderer.rb +++ b/config/initializers/application_controller_renderer.rb @@ -1,6 +1,8 @@ # Be sure to restart your server when you modify this file. -# ApplicationController.renderer.defaults.merge!( -# http_host: 'example.org', -# https: false -# ) +# ActiveSupport::Reloader.to_prepare do +# ApplicationController.renderer.defaults.merge!( +# http_host: 'example.org', +# https: false +# ) +# end diff --git a/config/initializers/content_security_policy.rb b/config/initializers/content_security_policy.rb new file mode 100644 index 000000000..d3bcaa5ec --- /dev/null +++ b/config/initializers/content_security_policy.rb @@ -0,0 +1,25 @@ +# Be sure to restart your server when you modify this file. + +# Define an application-wide content security policy +# For further information see the following documentation +# https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy + +# Rails.application.config.content_security_policy do |policy| +# policy.default_src :self, :https +# policy.font_src :self, :https, :data +# policy.img_src :self, :https, :data +# policy.object_src :none +# policy.script_src :self, :https +# policy.style_src :self, :https + +# # Specify URI for violation reports +# # policy.report_uri "/csp-violation-report-endpoint" +# end + +# If you are using UJS then enable automatic nonce generation +# Rails.application.config.content_security_policy_nonce_generator = -> request { SecureRandom.base64(16) } + +# Report CSP violations to a specified URI +# For further information see the following documentation: +# https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy-Report-Only +# Rails.application.config.content_security_policy_report_only = true diff --git a/config/initializers/new_framework_defaults_5_2.rb b/config/initializers/new_framework_defaults_5_2.rb new file mode 100644 index 000000000..c383d072b --- /dev/null +++ b/config/initializers/new_framework_defaults_5_2.rb @@ -0,0 +1,38 @@ +# Be sure to restart your server when you modify this file. +# +# This file contains migration options to ease your Rails 5.2 upgrade. +# +# Once upgraded flip defaults one by one to migrate to the new default. +# +# Read the Guide for Upgrading Ruby on Rails for more info on each option. + +# Make Active Record use stable #cache_key alongside new #cache_version method. +# This is needed for recyclable cache keys. +# Rails.application.config.active_record.cache_versioning = true + +# Use AES-256-GCM authenticated encryption for encrypted cookies. +# Also, embed cookie expiry in signed or encrypted cookies for increased security. +# +# This option is not backwards compatible with earlier Rails versions. +# It's best enabled when your entire app is migrated and stable on 5.2. +# +# Existing cookies will be converted on read then written with the new scheme. +# Rails.application.config.action_dispatch.use_authenticated_cookie_encryption = true + +# Use AES-256-GCM authenticated encryption as default cipher for encrypting messages +# instead of AES-256-CBC, when use_authenticated_message_encryption is set to true. +# Rails.application.config.active_support.use_authenticated_message_encryption = true + +# Add default protection from forgery to ActionController::Base instead of in +# ApplicationController. +# Rails.application.config.action_controller.default_protect_from_forgery = true + +# Store boolean values are in sqlite3 databases as 1 and 0 instead of 't' and +# 'f' after migrating old data. +# Rails.application.config.active_record.sqlite3.represent_boolean_as_integer = true + +# Use SHA-1 instead of MD5 to generate non-sensitive digests, such as the ETag header. +# Rails.application.config.active_support.use_sha1_digests = true + +# Make `form_with` generate id attributes for any generated HTML tags. +# Rails.application.config.action_view.form_with_generates_ids = true diff --git a/config/puma.rb b/config/puma.rb index 3d5df9063..b25810d4f 100644 --- a/config/puma.rb +++ b/config/puma.rb @@ -1,15 +1,37 @@ -workers Integer(ENV["WEB_CONCURRENCY"] || 2) -threads_count = Integer(ENV["MAX_THREADS"] || 5) +# Puma can serve each request in a thread from an internal thread pool. +# The `threads` method setting takes two numbers: a minimum and maximum. +# Any libraries that use thread pools should be configured to match +# the maximum value specified for Puma. Default is set to 5 threads for minimum +# and maximum; this matches the default thread size of Active Record. +# +threads_count = ENV.fetch("RAILS_MAX_THREADS") { 5 } threads threads_count, threads_count -worker_timeout 15 -worker_shutdown_timeout 8 +# Specifies the `port` that Puma will listen on to receive requests; default is 3000. +# +port ENV.fetch("PORT") { 3000 } +# Specifies the `environment` that Puma will run in. +# +environment ENV.fetch("RAILS_ENV") { "development" } + +# Specifies the number of `workers` to boot in clustered mode. +# Workers are forked webserver processes. If using threads and workers together +# the concurrency of the application would be max `threads` * `workers`. +# Workers do not work on JRuby or Windows (both of which do not support +# processes). +# +workers ENV.fetch("WEB_CONCURRENCY") { 2 } + +# Use the `preload_app!` method when specifying a `workers` number. +# This directive tells Puma to first boot the application and load code +# before forking the application. This takes advantage of Copy On Write +# process behavior so workers use less memory. +# preload_app! -rackup DefaultRackup -port ENV["PORT"] || 3000 -environment ENV["RACK_ENV"] || "development" +# Allow puma to be restarted by `rails restart` command. +plugin :tmp_restart on_worker_boot do # Worker specific setup for Rails 4.1+ diff --git a/config/storage.yml b/config/storage.yml new file mode 100644 index 000000000..d32f76e8f --- /dev/null +++ b/config/storage.yml @@ -0,0 +1,34 @@ +test: + service: Disk + root: <%= Rails.root.join("tmp/storage") %> + +local: + service: Disk + root: <%= Rails.root.join("storage") %> + +# Use rails credentials:edit to set the AWS secrets (as aws:access_key_id|secret_access_key) +# amazon: +# service: S3 +# access_key_id: <%= Rails.application.credentials.dig(:aws, :access_key_id) %> +# secret_access_key: <%= Rails.application.credentials.dig(:aws, :secret_access_key) %> +# region: us-east-1 +# bucket: your_own_bucket + +# Remember not to checkin your GCS keyfile to a repository +# google: +# service: GCS +# project: your_project +# credentials: <%= Rails.root.join("path/to/gcs.keyfile") %> +# bucket: your_own_bucket + +# Use rails credentials:edit to set the Azure Storage secret (as azure_storage:storage_access_key) +# microsoft: +# service: AzureStorage +# storage_account_name: your_account_name +# storage_access_key: <%= Rails.application.credentials.dig(:azure_storage, :storage_access_key) %> +# container: your_container_name + +# mirror: +# service: Mirror +# primary: local +# mirrors: [ amazon, google, microsoft ] diff --git a/db/seeds.rb b/db/seeds.rb index ae5ca8d13..41ae3c617 100644 --- a/db/seeds.rb +++ b/db/seeds.rb @@ -72,7 +72,7 @@ Article.clear_index! 25.times do |i| tags = [] tags << "discuss" if (i % 3).zero? - tags.concat Tag.order("RANDOM()").select("name").first(3).map(&:name) + tags.concat Tag.order(Arel.sql("RANDOM()")).select("name").first(3).map(&:name) markdown = <<~MARKDOWN --- @@ -91,7 +91,7 @@ Article.clear_index! body_markdown: markdown, featured: true, show_comments: true, - user_id: User.order("RANDOM()").first.id, + user_id: User.order(Arel.sql("RANDOM()")).first.id, ) end @@ -103,8 +103,8 @@ Comment.clear_index! 30.times do attributes = { body_markdown: Faker::Hipster.paragraph(1), - user_id: User.order("RANDOM()").first.id, - commentable_id: Article.order("RANDOM()").first.id, + user_id: User.order(Arel.sql("RANDOM()")).first.id, + commentable_id: Article.order(Arel.sql("RANDOM()")).first.id, commentable_type: "Article" } Comment.create!(attributes) diff --git a/spec/support/fixtures/approvals/liquid_tweet_tag_spec.approved.html b/spec/support/fixtures/approvals/liquid_tweet_tag_spec.approved.html index 92e78e7c9..bbd8e35e9 100644 --- a/spec/support/fixtures/approvals/liquid_tweet_tag_spec.approved.html +++ b/spec/support/fixtures/approvals/liquid_tweet_tag_spec.approved.html @@ -5,7 +5,7 @@