Skip to content

Commit

Permalink
Values and Variables (#3959)
Browse files Browse the repository at this point in the history
* dynamic values - work in progress

* add specs

* Add erb support, update content documentation

* fix tab

* Update values.html.erb

* add nonindex + authentication on /values page

* Test inputting a variable in a page (to revert after)

* Revert "Test inputting a variable in a page (to revert after)"

This reverts commit b992458.

* fix double back-tick

---------

Co-authored-by: MylesJarvis <myles.jarvis@education.gov.uk>
  • Loading branch information
martyn-w and MylesJarvis authored May 2, 2024
1 parent 4fd75fb commit 48dffea
Show file tree
Hide file tree
Showing 14 changed files with 217 additions and 2 deletions.
11 changes: 11 additions & 0 deletions app/controllers/pages_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,17 @@ def welcome_my_journey_into_teaching
render_page("welcome/my-journey-into-teaching")
end

def authenticate?
# restrict the /values page to any user who has a login
%w[values].include?(action_name) || super
end

def values
# restrict the /values page to any user who has a login
render_forbidden if session[:user].blank?
render template: "pages/values", layout: "content"
end

private

def adviser_sign_up_url
Expand Down
5 changes: 5 additions & 0 deletions app/helpers/content_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,9 @@ def article_classes(front_matter)
def display_content_errors?
Rails.application.config.x.display_content_errors
end

def value(key)
Value.data[key.to_s]
end
alias_method :v, :value
end
36 changes: 36 additions & 0 deletions app/models/value.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
class Value
PATH = "config/values/**/*.yml".freeze
attr_reader :data

def self.data
# the value data will rarely change, so OK to cache in a class variable
@@data ||= new.data
end

def initialize(path = nil)
@data = load_values(path || Rails.root.join(PATH))
end

private

def load_values(dir_spec)
{}.tap do |data|
Dir[dir_spec].each do |filename|
data.merge!(flatten_hash(YAML.load_file(filename)))
end
end
end

def flatten_hash(hash)
# based on https://stackoverflow.com/questions/23521230/flattening-nested-hash-to-a-single-hash-with-ruby-rails
hash.each_with_object({}) do |(k, v), h|
if v.is_a? Hash
flatten_hash(v).map do |h_k, h_v|
h["#{k}_#{h_k}"] = h_v
end
else
h[k] = v
end
end
end
end
6 changes: 6 additions & 0 deletions app/views/pages/values.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
title: Values
noindex: true
content:
- pages/values/table
---
26 changes: 26 additions & 0 deletions app/views/pages/values/_table.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<table>
<thead>
<tr>
<th>
Key
</th>
<th>
Value
</th>
</tr>
</thead>
<tbody>
<% Value.data.each do |key, value| %>
<tr>
<td>
<code>
$<%= key %>$
</code>
</td>
<td>
<%= value %>
</td>
</tr>
<% end %>
</tbody>
</table>
1 change: 1 addition & 0 deletions config/routes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@
get "/privacy-policy", to: "pages#privacy_policy", as: :privacy_policy
get "/cookies", to: "pages#cookies", as: :cookies
get "/session-expired", to: "pages#session_expired", as: :session_expired
get "/values", to: "pages#values", as: :values

get "/welcome", to: "pages#welcome", as: :welcome_guide
get "/welcome/my-journey-into-teaching", to: "pages#welcome_my_journey_into_teaching", as: :welcome_my_journey_into_teaching
Expand Down
5 changes: 5 additions & 0 deletions config/values/dates.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
dates:
example:
opening: 1st September 2024

dates_example_closing: 31/12/2024
5 changes: 5 additions & 0 deletions config/values/salaries.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
salaries:
example:
min: £30,000

salaries_example_max: £41k
38 changes: 37 additions & 1 deletion docs/content.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ This documentation aims to be a reference for content editors that want to make
* [Inset text](#inset-text)
* [YouTube Video](#youtube-video)
* [Hero](#hero)
* [Values](#values)
4. [Creating a Blog Post](#creating-a-blog-post)
* [Images](#images)
* [Footers](#footers)
Expand Down Expand Up @@ -287,6 +288,41 @@ hero_bg_color: white
hero_blend_content: true
```

### Values

You can use the Values system to maintain key values (e.g. salaries, dates, fees etc) in a single file, and then use these values throughout the site's content. Set up a list of values in one or more YML files stored in the `config/values/` folder (or sub-folder), for example `config/values/dates.yml`:

```yaml
dates:
example:
opening: 1st September 2024
dates_example_closing: 31/12/2024
```

These values can then be used in markdown files by referencing the value as `$value_name$`, e.g. `$dates_example_opening$` or `$dates_example_closing$`. Note that structured composite keys will be flattened to a single key.

An example markdown implementation might be:

```markdown
# Useful dates
The closing date for applications is $dates_example_closing$. It is important to submit your application in good time.
```

Values can also be used in ERB templates using `<%= value :value_name %>` (or as a shorthand, `<%= v :value_name %>`).

An example ERB implementation might be:

```html
<h1>Useful dates</h1>
<p>
The opening date for applications is <%= v :dates_example_opening %>.
</p>
```

A list of the current values available on the site can be viewed at the `/values` endpoint.

## Creating a Blog Post

Blog posts should be written in Markdown format using the following template as a guide:
Expand Down Expand Up @@ -574,4 +610,4 @@ You can find everywhere a page is linked to by:
## Resolving comments
People can add comments to pull requests in Github which makes it easier to see feedback and keep track of changes. You can also tag people and reply to their comments.
Once you've addressed a comment click on resolve. This hides it from the conversation making it easier to keep track of what's been updated.
Once you've addressed a comment click on resolve. This hides it from the conversation making it easier to keep track of what's been updated.
6 changes: 5 additions & 1 deletion lib/template_handlers/markdown.rb
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ def markdown
# entire placeholder to the arg (including dollar symbols) but we only
# want what's inside the capture group
parsed.content.gsub(COMPONENT_PLACEHOLDER_REGEX) do
safe_join([cta_component($1), content_component($1), image($1)].compact).strip
safe_join([cta_component($1), content_component($1), image($1), value($1)].compact).strip
end
end
# rubocop:enable Style/PerlBackrefs
Expand Down Expand Up @@ -95,6 +95,10 @@ def image(placeholder)
ApplicationController.render(component, layout: false)
end

def value(placeholder)
Value.data[placeholder]
end

def front_matter
@front_matter ||= self.class.global_front_matter.deep_merge(parsed.front_matter)
end
Expand Down
5 changes: 5 additions & 0 deletions spec/fixtures/files/example_values/data1.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
data1:
example:
date: 01/02/2003

data1_example_amount: £1,234.56
5 changes: 5 additions & 0 deletions spec/fixtures/files/example_values/data2.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
data2:
example:
string: Hello World!

data2_example_number: 0.01
34 changes: 34 additions & 0 deletions spec/lib/template_handlers/markdown_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -262,4 +262,38 @@
is_expected.to have_css("ol.steps")
end
end

describe "injecting values" do
let(:front_matter) { { "title": "Page with view components" } }

let :markdown do
<<~MARKDOWN
# Some page
data1_example_amount: $data1_example_amount$
Some text
data2_example_string: $data2_example_string$
MARKDOWN
end

let(:value_data) { Value.new("spec/fixtures/files/example_values/**/*.yml").data }

before do
allow(described_class).to receive(:global_front_matter).and_return(front_matter)
allow(Value).to receive(:data).and_return(value_data)
stub_template "page_with_rich_content.md" => markdown
render template: "page_with_rich_content"
end

subject { rendered }

it "contains the specified view components" do
is_expected.to have_text("Some page")
is_expected.to have_text("data1_example_amount: £1,234.56")
is_expected.to have_text("Some text")
is_expected.to have_text("data2_example_string: Hello World!")
end
end
end
36 changes: 36 additions & 0 deletions spec/models/value_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
require "rails_helper"

describe Value do
describe "##data (class method)" do
subject { described_class.data }

it { is_expected.to be_a Hash }
end

describe "#data" do
subject { instance.data }

let(:instance) { described_class.new(path) }

context "with default path" do
let(:path) { nil }

it { is_expected.to be_a Hash }
end

context "with specific file path" do
let(:path) { "spec/fixtures/files/example_values/**/*.yml" }

it {
is_expected.to eql(
{
"data1_example_amount" => "£1,234.56",
"data1_example_date" => "01/02/2003",
"data2_example_number" => 0.01,
"data2_example_string" => "Hello World!",
},
)
}
end
end
end

0 comments on commit 48dffea

Please sign in to comment.