Skip to content

Commit

Permalink
Return ingredients value if element asked for ingredient
Browse files Browse the repository at this point in the history
Adds deprecated support for returning an ingredients value if the element
is asked for its ingredient. This helps to migrate existing sites to ingredients.

With the next version of Alchemy this behavior is changed to return the ingredient
record instead.

A helpful deprecation notice is logged.
  • Loading branch information
tvdeyen committed Aug 10, 2021
1 parent 95c93b8 commit bb8e37c
Show file tree
Hide file tree
Showing 6 changed files with 93 additions and 15 deletions.
14 changes: 8 additions & 6 deletions app/helpers/alchemy/elements_block_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -51,21 +51,23 @@ def content(name)
# If the element uses +ingredients+ it returns the +value+ of the ingredient record.
#
def ingredient(name)
element.ingredient(name).presence || element.ingredient_by_role(name)&.value
element.ingredient(name)
end

deprecate ingredient: :value, deprecator: Alchemy::Deprecation

# Returns the value of one of the element's ingredients.
#
def value(name)
element.ingredient_by_role(name)&.value
element.value_for(name)
end

# Returns true if the given content or ingredient has been filled by the user.
# Returns true if the given content or ingredient has a value.
#
def has?(name)
element.has_ingredient?(name) || element.has_value_for?(name)
if element.ingredient_definitions.any?
element.has_value_for?(name)
else
element.has_ingredient?(name)
end
end

# Return's the given content's essence.
Expand Down
17 changes: 14 additions & 3 deletions app/models/alchemy/element/element_essences.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,28 @@ class Element < BaseRecord
module ElementEssences
# Returns the contents essence value (aka. ingredient) for passed content name.
def ingredient(name)
content = content_by_name(name)
return nil if content.blank?
ing = ingredient_by_role(name)
if ing
Alchemy::Deprecation.warn <<~WARN
Using `element.ingredient` to get the value of an ingredient is deprecated and will change in Alchemy 6.1
If you want to read the value of an elements ingredient please use `element.value_for(:ingredient_role)` instead.
The next version of Alchemy will return a `Alchemy::Ingredient` record instead.
WARN
ing.value
else
content = content_by_name(name)
return nil if content.blank?

content.ingredient
content.ingredient
end
end

# True if the element has a content for given name,
# that has an essence value (aka. ingredient) that is not blank.
def has_ingredient?(name)
ingredient(name).present?
end
deprecate has_ingredient?: :has_value_for?, deprecator: Alchemy::Deprecation

# Returns all essence errors in the format of:
#
Expand Down
7 changes: 6 additions & 1 deletion app/models/alchemy/element/element_ingredients.rb
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,11 @@ module ElementIngredients
validates_associated :ingredients, on: :update
end

# The value of an ingredient of the element by role
def value_for(role)
ingredient_by_role(role)&.value
end

# Find first ingredient from element by given role.
def ingredient_by_role(role)
ingredients.detect { |ingredient| ingredient.role == role.to_s }
Expand Down Expand Up @@ -87,7 +92,7 @@ def ingredients_with_errors
# True if the element has a ingredient for given name
# that has a non blank value.
def has_value_for?(role)
ingredient_by_role(role)&.value.present?
value_for(role).present?
end

# Ingredient validation error messages
Expand Down
16 changes: 14 additions & 2 deletions spec/helpers/alchemy/elements_block_helper_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -119,12 +119,24 @@ module Alchemy
let(:ingredient) { element.ingredients.first }

it "should return the ingredients value" do
expect(ingredient).to receive(:value).and_call_original
subject.ingredient(:headline)
Alchemy::Deprecation.silenced do
expect(ingredient).to receive(:value).and_call_original
subject.ingredient(:headline)
end
end
end
end

describe "#value" do
let(:element) { create(:alchemy_element, :with_ingredients) }
let(:ingredient) { element.ingredients.first }

it "should return the ingredients value" do
expect(element).to receive(:value_for).and_call_original
subject.value(:headline)
end
end

describe "#has?" do
context "with element having contents" do
it "should delegate to the element's #has_ingredient? method" do
Expand Down
30 changes: 30 additions & 0 deletions spec/models/alchemy/element_ingredients_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,36 @@
end
end

describe "#value_for" do
let!(:element) { create(:alchemy_element, :with_ingredients) }

context "with role existing" do
let(:ingredient) { element.ingredients.first }

context "with blank value" do
before do
expect(ingredient).to receive(:value) { nil }
end

it { expect(element.value_for(:headline)).to be_nil }
end

context "with value present" do
before do
expect(ingredient).to receive(:value) { "Headline" }
end

it "should return value" do
expect(element.value_for(:headline)).to eq("Headline")
end
end
end

context "role not existing" do
it { expect(element.value_for(:foo)).to be_nil }
end
end

describe "#has_value_for?" do
let!(:element) { create(:alchemy_element, :with_ingredients) }

Expand Down
24 changes: 21 additions & 3 deletions spec/models/alchemy/element_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -719,10 +719,28 @@ module Alchemy
end

context "retrieving contents, essences and ingredients" do
let(:element) { create(:alchemy_element, :with_contents, name: "news") }
describe "#ingredient" do
context "with contents" do
let(:element) { create(:alchemy_element, :with_contents, name: "news") }
let(:essence) { element.content_by_name(:news_headline) }

it "returns a contents value by name" do
expect(essence).to receive(:ingredient).and_call_original
element.ingredient("news_headline")
end
end

context "with ingredients" do
let(:element) { create(:alchemy_element, :with_ingredients) }
let(:ingredient) { element.ingredient_by_role(:headline) }

it "should return an ingredient by name" do
expect(element.ingredient("news_headline")).to eq(EssenceText.first.ingredient)
it "returns a ingredients value by name" do
Alchemy::Deprecation.silenced do
expect(ingredient).to receive(:value).and_call_original
element.ingredient("headline")
end
end
end
end

it "should return the content for rss title" do
Expand Down

0 comments on commit bb8e37c

Please sign in to comment.