From d713c0237def812e6d9111e6daa43ca955898e9a Mon Sep 17 00:00:00 2001 From: Thomas von Deyen Date: Wed, 30 Jun 2021 17:04:42 +0200 Subject: [PATCH 01/16] Add IngredientText serializer --- .../json_api/ingredient_text_serializer.rb | 22 ++++++++++ lib/alchemy/json_api/ingredient_serializer.rb | 22 ++++++++++ .../ingredient_serializer_behaviour.rb | 33 +++++++++++++++ spec/rails_helper.rb | 3 ++ .../ingredient_text_serializer_spec.rb | 41 +++++++++++++++++++ spec/spec_helper.rb | 2 - 6 files changed, 121 insertions(+), 2 deletions(-) create mode 100644 app/serializers/alchemy/json_api/ingredient_text_serializer.rb create mode 100644 lib/alchemy/json_api/ingredient_serializer.rb create mode 100644 lib/alchemy/json_api/test_support/ingredient_serializer_behaviour.rb create mode 100644 spec/serializers/alchemy/json_api/ingredient_text_serializer_spec.rb diff --git a/app/serializers/alchemy/json_api/ingredient_text_serializer.rb b/app/serializers/alchemy/json_api/ingredient_text_serializer.rb new file mode 100644 index 0000000..ec1b18a --- /dev/null +++ b/app/serializers/alchemy/json_api/ingredient_text_serializer.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true + +require "alchemy/json_api/ingredient_serializer" + +module Alchemy + module JsonApi + class IngredientTextSerializer + include IngredientSerializer + + attributes( + :link, + :link_class_name, + :link_target, + :link_title, + ) + + # maintain compatibility with EssenceText + attribute :body, &:value + attribute :link_url, &:link + end + end +end diff --git a/lib/alchemy/json_api/ingredient_serializer.rb b/lib/alchemy/json_api/ingredient_serializer.rb new file mode 100644 index 0000000..2cfa60c --- /dev/null +++ b/lib/alchemy/json_api/ingredient_serializer.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true + +module Alchemy + module JsonApi + module IngredientSerializer + def self.included(klass) + klass.include JSONAPI::Serializer + + klass.has_one :element, record_type: :element, serializer: ::Alchemy::JsonApi::ElementSerializer + + klass.attributes( + :role, + :value, + :created_at, + :updated_at + ) + + klass.attribute :deprecated, &:deprecated? + end + end + end +end diff --git a/lib/alchemy/json_api/test_support/ingredient_serializer_behaviour.rb b/lib/alchemy/json_api/test_support/ingredient_serializer_behaviour.rb new file mode 100644 index 0000000..b29901e --- /dev/null +++ b/lib/alchemy/json_api/test_support/ingredient_serializer_behaviour.rb @@ -0,0 +1,33 @@ +# frozen_string_literal: true + +RSpec.shared_examples "an ingredient serializer" do + describe "attributes" do + subject { serializer.serializable_hash[:data][:attributes] } + + it "has the right keys and values" do + expect(subject).to have_key(:role) + expect(subject).to have_key(:value) + expect(subject).to have_key(:created_at) + expect(subject).to have_key(:updated_at) + expect(subject[:deprecated]).to be(false) + end + + context "a deprecated ingredient" do + before do + expect(ingredient).to receive(:deprecated?) { true } + end + + it "has deprecated attribute set to true" do + expect(subject[:deprecated]).to eq(true) + end + end + end + + describe "relationships" do + subject { serializer.serializable_hash[:data][:relationships] } + + it "has one element" do + expect(subject[:element]).to eq(data: { id: ingredient.element_id.to_s, type: :element }) + end + end +end diff --git a/spec/rails_helper.rb b/spec/rails_helper.rb index 312ec5e..d3b20a8 100644 --- a/spec/rails_helper.rb +++ b/spec/rails_helper.rb @@ -11,6 +11,9 @@ require "jsonapi/rspec" require "shoulda-matchers" +require "alchemy/json_api/test_support/essence_serializer_behaviour" +require "alchemy/json_api/test_support/ingredient_serializer_behaviour" + Shoulda::Matchers.configure do |config| config.integrate do |with| with.test_framework :rspec diff --git a/spec/serializers/alchemy/json_api/ingredient_text_serializer_spec.rb b/spec/serializers/alchemy/json_api/ingredient_text_serializer_spec.rb new file mode 100644 index 0000000..b69d786 --- /dev/null +++ b/spec/serializers/alchemy/json_api/ingredient_text_serializer_spec.rb @@ -0,0 +1,41 @@ +# frozen_string_literal: true +require "rails_helper" + +RSpec.describe Alchemy::JsonApi::IngredientTextSerializer do + let(:ingredient) do + FactoryBot.create(:alchemy_ingredient_text, value: "Welcome") + end + + subject(:serializer) { described_class.new(ingredient) } + + it_behaves_like "an ingredient serializer" + + describe "attributes" do + subject { serializer.serializable_hash[:data][:attributes] } + + it "has the right keys and values" do + expect(subject[:body]).to eq("Welcome") + expect(subject[:link]).to be_nil + expect(subject[:link_class_name]).to be_nil + expect(subject[:link_target]).to be_nil + expect(subject[:link_title]).to be_nil + end + + context "with link" do + before do + ingredient.link = "https://alchemy-cms.com" + ingredient.link_class_name = "external" + ingredient.link_target = "_blank" + ingredient.link_title = "Great CMS" + end + + it "has the right keys and values" do + expect(subject[:link]).to eq "https://alchemy-cms.com" + expect(subject[:link_class_name]).to eq "external" + expect(subject[:link_target]).to eq "_blank" + expect(subject[:link_title]).to eq "Great CMS" + expect(subject[:link_url]).to eq "https://alchemy-cms.com" + end + end + end +end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index af601fd..5ec9648 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -15,8 +15,6 @@ # # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration -require "alchemy/json_api/test_support/essence_serializer_behaviour" - RSpec.configure do |config| # rspec-expectations config goes here. You can use an alternate # assertion/expectation library such as wrong or the stdlib/minitest From b1b8ec56fa5824b570db855f11fec298ed50b83b Mon Sep 17 00:00:00 2001 From: Thomas von Deyen Date: Wed, 30 Jun 2021 17:04:47 +0200 Subject: [PATCH 02/16] Add Ingredient Boolean serializer --- .../json_api/ingredient_boolean_serializer.rb | 11 +++++++++++ .../ingredient_boolean_serializer_spec.rb | 19 +++++++++++++++++++ 2 files changed, 30 insertions(+) create mode 100644 app/serializers/alchemy/json_api/ingredient_boolean_serializer.rb create mode 100644 spec/serializers/alchemy/json_api/ingredient_boolean_serializer_spec.rb diff --git a/app/serializers/alchemy/json_api/ingredient_boolean_serializer.rb b/app/serializers/alchemy/json_api/ingredient_boolean_serializer.rb new file mode 100644 index 0000000..dd529e4 --- /dev/null +++ b/app/serializers/alchemy/json_api/ingredient_boolean_serializer.rb @@ -0,0 +1,11 @@ +# frozen_string_literal: true + +require "alchemy/json_api/ingredient_serializer" + +module Alchemy + module JsonApi + class IngredientBooleanSerializer + include IngredientSerializer + end + end +end diff --git a/spec/serializers/alchemy/json_api/ingredient_boolean_serializer_spec.rb b/spec/serializers/alchemy/json_api/ingredient_boolean_serializer_spec.rb new file mode 100644 index 0000000..0f04086 --- /dev/null +++ b/spec/serializers/alchemy/json_api/ingredient_boolean_serializer_spec.rb @@ -0,0 +1,19 @@ +# frozen_string_literal: true + +require "rails_helper" + +RSpec.describe Alchemy::JsonApi::IngredientBooleanSerializer do + let(:ingredient) { FactoryBot.build_stubbed(:alchemy_ingredient_boolean, value: true) } + + subject(:serializer) { described_class.new(ingredient) } + + it_behaves_like "an ingredient serializer" + + describe "attributes" do + subject { serializer.serializable_hash[:data][:attributes] } + + it "has the right keys and values" do + expect(subject[:value]).to be(true) + end + end +end From f0cd09fd3bfd23a77ee4994bea9be93099f31ef2 Mon Sep 17 00:00:00 2001 From: Thomas von Deyen Date: Wed, 30 Jun 2021 17:04:51 +0200 Subject: [PATCH 03/16] Add Ingredient Datetime serializer --- .../ingredient_datetime_serializer.rb | 11 ++++++++++ .../ingredient_datetime_serializer_spec.rb | 20 +++++++++++++++++++ 2 files changed, 31 insertions(+) create mode 100644 app/serializers/alchemy/json_api/ingredient_datetime_serializer.rb create mode 100644 spec/serializers/alchemy/json_api/ingredient_datetime_serializer_spec.rb diff --git a/app/serializers/alchemy/json_api/ingredient_datetime_serializer.rb b/app/serializers/alchemy/json_api/ingredient_datetime_serializer.rb new file mode 100644 index 0000000..12eaa99 --- /dev/null +++ b/app/serializers/alchemy/json_api/ingredient_datetime_serializer.rb @@ -0,0 +1,11 @@ +# frozen_string_literal: true + +require "alchemy/json_api/ingredient_serializer" + +module Alchemy + module JsonApi + class IngredientDatetimeSerializer + include IngredientSerializer + end + end +end diff --git a/spec/serializers/alchemy/json_api/ingredient_datetime_serializer_spec.rb b/spec/serializers/alchemy/json_api/ingredient_datetime_serializer_spec.rb new file mode 100644 index 0000000..bad70ec --- /dev/null +++ b/spec/serializers/alchemy/json_api/ingredient_datetime_serializer_spec.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true + +require "rails_helper" + +RSpec.describe Alchemy::JsonApi::IngredientDatetimeSerializer do + let(:today) { Date.today } + let(:ingredient) { FactoryBot.build_stubbed(:alchemy_ingredient_datetime, value: today) } + + subject(:serializer) { described_class.new(ingredient) } + + it_behaves_like "an ingredient serializer" + + describe "attributes" do + subject { serializer.serializable_hash[:data][:attributes] } + + it "has the right keys and values" do + expect(subject[:value]).to eq(today) + end + end +end From 757e2e17bc208b6c9d888e1d2280280a255973ee Mon Sep 17 00:00:00 2001 From: Thomas von Deyen Date: Wed, 30 Jun 2021 17:04:54 +0200 Subject: [PATCH 04/16] Add Ingredient File serializer --- .../json_api/ingredient_file_serializer.rb | 35 +++++++++++++++ .../ingredient_file_serializer_spec.rb | 43 +++++++++++++++++++ 2 files changed, 78 insertions(+) create mode 100644 app/serializers/alchemy/json_api/ingredient_file_serializer.rb create mode 100644 spec/serializers/alchemy/json_api/ingredient_file_serializer_spec.rb diff --git a/app/serializers/alchemy/json_api/ingredient_file_serializer.rb b/app/serializers/alchemy/json_api/ingredient_file_serializer.rb new file mode 100644 index 0000000..a8a6faa --- /dev/null +++ b/app/serializers/alchemy/json_api/ingredient_file_serializer.rb @@ -0,0 +1,35 @@ +# frozen_string_literal: true + +require "alchemy/json_api/ingredient_serializer" + +module Alchemy + module JsonApi + class IngredientFileSerializer + include IngredientSerializer + + attribute :link_title, &:title + + attribute :value do |ingredient| + ingredient.attachment&.url + end + + with_options if: proc { |ingredient| ingredient.attachment } do + attribute :attachment_name do |ingredient| + ingredient.attachment.name + end + + attribute :attachment_file_name do |ingredient| + ingredient.attachment.file_name + end + + attribute :attachment_mime_type do |ingredient| + ingredient.attachment.file_mime_type + end + + attribute :attachment_file_size do |ingredient| + ingredient.attachment.file_size + end + end + end + end +end diff --git a/spec/serializers/alchemy/json_api/ingredient_file_serializer_spec.rb b/spec/serializers/alchemy/json_api/ingredient_file_serializer_spec.rb new file mode 100644 index 0000000..268aff7 --- /dev/null +++ b/spec/serializers/alchemy/json_api/ingredient_file_serializer_spec.rb @@ -0,0 +1,43 @@ +# frozen_string_literal: true +require "rails_helper" + +RSpec.describe Alchemy::JsonApi::IngredientFileSerializer do + let(:ingredient) { FactoryBot.build_stubbed(:alchemy_ingredient_file, title: "File", css_class: "custom") } + let(:attachment) { FactoryBot.build_stubbed(:alchemy_attachment) } + + subject(:serializer) { described_class.new(ingredient) } + + it_behaves_like "an ingredient serializer" + + describe "attributes" do + subject { serializer.serializable_hash[:data][:attributes] } + + context "With attachment set" do + before do + allow(ingredient).to receive(:attachment) { attachment } + end + + it "has the right keys and values" do + expect(subject[:value]).to eq("/attachment/#{attachment.id}/show") + expect(subject[:link_title]).to eq("File") + expect(subject[:attachment_name]).to eq("image") + expect(subject[:attachment_file_name]).to eq("image.png") + expect(subject[:attachment_mime_type]).to eq("image/png") + expect(subject[:attachment_file_size]).to eq(70) + end + end + end + + context "With no attachment set" do + describe "attributes" do + subject { serializer.serializable_hash[:data][:attributes] } + + it "has the right keys and values" do + expect(subject[:attachment_name]).to be_nil + expect(subject[:attachment_file_name]).to be_nil + expect(subject[:attachment_mime_type]).to be_nil + expect(subject[:attachment_file_size]).to be_nil + end + end + end +end From 264c703bdb7e3f28c3327c3ece195b1e7ea1f8d5 Mon Sep 17 00:00:00 2001 From: Thomas von Deyen Date: Wed, 30 Jun 2021 17:04:58 +0200 Subject: [PATCH 05/16] Add Ingredient Html serializer --- .../json_api/ingredient_html_serializer.rb | 11 +++++++++++ .../ingredient_html_serializer_spec.rb | 18 ++++++++++++++++++ 2 files changed, 29 insertions(+) create mode 100644 app/serializers/alchemy/json_api/ingredient_html_serializer.rb create mode 100644 spec/serializers/alchemy/json_api/ingredient_html_serializer_spec.rb diff --git a/app/serializers/alchemy/json_api/ingredient_html_serializer.rb b/app/serializers/alchemy/json_api/ingredient_html_serializer.rb new file mode 100644 index 0000000..8b3e36b --- /dev/null +++ b/app/serializers/alchemy/json_api/ingredient_html_serializer.rb @@ -0,0 +1,11 @@ +# frozen_string_literal: true + +require "alchemy/json_api/ingredient_serializer" + +module Alchemy + module JsonApi + class IngredientHtmlSerializer + include IngredientSerializer + end + end +end diff --git a/spec/serializers/alchemy/json_api/ingredient_html_serializer_spec.rb b/spec/serializers/alchemy/json_api/ingredient_html_serializer_spec.rb new file mode 100644 index 0000000..bd0cc78 --- /dev/null +++ b/spec/serializers/alchemy/json_api/ingredient_html_serializer_spec.rb @@ -0,0 +1,18 @@ +# frozen_string_literal: true +require "rails_helper" + +RSpec.describe Alchemy::JsonApi::IngredientHtmlSerializer do + let(:ingredient) { FactoryBot.build_stubbed(:alchemy_ingredient_html, value: "") } + + subject(:serializer) { described_class.new(ingredient) } + + it_behaves_like "an ingredient serializer" + + describe "attributes" do + subject { serializer.serializable_hash[:data][:attributes] } + + it "has the right keys and values" do + expect(subject[:value]).to eq("") + end + end +end From 3d51910284b0ff41297ede060341a22509903c94 Mon Sep 17 00:00:00 2001 From: Thomas von Deyen Date: Wed, 30 Jun 2021 17:05:01 +0200 Subject: [PATCH 06/16] Add Ingredient Link serializer --- .../json_api/ingredient_link_serializer.rb | 17 +++++++++++ .../ingredient_link_serializer_spec.rb | 30 +++++++++++++++++++ 2 files changed, 47 insertions(+) create mode 100644 app/serializers/alchemy/json_api/ingredient_link_serializer.rb create mode 100644 spec/serializers/alchemy/json_api/ingredient_link_serializer_spec.rb diff --git a/app/serializers/alchemy/json_api/ingredient_link_serializer.rb b/app/serializers/alchemy/json_api/ingredient_link_serializer.rb new file mode 100644 index 0000000..62eb456 --- /dev/null +++ b/app/serializers/alchemy/json_api/ingredient_link_serializer.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +require "alchemy/json_api/ingredient_serializer" + +module Alchemy + module JsonApi + class IngredientLinkSerializer + include IngredientSerializer + + attributes( + :link_class_name, + :link_target, + :link_title + ) + end + end +end diff --git a/spec/serializers/alchemy/json_api/ingredient_link_serializer_spec.rb b/spec/serializers/alchemy/json_api/ingredient_link_serializer_spec.rb new file mode 100644 index 0000000..23a5eee --- /dev/null +++ b/spec/serializers/alchemy/json_api/ingredient_link_serializer_spec.rb @@ -0,0 +1,30 @@ +# frozen_string_literal: true + +require "rails_helper" + +RSpec.describe Alchemy::JsonApi::IngredientLinkSerializer do + let(:ingredient) do + FactoryBot.build_stubbed( + :alchemy_ingredient_link, + value: "/hello", + link_class_name: "external", + link_target: "_blank", + link_title: "Greetings!", + ) + end + + subject(:serializer) { described_class.new(ingredient) } + + it_behaves_like "an ingredient serializer" + + describe "attributes" do + subject { serializer.serializable_hash[:data][:attributes] } + + it "has the right keys and values" do + expect(subject[:value]).to eq("/hello") + expect(subject[:link_class_name]).to eq("external") + expect(subject[:link_target]).to eq("_blank") + expect(subject[:link_title]).to eq("Greetings!") + end + end +end From a7cff515636b90a9bafa210042d64485b8c77c51 Mon Sep 17 00:00:00 2001 From: Thomas von Deyen Date: Wed, 30 Jun 2021 17:05:05 +0200 Subject: [PATCH 07/16] Add Ingredient Node serializer --- .../json_api/ingredient_node_serializer.rb | 35 +++++++++++++ .../ingredient_node_serializer_spec.rb | 50 +++++++++++++++++++ 2 files changed, 85 insertions(+) create mode 100644 app/serializers/alchemy/json_api/ingredient_node_serializer.rb create mode 100644 spec/serializers/alchemy/json_api/ingredient_node_serializer_spec.rb diff --git a/app/serializers/alchemy/json_api/ingredient_node_serializer.rb b/app/serializers/alchemy/json_api/ingredient_node_serializer.rb new file mode 100644 index 0000000..b8af76a --- /dev/null +++ b/app/serializers/alchemy/json_api/ingredient_node_serializer.rb @@ -0,0 +1,35 @@ +# frozen_string_literal: true + +require "alchemy/json_api/ingredient_serializer" + +module Alchemy + module JsonApi + class IngredientNodeSerializer + include IngredientSerializer + + attribute :value do |ingredient| + ingredient.node&.name + end + + belongs_to :node, record_type: :node, serializer: ::Alchemy::JsonApi::NodeSerializer + + with_options if: proc { |ingredient| ingredient.node } do + attribute :name do |ingredient| + ingredient.node.name + end + + attribute :link_url do |ingredient| + ingredient.node.url + end + + attribute :link_title do |ingredient| + ingredient.node.title + end + + attribute :link_nofollow do |ingredient| + ingredient.node.nofollow + end + end + end + end +end diff --git a/spec/serializers/alchemy/json_api/ingredient_node_serializer_spec.rb b/spec/serializers/alchemy/json_api/ingredient_node_serializer_spec.rb new file mode 100644 index 0000000..70057d1 --- /dev/null +++ b/spec/serializers/alchemy/json_api/ingredient_node_serializer_spec.rb @@ -0,0 +1,50 @@ +# frozen_string_literal: true + +require "rails_helper" + +RSpec.describe Alchemy::JsonApi::IngredientNodeSerializer do + let(:ingredient) { FactoryBot.build_stubbed(:alchemy_ingredient_node, node: node) } + let(:node) { FactoryBot.build_stubbed(:alchemy_node, title: "Pop-up explanation", url: "/acdc", nofollow: true, children: [child_node]) } + let(:child_node) { FactoryBot.build_stubbed(:alchemy_node, children: [child_of_child_node]) } + let(:child_of_child_node) { FactoryBot.build_stubbed(:alchemy_node) } + + subject(:serializer) { described_class.new(ingredient) } + + it_behaves_like "an ingredient serializer" + + describe "attributes" do + subject { serializer.serializable_hash[:data][:attributes] } + + it "has the right keys and values" do + expect(subject[:value]).to eq(node.name) + expect(subject[:name]).to eq("A Node") + expect(subject[:link_title]).to eq("Pop-up explanation") + expect(subject[:link_url]).to eq("/acdc") + expect(subject[:link_nofollow]).to be true + end + end + + describe "relationships" do + subject { serializer.serializable_hash[:data][:relationships] } + + it "has the right keys and values" do + expect(subject[:node]).to eq(data: { id: node.id.to_s, type: :node }) + end + end + + context "With no node set" do + let(:node) { nil } + + describe "attributes" do + subject { serializer.serializable_hash[:data][:attributes] } + + it "has the right keys and values" do + expect(subject[:value]).to be_nil + expect(subject[:name]).to be_nil + expect(subject[:link_title]).to be_nil + expect(subject[:link_url]).to be_nil + expect(subject[:link_nofollow]).to be_nil + end + end + end +end From 302cf849440784b1ad927459d9cc3ca8f7fc58af Mon Sep 17 00:00:00 2001 From: Thomas von Deyen Date: Wed, 30 Jun 2021 17:05:08 +0200 Subject: [PATCH 08/16] Add Ingredient Page serializer --- .../json_api/ingredient_page_serializer.rb | 25 +++++++++ .../ingredient_page_serializer_spec.rb | 54 +++++++++++++++++++ 2 files changed, 79 insertions(+) create mode 100644 app/serializers/alchemy/json_api/ingredient_page_serializer.rb create mode 100644 spec/serializers/alchemy/json_api/ingredient_page_serializer_spec.rb diff --git a/app/serializers/alchemy/json_api/ingredient_page_serializer.rb b/app/serializers/alchemy/json_api/ingredient_page_serializer.rb new file mode 100644 index 0000000..4788dfe --- /dev/null +++ b/app/serializers/alchemy/json_api/ingredient_page_serializer.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true + +require "alchemy/json_api/ingredient_serializer" + +module Alchemy + module JsonApi + class IngredientPageSerializer + include IngredientSerializer + + attribute :value do |ingredient| + ingredient.page&.url_path + end + + attribute :page_name do |ingredient| + ingredient.page&.name + end + + attribute :page_url do |ingredient| + ingredient.page&.url_path + end + + has_one :page, record_type: :page, serializer: ::Alchemy::JsonApi::PageSerializer + end + end +end diff --git a/spec/serializers/alchemy/json_api/ingredient_page_serializer_spec.rb b/spec/serializers/alchemy/json_api/ingredient_page_serializer_spec.rb new file mode 100644 index 0000000..7883c20 --- /dev/null +++ b/spec/serializers/alchemy/json_api/ingredient_page_serializer_spec.rb @@ -0,0 +1,54 @@ +# frozen_string_literal: true + +require "rails_helper" + +RSpec.describe Alchemy::JsonApi::IngredientPageSerializer do + let(:ingredient) { FactoryBot.build_stubbed(:alchemy_ingredient_page, page: page) } + let(:page) { FactoryBot.build_stubbed(:alchemy_page) } + + let(:serializer) { described_class.new(ingredient) } + + it_behaves_like "an ingredient serializer" + + subject { serializer.serializable_hash[:data][:attributes] } + + describe "attributes" do + it "has page url as ingredient" do + expect(subject[:value]).to eq(page.url_path) + end + + it "has page_name" do + expect(subject[:page_name]).to eq(page.name) + end + + it "has page_url" do + expect(subject[:page_url]).to eq(page.url_path) + end + end + + describe "relationships" do + subject { serializer.serializable_hash[:data][:relationships] } + + it "has page object" do + expect(subject[:page]).to eq(data: { id: page.id.to_s, type: :page }) + end + end + + context "With no page set" do + let(:page) { nil } + + describe "attributes" do + it "has no ingredient" do + expect(subject[:value]).to be_nil + end + + it "has no page_name" do + expect(subject[:page_name]).to be_nil + end + + it "has no page_url" do + expect(subject[:page_url]).to be_nil + end + end + end +end From 2e98dd3e1773a6339ccc33fe89a35f846c8555b5 Mon Sep 17 00:00:00 2001 From: Thomas von Deyen Date: Wed, 30 Jun 2021 17:05:11 +0200 Subject: [PATCH 09/16] Add Ingredient Picture serializer --- .../json_api/ingredient_picture_serializer.rb | 60 ++++++++++++ .../ingredient_picture_serializer_spec.rb | 96 +++++++++++++++++++ 2 files changed, 156 insertions(+) create mode 100644 app/serializers/alchemy/json_api/ingredient_picture_serializer.rb create mode 100644 spec/serializers/alchemy/json_api/ingredient_picture_serializer_spec.rb diff --git a/app/serializers/alchemy/json_api/ingredient_picture_serializer.rb b/app/serializers/alchemy/json_api/ingredient_picture_serializer.rb new file mode 100644 index 0000000..ccc00da --- /dev/null +++ b/app/serializers/alchemy/json_api/ingredient_picture_serializer.rb @@ -0,0 +1,60 @@ +# frozen_string_literal: true + +require "alchemy/json_api/ingredient_serializer" + +module Alchemy + module JsonApi + class IngredientPictureSerializer + include IngredientSerializer + + attributes( + :title, + :caption, + :link_class_name, + :link_title, + :link_target, + ) + + attribute :value do |ingredient| + ingredient.picture&.url + end + + attribute :alt_text, &:alt_tag + attribute :link_url, &:link + + with_options if: proc { |ingredient| ingredient.picture.present? } do + attribute :image_dimensions do |ingredient| + sizes = ingredient.settings[:size]&.split("x", 2)&.map(&:to_i) || [ + ingredient.image_file_width, + ingredient.image_file_height, + ] + + ratio = ingredient.image_file_width.to_f / ingredient.image_file_height + width = sizes[0].zero? ? sizes[1] * ratio : sizes[0] + height = sizes[1].zero? ? sizes[0] / ratio : sizes[1] + + { + width: width, + height: height, + } + end + + attribute :image_name do |ingredient| + ingredient.picture.name + end + + attribute :image_file_name do |ingredient| + ingredient.picture.image_file_name + end + + attribute :image_mime_type do |ingredient| + "image/#{ingredient.picture.image_file_format}" + end + + attribute :image_file_size do |ingredient| + ingredient.picture.image_file_size + end + end + end + end +end diff --git a/spec/serializers/alchemy/json_api/ingredient_picture_serializer_spec.rb b/spec/serializers/alchemy/json_api/ingredient_picture_serializer_spec.rb new file mode 100644 index 0000000..bb4c7cc --- /dev/null +++ b/spec/serializers/alchemy/json_api/ingredient_picture_serializer_spec.rb @@ -0,0 +1,96 @@ +# frozen_string_literal: true + +require "rails_helper" + +RSpec.describe Alchemy::JsonApi::IngredientPictureSerializer do + let(:ingredient) do + FactoryBot.build_stubbed( + :alchemy_ingredient_picture, + title: "Picture", + link: "/hello", + picture: picture, + ) + end + + let(:picture) { FactoryBot.create(:alchemy_picture, image_file_size: 301) } + + subject(:serializer) { described_class.new(ingredient) } + + it_behaves_like "an ingredient serializer" + + describe "attributes" do + subject { serializer.serializable_hash[:data][:attributes] } + + it "has the right keys and values" do + expect(subject[:title]).to eq("Picture") + expect(subject[:value]).to match(/pictures\/\w+\/image.png/) + expect(subject[:image_name]).to eq("image") + expect(subject[:image_file_name]).to eq("image.png") + expect(subject[:image_mime_type]).to eq("image/png") + expect(subject[:image_file_size]).to eq(301) + expect(subject[:image_dimensions]).to eq(width: 1, height: 1) + end + + describe "image_dimensions" do + let(:image_dimensions) { subject[:image_dimensions] } + + context "without image" do + let(:picture) { nil } + + it { expect(image_dimensions).to be_nil } + end + + context "with image" do + it do + expect(image_dimensions).to eq(width: 1, height: 1) + end + + context "with ingredient settings[:size]" do + before do + expect(ingredient).to receive(:settings).at_least(:once) { size } + end + + let(:size) do + { size: "100x100" } + end + + it do + expect(image_dimensions).to eq(width: 100, height: 100) + end + + context "without y dimension" do + let(:size) do + { size: "100x" } + end + + it "infers height from ratio" do + expect(image_dimensions).to eq(width: 100, height: 100) + end + end + + context "without x dimension" do + let(:size) do + { size: "x50" } + end + + it "infers width from ratio" do + expect(image_dimensions).to eq(width: 50, height: 50) + end + end + end + end + end + end + + context "With no picture set" do + let(:picture) { nil } + + describe "attributes" do + subject { serializer.serializable_hash[:data][:attributes] } + + it "has the right keys and values" do + expect(subject[:value]).to be_nil + end + end + end +end From 36c991964f17d12058eea663d92d4305b400b432 Mon Sep 17 00:00:00 2001 From: Thomas von Deyen Date: Wed, 30 Jun 2021 17:05:15 +0200 Subject: [PATCH 10/16] Add Ingredient Richtext serializer --- .../ingredient_richtext_serializer.rb | 18 +++++++++++++ .../ingredient_richtext_serializer_spec.rb | 26 +++++++++++++++++++ 2 files changed, 44 insertions(+) create mode 100644 app/serializers/alchemy/json_api/ingredient_richtext_serializer.rb create mode 100644 spec/serializers/alchemy/json_api/ingredient_richtext_serializer_spec.rb diff --git a/app/serializers/alchemy/json_api/ingredient_richtext_serializer.rb b/app/serializers/alchemy/json_api/ingredient_richtext_serializer.rb new file mode 100644 index 0000000..59bcb9f --- /dev/null +++ b/app/serializers/alchemy/json_api/ingredient_richtext_serializer.rb @@ -0,0 +1,18 @@ +# frozen_string_literal: true + +require "alchemy/json_api/ingredient_serializer" + +module Alchemy + module JsonApi + class IngredientRichtextSerializer + include IngredientSerializer + + attributes( + :sanitized_body, + :stripped_body, + ) + + attribute :body, &:value + end + end +end diff --git a/spec/serializers/alchemy/json_api/ingredient_richtext_serializer_spec.rb b/spec/serializers/alchemy/json_api/ingredient_richtext_serializer_spec.rb new file mode 100644 index 0000000..450e4f7 --- /dev/null +++ b/spec/serializers/alchemy/json_api/ingredient_richtext_serializer_spec.rb @@ -0,0 +1,26 @@ +# frozen_string_literal: true + +require "rails_helper" + +RSpec.describe Alchemy::JsonApi::IngredientRichtextSerializer do + let(:ingredient) do + FactoryBot.create( + :alchemy_ingredient_richtext, + value: "

Hello

", + ) + end + + subject(:serializer) { described_class.new(ingredient) } + + it_behaves_like "an ingredient serializer" + + describe "attributes" do + subject { serializer.serializable_hash[:data][:attributes] } + + it "has the right keys and values" do + expect(subject[:body]).to eq("

Hello

") + expect(subject[:sanitized_body]).to eq("

Hello

") + expect(subject[:stripped_body]).to eq("Hello") + end + end +end From e71635ecc53df8233d1cae122a46f5646f4fcbae Mon Sep 17 00:00:00 2001 From: Thomas von Deyen Date: Wed, 30 Jun 2021 17:05:19 +0200 Subject: [PATCH 11/16] Add Ingredient Select serializer --- .../json_api/ingredient_select_serializer.rb | 11 +++++++++++ .../ingredient_select_serializer_spec.rb | 19 +++++++++++++++++++ 2 files changed, 30 insertions(+) create mode 100644 app/serializers/alchemy/json_api/ingredient_select_serializer.rb create mode 100644 spec/serializers/alchemy/json_api/ingredient_select_serializer_spec.rb diff --git a/app/serializers/alchemy/json_api/ingredient_select_serializer.rb b/app/serializers/alchemy/json_api/ingredient_select_serializer.rb new file mode 100644 index 0000000..2262343 --- /dev/null +++ b/app/serializers/alchemy/json_api/ingredient_select_serializer.rb @@ -0,0 +1,11 @@ +# frozen_string_literal: true + +require "alchemy/json_api/ingredient_serializer" + +module Alchemy + module JsonApi + class IngredientSelectSerializer + include IngredientSerializer + end + end +end diff --git a/spec/serializers/alchemy/json_api/ingredient_select_serializer_spec.rb b/spec/serializers/alchemy/json_api/ingredient_select_serializer_spec.rb new file mode 100644 index 0000000..5fb5ee2 --- /dev/null +++ b/spec/serializers/alchemy/json_api/ingredient_select_serializer_spec.rb @@ -0,0 +1,19 @@ +# frozen_string_literal: true + +require "rails_helper" + +RSpec.describe Alchemy::JsonApi::IngredientSelectSerializer do + let(:ingredient) { FactoryBot.build_stubbed(:alchemy_ingredient_select, value: "wat") } + + subject(:serializer) { described_class.new(ingredient) } + + it_behaves_like "an ingredient serializer" + + describe "attributes" do + subject { serializer.serializable_hash[:data][:attributes] } + + it "has the right keys and values" do + expect(subject[:value]).to eq("wat") + end + end +end From 567a95880b91dd0493008da394b19a0695ad9a00 Mon Sep 17 00:00:00 2001 From: Thomas von Deyen Date: Wed, 30 Jun 2021 17:05:22 +0200 Subject: [PATCH 12/16] Add ingredients relationship to element serializer --- .../alchemy/json_api/element_serializer.rb | 5 ++++ .../json_api/element_serializer_spec.rb | 23 +++++++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/app/serializers/alchemy/json_api/element_serializer.rb b/app/serializers/alchemy/json_api/element_serializer.rb index b996d73..c15d8a3 100644 --- a/app/serializers/alchemy/json_api/element_serializer.rb +++ b/app/serializers/alchemy/json_api/element_serializer.rb @@ -20,6 +20,11 @@ class ElementSerializer element.contents.map(&:essence) end + has_many :ingredients, + serializer: ->(record) do + "Alchemy::JsonApi::Ingredient#{record.type.demodulize}Serializer".constantize + end + has_many :nested_elements, record_type: :element, serializer: self end end diff --git a/spec/serializers/alchemy/json_api/element_serializer_spec.rb b/spec/serializers/alchemy/json_api/element_serializer_spec.rb index 3772c20..d8add81 100644 --- a/spec/serializers/alchemy/json_api/element_serializer_spec.rb +++ b/spec/serializers/alchemy/json_api/element_serializer_spec.rb @@ -46,7 +46,30 @@ it "has the right keys and values" do expect(subject[:essences]).to eq(data: element.contents.map { |c| { id: c.essence_id.to_s, type: c.essence.class.name.demodulize.underscore.to_sym } }) + expect(subject[:ingredients]).to eq(data: []) expect(subject[:nested_elements]).to eq(data: [{ id: nested_element.id.to_s, type: :element }]) end + + context "with ingredients" do + before do + expect(element).to receive(:ingredients) do + [ + FactoryBot.build_stubbed(:alchemy_ingredient_text, element: element), + FactoryBot.build_stubbed(:alchemy_ingredient_richtext, element: element), + FactoryBot.build_stubbed(:alchemy_ingredient_picture, element: element), + ] + end + end + + it "has the right keys and values" do + expect(subject[:ingredients]).to eq( + data: [ + { id: "1001", type: :ingredient_text }, + { id: "1002", type: :ingredient_richtext }, + { id: "1003", type: :ingredient_picture }, + ], + ) + end + end end end From 36f4c95d3e786ef4a4dd1275cc10e90ad3fb059d Mon Sep 17 00:00:00 2001 From: Thomas von Deyen Date: Wed, 30 Jun 2021 21:21:40 +0200 Subject: [PATCH 13/16] Eager load ingredients in pages controller --- app/controllers/alchemy/json_api/pages_controller.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/app/controllers/alchemy/json_api/pages_controller.rb b/app/controllers/alchemy/json_api/pages_controller.rb index 8e6653a..8b34865 100644 --- a/app/controllers/alchemy/json_api/pages_controller.rb +++ b/app/controllers/alchemy/json_api/pages_controller.rb @@ -61,6 +61,7 @@ def page_scope_with_includes elements: [ :nested_elements, { contents: { essence: :ingredient_association } }, + { ingredients: :related_object }, ], }, }, From 37aadc27dbccba7818b107dae73fdd37c1b83787 Mon Sep 17 00:00:00 2001 From: Thomas von Deyen Date: Thu, 1 Jul 2021 17:53:01 +0200 Subject: [PATCH 14/16] Add ingredient headline serializer --- .../ingredient_headline_serializer.rb | 13 ++++++++ .../ingredient_headline_serializer_spec.rb | 33 +++++++++++++++++++ 2 files changed, 46 insertions(+) create mode 100644 app/serializers/alchemy/json_api/ingredient_headline_serializer.rb create mode 100644 spec/serializers/alchemy/json_api/ingredient_headline_serializer_spec.rb diff --git a/app/serializers/alchemy/json_api/ingredient_headline_serializer.rb b/app/serializers/alchemy/json_api/ingredient_headline_serializer.rb new file mode 100644 index 0000000..b6c0676 --- /dev/null +++ b/app/serializers/alchemy/json_api/ingredient_headline_serializer.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +require "alchemy/json_api/ingredient_serializer" + +module Alchemy + module JsonApi + class IngredientHeadlineSerializer + include IngredientSerializer + + attributes :level, :size + end + end +end diff --git a/spec/serializers/alchemy/json_api/ingredient_headline_serializer_spec.rb b/spec/serializers/alchemy/json_api/ingredient_headline_serializer_spec.rb new file mode 100644 index 0000000..4cfa66b --- /dev/null +++ b/spec/serializers/alchemy/json_api/ingredient_headline_serializer_spec.rb @@ -0,0 +1,33 @@ +# frozen_string_literal: true + +require "rails_helper" + +RSpec.describe Alchemy::JsonApi::IngredientHeadlineSerializer do + let(:element) { FactoryBot.build_stubbed(:alchemy_element) } + let(:ingredient) do + FactoryBot.build_stubbed( + :alchemy_ingredient_headline, + element: element, + role: "headline", + value: "Hello you world", + size: 2, + level: 3, + ) + end + + let(:serializer) { described_class.new(ingredient) } + + it_behaves_like "an ingredient serializer" + + subject { serializer.serializable_hash[:data][:attributes] } + + it do + is_expected.to match( + hash_including( + value: "Hello you world", + level: 3, + size: 2, + ) + ) + end +end From 76773b8d132644f383ce2f980b6935437a12571a Mon Sep 17 00:00:00 2001 From: Thomas von Deyen Date: Mon, 5 Jul 2021 14:32:58 +0200 Subject: [PATCH 15/16] Add Ingredient Video serializer --- .../json_api/ingredient_video_serializer.rb | 42 +++++++++++++++ .../ingredient_video_serializer_spec.rb | 52 +++++++++++++++++++ 2 files changed, 94 insertions(+) create mode 100644 app/serializers/alchemy/json_api/ingredient_video_serializer.rb create mode 100644 spec/serializers/alchemy/json_api/ingredient_video_serializer_spec.rb diff --git a/app/serializers/alchemy/json_api/ingredient_video_serializer.rb b/app/serializers/alchemy/json_api/ingredient_video_serializer.rb new file mode 100644 index 0000000..1fb403c --- /dev/null +++ b/app/serializers/alchemy/json_api/ingredient_video_serializer.rb @@ -0,0 +1,42 @@ +# frozen_string_literal: true + +require "alchemy/json_api/ingredient_serializer" + +module Alchemy + module JsonApi + class IngredientVideoSerializer + include IngredientSerializer + + attributes( + :width, + :height, + :allow_fullscreen, + :autoplay, + :controls, + :preload, + ) + + attribute :value do |ingredient| + ingredient.attachment&.url + end + + with_options if: ->(ingredient) { ingredient.attachment } do + attribute :video_name do |ingredient| + ingredient.attachment.name + end + + attribute :video_file_name do |ingredient| + ingredient.attachment.file_name + end + + attribute :video_mime_type do |ingredient| + ingredient.attachment.file_mime_type + end + + attribute :video_file_size do |ingredient| + ingredient.attachment.file_size + end + end + end + end +end diff --git a/spec/serializers/alchemy/json_api/ingredient_video_serializer_spec.rb b/spec/serializers/alchemy/json_api/ingredient_video_serializer_spec.rb new file mode 100644 index 0000000..2393f89 --- /dev/null +++ b/spec/serializers/alchemy/json_api/ingredient_video_serializer_spec.rb @@ -0,0 +1,52 @@ +# frozen_string_literal: true + +require "rails_helper" + +RSpec.describe Alchemy::JsonApi::IngredientVideoSerializer do + let(:element) { FactoryBot.build_stubbed(:alchemy_element) } + let(:attachment) { FactoryBot.build_stubbed(:alchemy_attachment) } + let(:ingredient) do + Alchemy::Ingredients::Video.new( + role: "video", + element: element, + attachment: attachment, + allow_fullscreen: true, + autoplay: false, + controls: true, + ) + end + + subject(:serializer) { described_class.new(ingredient) } + + it_behaves_like "an ingredient serializer" + + describe "attributes" do + subject { serializer.serializable_hash[:data][:attributes] } + + it "has the right keys and values", :aggregate_failures do + expect(subject[:width]).to eq(nil) + expect(subject[:height]).to eq(nil) + expect(subject[:allow_fullscreen]).to eq(true) + expect(subject[:autoplay]).to eq(false) + expect(subject[:controls]).to eq(true) + expect(subject[:preload]).to eq(nil) + expect(subject[:value]).to match(/\/attachment\/#{attachment.id}\/show/o) + expect(subject[:video_name]).to eq("image") + expect(subject[:video_file_name]).to eq("image.png") + expect(subject[:video_mime_type]).to eq("image/png") + expect(subject[:video_file_size]).to eq(70) + end + end + + context "With no video set" do + let(:attachment) { nil } + + describe "attributes" do + subject { serializer.serializable_hash[:data][:attributes] } + + it "has the right keys and values" do + expect(subject[:ingredient]).to be nil + end + end + end +end From d0344e9dff4cd77cef4e1b49041d459a57b66176 Mon Sep 17 00:00:00 2001 From: Thomas von Deyen Date: Mon, 5 Jul 2021 14:47:33 +0200 Subject: [PATCH 16/16] Add Ingredient Audio serializer --- .../json_api/ingredient_audio_serializer.rb | 40 +++++++++++++++ .../ingredient_audio_serializer_spec.rb | 50 +++++++++++++++++++ 2 files changed, 90 insertions(+) create mode 100644 app/serializers/alchemy/json_api/ingredient_audio_serializer.rb create mode 100644 spec/serializers/alchemy/json_api/ingredient_audio_serializer_spec.rb diff --git a/app/serializers/alchemy/json_api/ingredient_audio_serializer.rb b/app/serializers/alchemy/json_api/ingredient_audio_serializer.rb new file mode 100644 index 0000000..aa6c199 --- /dev/null +++ b/app/serializers/alchemy/json_api/ingredient_audio_serializer.rb @@ -0,0 +1,40 @@ +# frozen_string_literal: true + +require "alchemy/json_api/ingredient_serializer" + +module Alchemy + module JsonApi + class IngredientAudioSerializer + include IngredientSerializer + + attributes( + :autoplay, + :controls, + :muted, + :loop, + ) + + attribute :value do |ingredient| + ingredient.attachment&.url + end + + with_options if: ->(ingredient) { ingredient.attachment } do + attribute :audio_name do |ingredient| + ingredient.attachment.name + end + + attribute :audio_file_name do |ingredient| + ingredient.attachment.file_name + end + + attribute :audio_mime_type do |ingredient| + ingredient.attachment.file_mime_type + end + + attribute :audio_file_size do |ingredient| + ingredient.attachment.file_size + end + end + end + end +end diff --git a/spec/serializers/alchemy/json_api/ingredient_audio_serializer_spec.rb b/spec/serializers/alchemy/json_api/ingredient_audio_serializer_spec.rb new file mode 100644 index 0000000..7fedc46 --- /dev/null +++ b/spec/serializers/alchemy/json_api/ingredient_audio_serializer_spec.rb @@ -0,0 +1,50 @@ +# frozen_string_literal: true + +require "rails_helper" + +RSpec.describe Alchemy::JsonApi::IngredientAudioSerializer do + let(:element) { FactoryBot.build_stubbed(:alchemy_element) } + let(:attachment) { FactoryBot.build_stubbed(:alchemy_attachment) } + let(:ingredient) do + Alchemy::Ingredients::Audio.new( + role: "audio", + element: element, + attachment: attachment, + autoplay: false, + controls: true, + muted: true, + ) + end + + subject(:serializer) { described_class.new(ingredient) } + + it_behaves_like "an ingredient serializer" + + describe "attributes" do + subject { serializer.serializable_hash[:data][:attributes] } + + it "has the right keys and values", :aggregate_failures do + expect(subject[:autoplay]).to eq(false) + expect(subject[:controls]).to eq(true) + expect(subject[:muted]).to eq(true) + expect(subject[:leep]).to eq(nil) + expect(subject[:value]).to match(/\/attachment\/#{attachment.id}\/show/o) + expect(subject[:audio_name]).to eq("image") + expect(subject[:audio_file_name]).to eq("image.png") + expect(subject[:audio_mime_type]).to eq("image/png") + expect(subject[:audio_file_size]).to eq(70) + end + end + + context "With no audio set" do + let(:attachment) { nil } + + describe "attributes" do + subject { serializer.serializable_hash[:data][:attributes] } + + it "has the right keys and values" do + expect(subject[:ingredient]).to be nil + end + end + end +end