From 58758b370a19589cef0cfdbcddd598e680eacc66 Mon Sep 17 00:00:00 2001 From: Thomas von Deyen Date: Tue, 19 Jan 2021 20:05:10 +0100 Subject: [PATCH] Use our optimized decorators to serialize pages BREAKING: This removes the all_elements relation from the includable relationships and uses an eager loaded elements collection that includes all publicly available elements from that page. Use client side filtering and grouping to seperate fixed ones from other elements and use a deserializer that supports nesting. --- .../alchemy/json_api/pages_controller.rb | 9 +++--- .../alchemy/json_api/page_serializer.rb | 14 ++++----- spec/requests/alchemy/json_api/pages_spec.rb | 2 +- .../alchemy/json_api/page_serializer_spec.rb | 29 +++++++++---------- 4 files changed, 27 insertions(+), 27 deletions(-) diff --git a/app/controllers/alchemy/json_api/pages_controller.rb b/app/controllers/alchemy/json_api/pages_controller.rb index 83de448..b38d3ce 100644 --- a/app/controllers/alchemy/json_api/pages_controller.rb +++ b/app/controllers/alchemy/json_api/pages_controller.rb @@ -1,4 +1,5 @@ # frozen_string_literal: true + module Alchemy module JsonApi class PagesController < JsonApi::BaseController @@ -48,15 +49,15 @@ def page_scope def page_scope_with_includes base_page_scope. with_language(Language.current). - preload(language: {nodes: [:parent, :page]}, all_elements: [:parent_element, :nested_elements, { contents: { essence: :ingredient_association } }]) + preload(language: { nodes: [:parent, :page] }, elements: { contents: { essence: :ingredient_association } }) end def base_page_scope # cancancan is not able to merge our complex AR scopes for logged in users - if can?(:edit_content, Page) - Page.all + if can?(:edit_content, ::Alchemy::Page) + ::Alchemy::JsonApi::Page.all else - Page.published + ::Alchemy::JsonApi::Page.published end end diff --git a/app/serializers/alchemy/json_api/page_serializer.rb b/app/serializers/alchemy/json_api/page_serializer.rb index 5841ffd..a5f9522 100644 --- a/app/serializers/alchemy/json_api/page_serializer.rb +++ b/app/serializers/alchemy/json_api/page_serializer.rb @@ -17,16 +17,16 @@ class PageSerializer ) belongs_to :language, record_type: :language, serializer: ::Alchemy::JsonApi::LanguageSerializer - has_many :elements, record_type: :element, serializer: ::Alchemy::JsonApi::ElementSerializer - has_many :fixed_elements, record_type: :element, serializer: ::Alchemy::JsonApi::ElementSerializer - - has_many :all_elements, record_type: :element, serializer: ::Alchemy::JsonApi::ElementSerializer do |page| - page.all_elements.select { |e| e.public? && !e.trashed? } - end with_options if: ->(_, params) { params[:admin] == true } do - attribute :tag_list + attribute :tag_list do |page| + Gutentag::Tagging.where( + taggable_id: page.id, + taggable_type: "Alchemy::Page", + ).joins(:tag).pluck("gutentag_tags.name") + end + attribute :status end end diff --git a/spec/requests/alchemy/json_api/pages_spec.rb b/spec/requests/alchemy/json_api/pages_spec.rb index f48dcc5..657b609 100644 --- a/spec/requests/alchemy/json_api/pages_spec.rb +++ b/spec/requests/alchemy/json_api/pages_spec.rb @@ -32,7 +32,7 @@ let(:element) { FactoryBot.create(:alchemy_element, name: "article", autogenerate_contents: true) } it "includes the data" do - get alchemy_json_api.page_path(page, include: "all_elements.essences") + get alchemy_json_api.page_path(page, include: "elements.essences") included = JSON.parse(response.body)["included"] expect(included).to include(have_type("element").and(have_id(element.id.to_s))) end diff --git a/spec/serializers/alchemy/json_api/page_serializer_spec.rb b/spec/serializers/alchemy/json_api/page_serializer_spec.rb index af172b3..bfdad11 100644 --- a/spec/serializers/alchemy/json_api/page_serializer_spec.rb +++ b/spec/serializers/alchemy/json_api/page_serializer_spec.rb @@ -3,7 +3,7 @@ require "alchemy/test_support/factories" RSpec.describe Alchemy::JsonApi::PageSerializer do - let(:page) do + let(:alchemy_page) do FactoryBot.create( :alchemy_page, urlname: "a-page", @@ -14,6 +14,7 @@ ) end let(:options) { {} } + let(:page) { Alchemy::JsonApi::Page.find(alchemy_page.id) } subject(:serializer) { described_class.new(page, options) } @@ -52,22 +53,20 @@ end describe "relationships" do - let(:element) { FactoryBot.create(:alchemy_element) } - let(:fixed_element) { FactoryBot.create(:alchemy_element, fixed: true) } - let(:trashed_element) { FactoryBot.create(:alchemy_element, :trashed) } - subject { serializer.serializable_hash[:data][:relationships] } + let!(:element) { FactoryBot.create(:alchemy_element, page: alchemy_page) } + let!(:fixed_element) { FactoryBot.create(:alchemy_element, page: alchemy_page, fixed: true) } + let!(:non_public_element) { FactoryBot.create(:alchemy_element, page: alchemy_page, public: false) } + let!(:trashed_element) { FactoryBot.create(:alchemy_element, page: alchemy_page).tap(&:trash!) } - before do - page.all_elements << element - page.all_elements << fixed_element - page.all_elements << trashed_element - trashed_element.trash! - end + subject { serializer.serializable_hash[:data][:relationships] } - it "has the right keys and values, and does not include trashed elements" do - expect(subject[:elements]).to eq(data: [{ id: element.id.to_s, type: :element }]) - expect(subject[:fixed_elements]).to eq(data: [{ id: fixed_element.id.to_s, type: :element }]) - expect(subject[:all_elements]).to eq(data: [{ id: element.id.to_s, type: :element }, { id: fixed_element.id.to_s, type: :element }]) + it "has the right keys and values, and does not include trashed or hidden elements" do + expect(subject[:elements]).to eq( + data: [ + { id: element.id.to_s, type: :element }, + { id: fixed_element.id.to_s, type: :element }, + ], + ) expect(subject[:language]).to eq(data: { id: page.language_id.to_s, type: :language }) end end