Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions app/models/alchemy/element.rb
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ class Element < BaseRecord

validates_presence_of :name, on: :create
validates_format_of :name, on: :create, with: NAME_REGEXP
validate :validate_same_page_version_as_parent

after_initialize :set_default_public_on, if: :new_record?

Expand Down Expand Up @@ -326,6 +327,13 @@ def set_default_public_on
self.public_on ||= Time.current
end

def validate_same_page_version_as_parent
return unless parent_element
return if page_version_id == parent_element.page_version_id

errors.add(:page_version_id, :must_match_parent)
end

def generate_nested_elements
definition.autogenerate.each do |nestable_element|
if nestable_elements.include?(nestable_element)
Expand Down
4 changes: 4 additions & 0 deletions config/locales/alchemy.en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -811,6 +811,10 @@ en:
base:
restrict_dependent_destroy:
has_many: "There are still %{record} attached to this page. Please remove them first."
alchemy/element:
attributes:
page_version_id:
must_match_parent: "must be the same as the parent element's page version"
models:
gutentag/tag:
one: Tag
Expand Down
4 changes: 2 additions & 2 deletions lib/alchemy/test_support/factories/element_factory.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
factory :alchemy_element, class: "Alchemy::Element" do
name { "article" }
autogenerate_ingredients { false }
association :page_version, factory: :alchemy_page_version
page_version { parent_element&.page_version || association(:alchemy_page_version) }

trait :fixed do
fixed { true }
Expand All @@ -21,7 +21,7 @@
end

trait :nested do
parent_element { build(:alchemy_element, name: "slider", page_version: page_version) }
parent_element { association(:alchemy_element, name: "slider") }
name { "slide" }
end

Expand Down
16 changes: 9 additions & 7 deletions spec/controllers/alchemy/admin/elements_controller_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ module Alchemy
describe "#index" do
let!(:page_version) { create(:alchemy_page_version) }
let!(:element) { create(:alchemy_element, page_version: page_version) }
let!(:nested_element) { create(:alchemy_element, :nested, page_version: page_version) }
let!(:parent_for_nested) { create(:alchemy_element, :with_nestable_elements, page_version: page_version) }
let!(:nested_element) { create(:alchemy_element, name: "slide", parent_element: parent_for_nested) }
let!(:hidden_element) { create(:alchemy_element, page_version: page_version, public: false) }

context "with fixed elements" do
Expand All @@ -36,7 +37,7 @@ module Alchemy

it "assigns elements" do
get :index, params: {page_version_id: page_version.id}
expect(assigns(:elements)).to eq([element, nested_element.parent_element, hidden_element])
expect(assigns(:elements)).to eq([element, parent_for_nested, hidden_element])
end
end

Expand Down Expand Up @@ -69,7 +70,7 @@ module Alchemy
end

context "when nested inside parent element" do
let(:parent) { create(:alchemy_element) }
let(:parent) { create(:alchemy_element, page_version: page_version) }

it "touches the cache key of parent element" do
parent.update_column(:updated_at, 3.days.ago)
Expand Down Expand Up @@ -188,12 +189,13 @@ module Alchemy
end

context "with parent_element_id given" do
let(:element_in_clipboard) { create(:alchemy_element, :nested, page_version: page_version) }
let(:parent_element) { create(:alchemy_element, :with_nestable_elements) }
let(:original_parent) { create(:alchemy_element, :with_nestable_elements, page_version: page_version) }
let(:element_in_clipboard) { create(:alchemy_element, name: "slide", parent_element: original_parent) }
let(:new_parent) { create(:alchemy_element, :with_nestable_elements, page_version: page_version) }

it "moves the element to new parent" do
post :create, params: {paste_from_clipboard: element_in_clipboard.id, element: {page_version_id: page_version.id, parent_element_id: parent_element.id}}, xhr: true
expect(Alchemy::Element.last.parent_element_id).to eq(parent_element.id)
post :create, params: {paste_from_clipboard: element_in_clipboard.id, element: {page_version_id: page_version.id, parent_element_id: new_parent.id}}, xhr: true
expect(Alchemy::Element.last.parent_element_id).to eq(new_parent.id)
end
end
end
Expand Down
3 changes: 2 additions & 1 deletion spec/controllers/alchemy/api/elements_controller_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ module Alchemy

before do
2.times { create(:alchemy_element, page_version: page_version) }
create(:alchemy_element, :nested, page_version: page_version)
# Create a slider element which auto-generates a nested slide element
create(:alchemy_element, :with_nestable_elements, page_version: page_version)
end

it "returns all not nested elements from published versions as json objects" do
Expand Down
3 changes: 2 additions & 1 deletion spec/libraries/elements_finder_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,8 @@
end

context "with nested elements present" do
let!(:nested_element) { create(:alchemy_element, :nested, page_version: page_version) }
let!(:parent_element) { create(:alchemy_element, :with_nestable_elements, page_version: page_version) }
let!(:nested_element) { create(:alchemy_element, name: "slide", parent_element: parent_element) }

it "does not include nested elements" do
is_expected.to_not include(nested_element)
Expand Down
24 changes: 24 additions & 0 deletions spec/models/alchemy/element_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,30 @@ module Alchemy
it { is_expected.to have_one(:page).through(:page_version) }
it { is_expected.to have_one(:language).through(:page) }

describe "validations" do
describe "page_version must match parent" do
let(:page_version) { create(:alchemy_page_version) }
let(:other_page_version) { create(:alchemy_page_version) }
let(:parent) { create(:alchemy_element, name: "slider", page_version: page_version) }

it "is valid when page_version matches parent's page_version" do
element = build(:alchemy_element, name: "slide", parent_element: parent, page_version: page_version)
expect(element).to be_valid
end

it "is invalid when page_version differs from parent's page_version" do
element = build(:alchemy_element, name: "slide", parent_element: parent, page_version: other_page_version)
expect(element).not_to be_valid
expect(element.errors[:page_version_id]).to include("must be the same as the parent element's page version")
end

it "is valid for root elements (no parent)" do
element = build(:alchemy_element, page_version: page_version)
expect(element).to be_valid
end
end
end

# to prevent memoization
before { ElementDefinition.instance_variable_set(:@definitions, nil) }

Expand Down
Loading