diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index bbc214b6fa..969746370b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -11,6 +11,7 @@ jobs: rails: - "6.0" - "6.1" + - "7.0" ruby: - "2.6" - "2.7" @@ -18,6 +19,13 @@ jobs: database: - mysql - postgresql + exclude: + - rails: "7.0" + ruby: "2.6" + database: mysql + - rails: "7.0" + ruby: "2.6" + database: postgresql env: DB: ${{ matrix.database }} DB_USER: alchemy_user diff --git a/Gemfile b/Gemfile index 71ebc58f16..597dc1910f 100644 --- a/Gemfile +++ b/Gemfile @@ -3,11 +3,13 @@ source "https://rubygems.org" gemspec -rails_version = ENV.fetch("RAILS_VERSION", 6.1).to_f +rails_version = ENV.fetch("RAILS_VERSION", 7.0).to_f # Necessary until a new 6.1.5 version has been released # https://github.com/rails/rails/pull/44691 if rails_version.to_s.match?(/6.1/) gem "rails", git: "https://github.com/rails/rails", branch: "6-1-stable" +elsif rails_version.to_s.match?(/7.0/) + gem "rails", git: "https://github.com/rails/rails", branch: "7-0-stable" else gem "rails", "~> #{rails_version}.0" end diff --git a/alchemy_cms.gemspec b/alchemy_cms.gemspec index e4c160edfd..259f6e02b5 100644 --- a/alchemy_cms.gemspec +++ b/alchemy_cms.gemspec @@ -29,7 +29,7 @@ Gem::Specification.new do |gem| activesupport railties ].each do |rails_gem| - gem.add_runtime_dependency rails_gem, [">= 6.0", "< 6.2"] + gem.add_runtime_dependency rails_gem, [">= 6.0", "< 7.1"] end gem.add_runtime_dependency "active_model_serializers", ["~> 0.10.0"] diff --git a/app/controllers/alchemy/admin/elements_controller.rb b/app/controllers/alchemy/admin/elements_controller.rb index 826eae9737..c9eeac749d 100644 --- a/app/controllers/alchemy/admin/elements_controller.rb +++ b/app/controllers/alchemy/admin/elements_controller.rb @@ -106,18 +106,14 @@ def fold def element_includes [ { - contents: { - essence: :ingredient_association, - }, + contents: :essence, ingredients: :related_object, }, :tags, { all_nested_elements: [ { - contents: { - essence: :ingredient_association, - }, + contents: :essence, ingredients: :related_object, }, :tags, diff --git a/app/controllers/alchemy/admin/pages_controller.rb b/app/controllers/alchemy/admin/pages_controller.rb index 7c0219cbab..9d8e908a11 100644 --- a/app/controllers/alchemy/admin/pages_controller.rb +++ b/app/controllers/alchemy/admin/pages_controller.rb @@ -179,9 +179,12 @@ def unlock @pages_locked_by_user = Page.from_current_site.locked_by(current_alchemy_user) respond_to do |format| format.js - format.html { - redirect_to params[:redirect_to].blank? ? admin_pages_path : params[:redirect_to] - } + format.html do + redirect_to( + params[:redirect_to].presence || admin_pages_path, + allow_other_host: true, + ) + end end end diff --git a/app/controllers/alchemy/api/contents_controller.rb b/app/controllers/alchemy/api/contents_controller.rb index c864de5fe2..ee4a1dc227 100644 --- a/app/controllers/alchemy/api/contents_controller.rb +++ b/app/controllers/alchemy/api/contents_controller.rb @@ -46,11 +46,7 @@ def show private def content_includes - [ - { - essence: :ingredient_association, - }, - ] + %i[essence] end end end diff --git a/app/controllers/alchemy/api/elements_controller.rb b/app/controllers/alchemy/api/elements_controller.rb index 9fb6fe129f..168c242e0a 100644 --- a/app/controllers/alchemy/api/elements_controller.rb +++ b/app/controllers/alchemy/api/elements_controller.rb @@ -47,18 +47,14 @@ def element_includes { nested_elements: [ { - contents: { - essence: :ingredient_association, - }, + contents: :essence, ingredients: :related_object, }, :tags, ], }, { - contents: { - essence: :ingredient_association, - }, + contents: :essence, ingredients: :related_object, }, :tags, diff --git a/app/controllers/alchemy/api/pages_controller.rb b/app/controllers/alchemy/api/pages_controller.rb index 7a914fc41c..aa483648cf 100644 --- a/app/controllers/alchemy/api/pages_controller.rb +++ b/app/controllers/alchemy/api/pages_controller.rb @@ -112,17 +112,13 @@ def page_includes { nested_elements: [ { - contents: { - essence: :ingredient_association, - }, + contents: :essence, }, :tags, ], }, { - contents: { - essence: :ingredient_association, - }, + contents: :essence, }, :tags, ], diff --git a/lib/alchemy/engine.rb b/lib/alchemy/engine.rb index c3ec702565..47a03647ae 100644 --- a/lib/alchemy/engine.rb +++ b/lib/alchemy/engine.rb @@ -37,7 +37,7 @@ class Engine < Rails::Engine end end - initializer "alchemy.userstamp" do + config.after_initialize do if Alchemy.user_class ActiveSupport.on_load(:active_record) do Alchemy.user_class.model_stamper diff --git a/lib/alchemy/essence.rb b/lib/alchemy/essence.rb index 0feb2fc97d..54f8e2ade4 100644 --- a/lib/alchemy/essence.rb +++ b/lib/alchemy/essence.rb @@ -3,18 +3,6 @@ require "active_record" module Alchemy #:nodoc: - # A bogus association that skips eager loading for essences not having an ingredient association - class IngredientAssociation < ActiveRecord::Associations::BelongsToAssociation - # Skip eager loading if called by Rails' preloader - def klass - if caller.any? { |line| line =~ /preloader\.rb/ } - nil - else - super - end - end - end - module Essence #:nodoc: def self.included(base) base.extend(ClassMethods) @@ -43,8 +31,6 @@ def acts_as_essence(options = {}) ingredient_column: "body", }.update(options) - @_classes_with_ingredient_association ||= [] - class_eval <<-RUBY, __FILE__, __LINE__ + 1 attr_writer :validation_errors include Alchemy::Essence::InstanceMethods @@ -87,18 +73,6 @@ def preview_text_column alias_method :#{configuration[:ingredient_column]}, :ingredient_association alias_method :#{configuration[:ingredient_column]}=, :ingredient_association= RUBY - - @_classes_with_ingredient_association << self - end - end - - # Overwrite ActiveRecords method to return a bogus association class that skips eager loading - # for essence classes that do not have an ingredient association - def _reflect_on_association(name) - if name == :ingredient_association && !in?(@_classes_with_ingredient_association) - OpenStruct.new(association_class: Alchemy::IngredientAssociation) - else - super end end diff --git a/lib/alchemy/test_support/essence_shared_examples.rb b/lib/alchemy/test_support/essence_shared_examples.rb index bd630f8f98..a89907151e 100644 --- a/lib/alchemy/test_support/essence_shared_examples.rb +++ b/lib/alchemy/test_support/essence_shared_examples.rb @@ -7,18 +7,6 @@ let(:content) { Alchemy::Content.new(name: "foo") } let(:content_definition) { { "name" => "foo" } } - describe "eager loading" do - before do - 2.times { described_class.create! } - end - - it "does not throw error if eager loaded" do - expect { - described_class.all.includes(:ingredient_association).to_a - }.to_not raise_error - end - end - it "touches the element after save" do element = FactoryBot.create(:alchemy_element) content = FactoryBot.create(:alchemy_content, element: element, essence: essence, essence_type: essence.class.name) diff --git a/lib/alchemy/upgrader/tasks/ingredients_migrator.rb b/lib/alchemy/upgrader/tasks/ingredients_migrator.rb index ab977ff569..6ee992c540 100644 --- a/lib/alchemy/upgrader/tasks/ingredients_migrator.rb +++ b/lib/alchemy/upgrader/tasks/ingredients_migrator.rb @@ -16,7 +16,7 @@ def create_ingredients # eager load all elements that have ingredients defined but no ingredient records yet. all_elements = Alchemy::Element .named(elements_with_ingredients.map { |d| d[:name] }) - .includes(contents: { essence: :ingredient_association }) + .includes(contents: :essence) .left_outer_joins(:ingredients).where(alchemy_ingredients: { id: nil }) .to_a elements_with_ingredients.map do |element_definition| diff --git a/spec/dummy/bin/rails b/spec/dummy/bin/rails index cbfe38b1c3..efc0377492 100755 --- a/spec/dummy/bin/rails +++ b/spec/dummy/bin/rails @@ -1,5 +1,4 @@ #!/usr/bin/env ruby -# frozen_string_literal: true APP_PATH = File.expand_path("../config/application", __dir__) require_relative "../config/boot" require "rails/commands" diff --git a/spec/dummy/bin/rake b/spec/dummy/bin/rake index d648cf02d5..4fbf10b960 100755 --- a/spec/dummy/bin/rake +++ b/spec/dummy/bin/rake @@ -1,5 +1,4 @@ #!/usr/bin/env ruby -# frozen_string_literal: true require_relative "../config/boot" require "rake" Rake.application.run diff --git a/spec/dummy/bin/setup b/spec/dummy/bin/setup index a3bdce2222..ec47b79b3b 100755 --- a/spec/dummy/bin/setup +++ b/spec/dummy/bin/setup @@ -1,5 +1,4 @@ #!/usr/bin/env ruby -# frozen_string_literal: true require "fileutils" # path to your application root. @@ -10,20 +9,17 @@ def system!(*args) end FileUtils.chdir APP_ROOT do - # This script is a way to setup or update your development environment automatically. - # This script is idempotent, so that you can run it at anytime and get an expectable outcome. + # This script is a way to set up or update your development environment automatically. + # This script is idempotent, so that you can run it at any time and get an expectable outcome. # Add necessary setup steps to this file. 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== Copying sample files ==" - # unless File.exist?('config/database.yml') - # FileUtils.cp 'config/database.yml.sample', 'config/database.yml' + # unless File.exist?("config/database.yml") + # FileUtils.cp "config/database.yml.sample", "config/database.yml" # end puts "\n== Preparing database ==" diff --git a/spec/dummy/config/application.rb b/spec/dummy/config/application.rb index ea4fb07d1e..0e1bb36d4d 100644 --- a/spec/dummy/config/application.rb +++ b/spec/dummy/config/application.rb @@ -23,7 +23,7 @@ module Dummy class Application < Rails::Application # Initialize configuration defaults for originally generated Rails version. if config.respond_to?(:load_defaults) - config.load_defaults ENV["RAILS_VERSION"] || 6.1 + config.load_defaults ENV["RAILS_VERSION"] || 7.0 end # Settings in config/environments/* take precedence over those specified here. diff --git a/spec/dummy/config/environments/development.rb b/spec/dummy/config/environments/development.rb index d334e53532..a4dd7c2858 100644 --- a/spec/dummy/config/environments/development.rb +++ b/spec/dummy/config/environments/development.rb @@ -14,15 +14,18 @@ # Show full error reports. config.consider_all_requests_local = true + # Enable server timing + config.server_timing = true + # Enable/disable caching. By default caching is disabled. # Run rails dev:cache to toggle caching. - if Rails.root.join("tmp", "caching-dev.txt").exist? + if Rails.root.join("tmp/caching-dev.txt").exist? config.action_controller.perform_caching = true config.action_controller.enable_fragment_cache_logging = true config.cache_store = :memory_store config.public_file_server.headers = { - "Cache-Control" => "public, max-age=#{2.days.to_i}", + "Cache-Control" => "public, max-age=#{2.days.to_i}" } else config.action_controller.perform_caching = false diff --git a/spec/dummy/config/environments/production.rb b/spec/dummy/config/environments/production.rb index 6671da2b33..63991a8eb9 100644 --- a/spec/dummy/config/environments/production.rb +++ b/spec/dummy/config/environments/production.rb @@ -13,7 +13,7 @@ config.eager_load = true # Full error reports are disabled and caching is turned on. - config.consider_all_requests_local = false + config.consider_all_requests_local = false config.action_controller.perform_caching = true # Ensures that a master key has been made available in either ENV["RAILS_MASTER_KEY"] @@ -31,11 +31,11 @@ config.assets.compile = false # Enable serving of images, stylesheets, and JavaScripts from an asset server. - # config.asset_host = 'http://assets.example.com' + # config.asset_host = "http://assets.example.com" # Specifies the header that your server uses for sending files. - # config.action_dispatch.x_sendfile_header = 'X-Sendfile' # for Apache - # config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for NGINX + # config.action_dispatch.x_sendfile_header = "X-Sendfile" # for Apache + # config.action_dispatch.x_sendfile_header = "X-Accel-Redirect" # for NGINX # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies. # config.force_ssl = true @@ -45,7 +45,7 @@ config.log_level = :info # Prepend all log lines with the following tags. - config.log_tags = [:request_id] + config.log_tags = [ :request_id ] # Use a different cache store in production. # config.cache_store = :mem_cache_store @@ -64,49 +64,22 @@ # the I18n.default_locale when a translation cannot be found). config.i18n.fallbacks = true - # Send deprecation notices to registered listeners. - config.active_support.deprecation = :notify - - # Log disallowed deprecations. - config.active_support.disallowed_deprecation = :log - - # Tell Active Support which deprecation messages to disallow. - config.active_support.disallowed_deprecation_warnings = [] + # Don't log any deprecations. + config.active_support.report_deprecations = false # Use default logging formatter so that PID and timestamp are not suppressed. config.log_formatter = ::Logger::Formatter.new # Use a different logger for distributed setups. # require "syslog/logger" - # config.logger = ActiveSupport::TaggedLogging.new(Syslog::Logger.new 'app-name') + # config.logger = ActiveSupport::TaggedLogging.new(Syslog::Logger.new "app-name") if ENV["RAILS_LOG_TO_STDOUT"].present? - logger = ActiveSupport::Logger.new(STDOUT) + logger = ActiveSupport::Logger.new(STDOUT) logger.formatter = config.log_formatter - config.logger = ActiveSupport::TaggedLogging.new(logger) + config.logger = ActiveSupport::TaggedLogging.new(logger) end # Do not dump schema after migrations. config.active_record.dump_schema_after_migration = false - - # Inserts middleware to perform automatic connection switching. - # The `database_selector` hash is used to pass options to the DatabaseSelector - # middleware. The `delay` is used to determine how long to wait after a write - # to send a subsequent read to the primary. - # - # The `database_resolver` class is used by the middleware to determine which - # database is appropriate to use based on the time delay. - # - # The `database_resolver_context` class is used by the middleware to set - # timestamps for the last write to the primary. The resolver uses the context - # class timestamps to determine how long to wait before reading from the - # replica. - # - # By default Rails will store a last write timestamp in the session. The - # DatabaseSelector middleware is designed as such you can define your own - # strategy for connection switching and pass that into the middleware through - # these configuration options. - # config.active_record.database_selector = { delay: 2.seconds } - # config.active_record.database_resolver = ActiveRecord::Middleware::DatabaseSelector::Resolver - # config.active_record.database_resolver_context = ActiveRecord::Middleware::DatabaseSelector::Resolver::Session end diff --git a/spec/dummy/config/environments/test.rb b/spec/dummy/config/environments/test.rb index 3d0843d515..eb23db32e9 100644 --- a/spec/dummy/config/environments/test.rb +++ b/spec/dummy/config/environments/test.rb @@ -8,21 +8,22 @@ Rails.application.configure do # Settings specified here will take precedence over those in config/application.rb. + # Turn false under Spring and add config.action_view.cache_template_loading = true. config.cache_classes = true - # Do not eager load code on boot. This avoids loading your whole application - # just for the purpose of running a single test. If you are using a tool that - # preloads Rails for running tests, you may have to set it to true. - config.eager_load = false + # Eager loading loads your whole application. When running a single test locally, + # this probably isn't necessary. It's a good idea to do in a continuous integration + # system, or in some way before deploying your code. + config.eager_load = ENV["CI"].present? # Configure public 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=#{1.hour.to_i}", + "Cache-Control" => "public, max-age=#{1.hour.to_i}" } # Show full error reports and disable caching. - config.consider_all_requests_local = true + config.consider_all_requests_local = true config.action_controller.perform_caching = false config.cache_store = :null_store diff --git a/spec/dummy/config/initializers/alchemy.rb b/spec/dummy/config/initializers/alchemy.rb index a01c49a86d..68c531b144 100644 --- a/spec/dummy/config/initializers/alchemy.rb +++ b/spec/dummy/config/initializers/alchemy.rb @@ -1,31 +1,33 @@ # frozen_string_literal: true -Alchemy.register_ability Ability -Alchemy.user_class_name = 'DummyUser' -Alchemy.signup_path = '/admin/pages' unless Rails.env.test? -Alchemy::Modules.register_module( - name: 'events', - navigation: { - name: 'Events', - controller: '/admin/events', - action: 'index', - icon: 'calendar-alt', - sub_navigation: [{ - name: 'Events', - controller: '/admin/events', - action: 'index' - }, { - name: 'Locations', - controller: '/admin/locations', - action: 'index' - }, { - name: 'Series', - controller: '/admin/series', - action: 'index' - }, { - name: 'Bookings', - controller: '/admin/bookings', - action: 'index' - }] - } -) +Rails.application.config.to_prepare do + Alchemy.register_ability Ability + Alchemy.user_class_name = "DummyUser" + Alchemy.signup_path = "/admin/pages" unless Rails.env.test? + Alchemy::Modules.register_module( + name: "events", + navigation: { + name: "Events", + controller: "/admin/events", + action: "index", + icon: "calendar-alt", + sub_navigation: [{ + name: "Events", + controller: "/admin/events", + action: "index", + }, { + name: "Locations", + controller: "/admin/locations", + action: "index", + }, { + name: "Series", + controller: "/admin/series", + action: "index", + }, { + name: "Bookings", + controller: "/admin/bookings", + action: "index", + }], + }, + ) +end diff --git a/spec/dummy/config/initializers/content_security_policy.rb b/spec/dummy/config/initializers/content_security_policy.rb index 41c43016f1..3621f97f8e 100644 --- a/spec/dummy/config/initializers/content_security_policy.rb +++ b/spec/dummy/config/initializers/content_security_policy.rb @@ -4,25 +4,23 @@ # 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" +# Rails.application.configure do +# 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 +# +# # Generate session nonces for permitted importmap and inline scripts +# config.content_security_policy_nonce_generator = ->(request) { request.session.id.to_s } +# config.content_security_policy_nonce_directives = %w(script-src) +# +# # Report CSP violations to a specified URI. See: +# # https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy-Report-Only +# # config.content_security_policy_report_only = true # end - -# If you are using UJS then enable automatic nonce generation -# Rails.application.config.content_security_policy_nonce_generator = -> request { SecureRandom.base64(16) } - -# Set the nonce only to specific directives -# Rails.application.config.content_security_policy_nonce_directives = %w(script-src) - -# 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/spec/dummy/config/initializers/filter_parameter_logging.rb b/spec/dummy/config/initializers/filter_parameter_logging.rb index 5118eb69cc..adc6568ce8 100644 --- a/spec/dummy/config/initializers/filter_parameter_logging.rb +++ b/spec/dummy/config/initializers/filter_parameter_logging.rb @@ -1,8 +1,8 @@ -# frozen_string_literal: true - # Be sure to restart your server when you modify this file. -# Configure sensitive parameters which will be filtered from the log file. +# Configure parameters to be filtered from the log file. Use this to limit dissemination of +# sensitive information. See the ActiveSupport::ParameterFilter documentation for supported +# notations and behaviors. Rails.application.config.filter_parameters += [ :passw, :secret, :token, :_key, :crypt, :salt, :certificate, :otp, :ssn ] diff --git a/spec/dummy/config/initializers/inflections.rb b/spec/dummy/config/initializers/inflections.rb index dc84742212..3860f659ea 100644 --- a/spec/dummy/config/initializers/inflections.rb +++ b/spec/dummy/config/initializers/inflections.rb @@ -1,18 +1,16 @@ -# frozen_string_literal: true - # Be sure to restart your server when you modify this file. # Add new inflection rules using the following format. Inflections # are locale specific, and you may define rules for as many different # locales as you wish. All of these examples are active by default: # ActiveSupport::Inflector.inflections(:en) do |inflect| -# inflect.plural /^(ox)$/i, '\1en' -# inflect.singular /^(ox)en/i, '\1' -# inflect.irregular 'person', 'people' +# inflect.plural /^(ox)$/i, "\\1en" +# inflect.singular /^(ox)en/i, "\\1" +# inflect.irregular "person", "people" # inflect.uncountable %w( fish sheep ) # end # These inflection rules are supported but not enabled by default: # ActiveSupport::Inflector.inflections(:en) do |inflect| -# inflect.acronym 'RESTful' +# inflect.acronym "RESTful" # end diff --git a/spec/dummy/db/schema.rb b/spec/dummy/db/schema.rb index e35b6f889a..10e94895a9 100644 --- a/spec/dummy/db/schema.rb +++ b/spec/dummy/db/schema.rb @@ -10,17 +10,16 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 2021_11_05_175532) do - +ActiveRecord::Schema[7.0].define(version: 2021_11_05_175532) do create_table "alchemy_attachments", force: :cascade do |t| t.string "name" t.string "file_name" t.string "file_mime_type" t.integer "file_size" - t.bigint "creator_id" - t.bigint "updater_id" - t.datetime "created_at", precision: 6, null: false - t.datetime "updated_at", precision: 6, null: false + t.integer "creator_id" + t.integer "updater_id" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false t.string "file_uid" t.index ["creator_id"], name: "index_alchemy_attachments_on_creator_id" t.index ["file_uid"], name: "index_alchemy_attachments_on_file_uid" @@ -42,8 +41,8 @@ t.boolean "public", default: true, null: false t.boolean "folded", default: false, null: false t.boolean "unique", default: false, null: false - t.datetime "created_at", precision: 6, null: false - t.datetime "updated_at", precision: 6, null: false + t.datetime "created_at", null: false + t.datetime "updated_at", null: false t.integer "creator_id" t.integer "updater_id" t.integer "parent_element_id" @@ -57,14 +56,14 @@ end create_table "alchemy_elements_alchemy_pages", id: false, force: :cascade do |t| - t.bigint "element_id" - t.bigint "page_id" + t.integer "element_id" + t.integer "page_id" t.index ["element_id"], name: "index_alchemy_elements_alchemy_pages_on_element_id" t.index ["page_id"], name: "index_alchemy_elements_alchemy_pages_on_page_id" end create_table "alchemy_essence_audios", force: :cascade do |t| - t.bigint "attachment_id" + t.integer "attachment_id" t.boolean "controls", default: true, null: false t.boolean "autoplay", default: false t.boolean "loop", default: false, null: false @@ -78,11 +77,11 @@ end create_table "alchemy_essence_dates", force: :cascade do |t| - t.datetime "date" + t.datetime "date", precision: nil end create_table "alchemy_essence_files", force: :cascade do |t| - t.bigint "attachment_id" + t.integer "attachment_id" t.string "title" t.string "css_class" t.string "link_text" @@ -93,8 +92,8 @@ t.text "body" t.integer "level" t.integer "size" - t.datetime "created_at", precision: 6, null: false - t.datetime "updated_at", precision: 6, null: false + t.datetime "created_at", null: false + t.datetime "updated_at", null: false end create_table "alchemy_essence_htmls", force: :cascade do |t| @@ -110,8 +109,8 @@ create_table "alchemy_essence_nodes", force: :cascade do |t| t.integer "node_id" - t.datetime "created_at", precision: 6, null: false - t.datetime "updated_at", precision: 6, null: false + t.datetime "created_at", null: false + t.datetime "updated_at", null: false t.index ["node_id"], name: "index_alchemy_essence_nodes_on_node_id" end @@ -121,7 +120,7 @@ end create_table "alchemy_essence_pictures", force: :cascade do |t| - t.bigint "picture_id" + t.integer "picture_id" t.string "caption" t.string "title" t.string "alt_tag" @@ -158,7 +157,7 @@ end create_table "alchemy_essence_videos", force: :cascade do |t| - t.bigint "attachment_id" + t.integer "attachment_id" t.string "width" t.string "height" t.boolean "allow_fullscreen", default: true, null: false @@ -178,15 +177,15 @@ end create_table "alchemy_ingredients", force: :cascade do |t| - t.bigint "element_id", null: false + t.integer "element_id", null: false t.string "type", null: false t.string "role", null: false t.text "value" t.json "data" t.string "related_object_type" - t.bigint "related_object_id" - t.datetime "created_at", precision: 6, null: false - t.datetime "updated_at", precision: 6, null: false + t.integer "related_object_id" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false t.index ["element_id", "role"], name: "index_alchemy_ingredients_on_element_id_and_role", unique: true t.index ["element_id"], name: "index_alchemy_ingredients_on_element_id" t.index ["related_object_id", "related_object_type"], name: "idx_alchemy_ingredient_relation" @@ -199,8 +198,8 @@ t.string "frontpage_name" t.string "page_layout", default: "intro" t.boolean "public", default: false, null: false - t.datetime "created_at", precision: 6, null: false - t.datetime "updated_at", precision: 6, null: false + t.datetime "created_at", null: false + t.datetime "updated_at", null: false t.integer "creator_id" t.integer "updater_id" t.boolean "default", default: false, null: false @@ -216,9 +215,9 @@ create_table "alchemy_legacy_page_urls", force: :cascade do |t| t.string "urlname", null: false - t.bigint "page_id", null: false - t.datetime "created_at", precision: 6, null: false - t.datetime "updated_at", precision: 6, null: false + t.integer "page_id", null: false + t.datetime "created_at", null: false + t.datetime "updated_at", null: false t.index ["page_id"], name: "index_alchemy_legacy_page_urls_on_page_id" t.index ["urlname"], name: "index_alchemy_legacy_page_urls_on_urlname" end @@ -238,8 +237,8 @@ t.integer "language_id", null: false t.integer "creator_id" t.integer "updater_id" - t.datetime "created_at", precision: 6, null: false - t.datetime "updated_at", precision: 6, null: false + t.datetime "created_at", null: false + t.datetime "updated_at", null: false t.string "menu_type", null: false t.index ["creator_id"], name: "index_alchemy_nodes_on_creator_id" t.index ["language_id"], name: "index_alchemy_nodes_on_language_id" @@ -251,11 +250,11 @@ end create_table "alchemy_page_versions", force: :cascade do |t| - t.bigint "page_id", null: false - t.datetime "public_on" - t.datetime "public_until" - t.datetime "created_at", precision: 6, null: false - t.datetime "updated_at", precision: 6, null: false + t.integer "page_id", null: false + t.datetime "public_on", precision: nil + t.datetime "public_until", precision: nil + t.datetime "created_at", null: false + t.datetime "updated_at", null: false t.index ["page_id"], name: "index_alchemy_page_versions_on_page_id" t.index ["public_on", "public_until"], name: "index_alchemy_page_versions_on_public_on_and_public_until" end @@ -279,15 +278,15 @@ t.boolean "robot_follow", default: true, null: false t.boolean "sitemap", default: true, null: false t.boolean "layoutpage", default: false, null: false - t.datetime "created_at", precision: 6, null: false - t.datetime "updated_at", precision: 6, null: false + t.datetime "created_at", null: false + t.datetime "updated_at", null: false t.integer "creator_id" t.integer "updater_id" t.integer "language_id", null: false - t.datetime "published_at" - t.datetime "legacy_public_on" - t.datetime "legacy_public_until" - t.datetime "locked_at" + t.datetime "published_at", precision: nil + t.datetime "legacy_public_on", precision: nil + t.datetime "legacy_public_until", precision: nil + t.datetime "locked_at", precision: nil t.index ["creator_id"], name: "index_alchemy_pages_on_creator_id" t.index ["language_id"], name: "index_alchemy_pages_on_language_id" t.index ["locked_at", "locked_by"], name: "index_alchemy_pages_on_locked_at_and_locked_by" @@ -298,7 +297,7 @@ end create_table "alchemy_picture_thumbs", force: :cascade do |t| - t.bigint "picture_id", null: false + t.integer "picture_id", null: false t.string "signature", null: false t.text "uid", null: false t.index ["picture_id"], name: "index_alchemy_picture_thumbs_on_picture_id" @@ -310,10 +309,10 @@ t.string "image_file_name" t.integer "image_file_width" t.integer "image_file_height" - t.datetime "created_at", precision: 6, null: false - t.datetime "updated_at", precision: 6, null: false - t.bigint "creator_id" - t.bigint "updater_id" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.integer "creator_id" + t.integer "updater_id" t.string "upload_hash" t.string "image_file_uid" t.integer "image_file_size" @@ -325,8 +324,8 @@ create_table "alchemy_sites", force: :cascade do |t| t.string "host" t.string "name" - t.datetime "created_at", precision: 6, null: false - t.datetime "updated_at", precision: 6, null: false + t.datetime "created_at", null: false + t.datetime "updated_at", null: false t.boolean "public", default: false, null: false t.text "aliases" t.boolean "redirect_to_primary_host", default: false, null: false @@ -337,8 +336,8 @@ create_table "bookings", force: :cascade do |t| t.date "from" t.date "until" - t.datetime "created_at", null: false - t.datetime "updated_at", null: false + t.datetime "created_at", precision: nil, null: false + t.datetime "updated_at", precision: nil, null: false end create_table "dummy_models", force: :cascade do |t| @@ -354,16 +353,16 @@ create_table "events", force: :cascade do |t| t.string "name" t.string "hidden_name" - t.datetime "starts_at" - t.datetime "ends_at" + t.datetime "starts_at", precision: nil + t.datetime "ends_at", precision: nil t.time "lunch_starts_at" t.time "lunch_ends_at" t.text "description" t.decimal "entrance_fee", precision: 6, scale: 2 t.boolean "published" t.integer "location_id" - t.datetime "created_at", null: false - t.datetime "updated_at", null: false + t.datetime "created_at", precision: nil, null: false + t.datetime "updated_at", precision: nil, null: false t.integer "event_type", default: 0, null: false end @@ -371,8 +370,8 @@ t.integer "tag_id", null: false t.integer "taggable_id", null: false t.string "taggable_type", null: false - t.datetime "created_at", null: false - t.datetime "updated_at", null: false + t.datetime "created_at", precision: nil, null: false + t.datetime "updated_at", precision: nil, null: false t.index ["tag_id"], name: "index_gutentag_taggings_on_tag_id" t.index ["taggable_type", "taggable_id", "tag_id"], name: "unique_taggings", unique: true t.index ["taggable_type", "taggable_id"], name: "index_gutentag_taggings_on_taggable_type_and_taggable_id" @@ -380,8 +379,8 @@ create_table "gutentag_tags", force: :cascade do |t| t.string "name", null: false - t.datetime "created_at", null: false - t.datetime "updated_at", null: false + t.datetime "created_at", precision: nil, null: false + t.datetime "updated_at", precision: nil, null: false t.integer "taggings_count", default: 0, null: false t.index ["name"], name: "index_gutentag_tags_on_name", unique: true t.index ["taggings_count"], name: "index_gutentag_tags_on_taggings_count" @@ -389,8 +388,8 @@ create_table "locations", force: :cascade do |t| t.string "name" - t.datetime "created_at" - t.datetime "updated_at" + t.datetime "created_at", precision: nil + t.datetime "updated_at", precision: nil end create_table "series", force: :cascade do |t| diff --git a/spec/models/alchemy/message_spec.rb b/spec/models/alchemy/message_spec.rb index 078289ea46..31891712d4 100644 --- a/spec/models/alchemy/message_spec.rb +++ b/spec/models/alchemy/message_spec.rb @@ -2,54 +2,59 @@ require "rails_helper" -module Alchemy - Config.get(:mailer)["fields"].push("email_of_my_boss") - Config.get(:mailer)["validate_fields"].push("email_of_my_boss") +RSpec.describe "Alchemy::Message" do + let(:message) { Alchemy::Message.new } - describe Message do - let(:message) { Message.new } + describe ".config" do + it "should return the mailer config" do + expect(Alchemy::Message.config).to eq(Alchemy::Config.get(:mailer)) + end + end - describe ".config" do - it "should return the mailer config" do - expect(Config).to receive(:get).with(:mailer) - Message.config - end + it "has attributes writers and getters for all fields defined in mailer config" do + Alchemy::Config.get(:mailer)["fields"].each do |field| + expect(message).to respond_to(field) + expect(message).to respond_to("#{field}=") end + end - it "has attributes writers and getters for all fields defined in mailer config" do - Config.get(:mailer)["fields"].each do |field| - expect(message).to respond_to(field) - expect(message).to respond_to("#{field}=") + context "validation of" do + context "all fields defined in mailer config" do + it "adds errors on that fields" do + Alchemy::Config.get(:mailer)["validate_fields"].each do |field| + expect(message).to_not be_valid + expect(message.errors[field].size).to eq(1) + end end end - context "validation of" do - context "all fields defined in mailer config" do - it "adds errors on that fields" do - Config.get(:mailer)["validate_fields"].each do |field| - expect(message).to_not be_valid - expect(message.errors[field].size).to eq(1) - end - end + context "field containing email in its name" do + before do + stub_alchemy_config(:mailer, { + fields: %w[email_of_my_boss], + validate_fields: %w[email_of_my_boss], + }.with_indifferent_access) + Alchemy.send(:remove_const, :Message) + load Alchemy::Engine.root.join("app/models/alchemy/message.rb") end - context "field containing email in its name" do - context "when field has a value" do - before { message.email_of_my_boss = "wrong email format" } + context "when field has a value" do + let(:invalid_message) { Alchemy::Message.new } - it "adds error notice (is invalid) to the field" do - expect(message).to_not be_valid - expect(message.errors[:email_of_my_boss]).to include("is invalid") - end + before { invalid_message.email_of_my_boss = "wrong email format" } + + it "adds error notice (is invalid) to the field" do + expect(invalid_message).to_not be_valid + expect(invalid_message.errors[:email_of_my_boss]).to include("is invalid") end + end - context "when field is blank" do - before { message.email_of_my_boss = "" } + context "when field is blank" do + before { message.email_of_my_boss = "" } - it "adds error notice (can't be blank) to the field" do - expect(message).to_not be_valid - expect(message.errors[:email_of_my_boss]).to include("can't be blank") - end + it "adds error notice (can't be blank) to the field" do + expect(message).to_not be_valid + expect(message.errors[:email_of_my_boss]).to include("can't be blank") end end end