Hello,
I’m trying to render a Json with microformat data in the root of the template.
Initially I did it writing the json in a template, but it seems inneficient, and buggy:
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "LocalBusiness",
<%= if @data.name != nil do %>"name": "<%= @data.name %>"<% end %>,
<%= if @data.description != nil do %>"description": "<%= @data.description %>"<% end %>,
<%= if @data.phone != nil do %>"telephone": "<%= @data.phone %>"<% end %>,
<%= if @data.has_geo_data do %>
"geo": {
"@type": "GeoCoordinates",
"latitude": <%= @data.latitude %>,
"longitude": <%= @data.longitude %>
},
<%= render("geo.json", latitude: @data.latitude, longitude: @data.longitude)%>
<% end %>
"address": {
"@type": "PostalAddress",
<%= if @data.address.street_address != nil do %>"streetAddress": "<%= @data.address.street_address %>",<% end %>
<%= if @data.address.address_locality != nil do %>"addressLocality": "<%= @data.address.address_locality %>",<% end %>
<%= if @data.address.address_region != nil do %>"addressRegion": "<%= @data.address.address_region %>",<% end %>
<%= if @data.address.postal_code != nil do %>"postalCode": "<%= @data.address.postal_code %>",<% end %>
<%= if @data.address.address_country_code != nil do %>"addressCountry": "<%= @data.address.address_country_code %>",<% end %>
}
}
</script>
Too many conditionals, and tje json is not valid because of the last comma.
I thought that maybe I could render a map instead, and did a test only with the geo data:
<%= render("geo.json", latitude: @data.latitude, longitude: @data.longitude) %>
The idea is to render the whole json the same way, but I just started with this section.
This is the view:
def render("geo.json", %{longitude: longitude, latitude: latitude})
when is_float(longitude) and is_float(latitude) do
%{
"geo" => %{
"@type" => "GeoCoordinates",
"latitude" => latitude,
"longitude" => longitude
}
}
|> Jason.encode_to_iodata!()
|> raw
end
def render("geo.json", _) do
raw(nil)
end
(1) First question: Is this efficient because of the usage of Jason.encode_to_iodata()
?or maybe the latest raw
make it inefficient?
(2) Second question: Since I want it to be rendered inside the template, I have to mark it safe using raw
but this is data comming from the database that is being introduced by the users. This is not safe.
For latitude & longitude is not that bad, but if the users set the name to <script>..some script code..</script>
then we have a security risk.
My initial idea was to iterate witn Enum.map
over the map and apply html_escape to each value.
It should be a recursive function because the map can have another map as a value.
Do you think there is a better way of doing this with Phoenix?
Thanks!
Adrián