3

Problem

In PHP I'd do this

<html>
<body>
    <script>
        <?php
        $templates = array(
          'result' => file_get_contents('template.html')
          );
          echo '__templates = ' . json_encode($templates) . ';';
          ?>
    </script>
</body>
</html>

So I did this in Sinatra

<!DOCTYPE html>
<html>
<body>
    <script type="text/javascript">
        __templates = <%= get_templates  %>;
    </script>
</body>
</html>

And my Sinatra routes file looks like this:

require 'sinatra'
require 'json'
require 'erb'

helpers do
    def get_templates
        {'result' => (erb :template2)}.to_json
    end
end

get '/' do
    erb :index
end

But my javascript object ends up broken when I consume the __templates object from jquery.

What does ruby's to_json do that PHP's does not?

php result

{"result":"<!doctype html>\n<html>\n\n<head>\n\t<meta charset=\"UTF-8\">\n\t<title>{{ TITLE }}<\/title>\n\n\t<style type=\"text\/css\">\n\t{{ CSS }}\n\t<\/style>\n<\/head>\n\n<body>\n\n\t{{{ HTML }}}\n\n\t<script src=\"{{{ JSLIB }}}\"><\/script>\n\t<script src=\"{{{ PREFIX }}}\"><\/script>\n\t<script>\n\t\tfunction __run() {\n\t\t\t{{{ JS }}}\n\t\t}\n\t<\/script>\n\n<\/body>\n\n<\/html>"}

ruby result

{"result":"<!doctype html>\n<html>\n\n<head>\n    <meta charset=\"UTF-8\">\n    <title>{{ TITLE }}</title>\n\n    <style type=\"text/css\">\n        {{ CSS}}\n    </style>\n</head>\n\n<body>\n\n    {{{ HTML }}}\n\n    <script src=\"{{{ JSLIB }}}\"></script>\n    <script src=\"{{{ PREFIX }}}\"></script>\n    <script>\n        function __run() {\n            {{{ JS }}}\n        }\n    </script>\n\n</body>\n\n</html>\n"};

notice the <\/body> on the php version.

Solution (for now)

I found a solution based on comments posted below. However, I'm not sure if this is the 'one true way', if that exists. NOTE: I'd like to know if this implementation would break something else down the road. I'll be depending on this function throughout my application.

I ended up just using gsub to solve my problem. I wrapped it in a helper like this

helpers do
    def close embedded_json
        embedded_json.gsub('</', '<\/')
    end
    ...
end

and called it like this

__templates = <%= close get_templates  %>;

it seems jangy, but under the covers, maybe the helpers alluded to in rails do the same thing? I'm going to move on for now, but I'd still like to know if I'll be shot in the foot later by this.

11
  • 1
    What does the resulting JSON output look like? Commented Feb 5, 2012 at 5:19
  • What error do you get? Can you check in the console? Commented Feb 5, 2012 at 5:26
  • 2:9393/:197Uncaught SyntaxError: Unexpected token ILLEGAL Commented Feb 5, 2012 at 5:31
  • Hmm, the ruby output is valid JSON according to jsonlint.com Commented Feb 5, 2012 at 5:41
  • There's no semicolon at the end of the Ruby json example, but that's probably just a type/copy-past error. Commented Feb 5, 2012 at 5:46

3 Answers 3

2

It's all about those backslashes.

Anywhere something like </title> shows up in the JSON, it needs to actually be <\/title>

The problem is the .to_json isn't adding those backslashes.

How can we make it?

Sign up to request clarification or add additional context in comments.

4 Comments

You could "...".to_json.gsub('</', '<\/') (not that single quotes are important here.
</title> is a forward slash - no need to escape is there?
No because in ruby "\/" == "/". Single quotes would be a different story.
Note that they only need to be escaped when the JSON is being injected into JavaScript that is being embedded in HTML. The end tags terminate the script (in theory for most of them and definitely when it is </script>).
0

I think the problem is no that that the json isn't json (nothing wrong with / in a json string) but that you are inside an html documnt and so characters like </ have special significance.

I'd guess that it looks to the HTML parser that the is a dodgy attempt to close the actual body tag in your document. If you enclose the json with a CDATA section, ie

<script type="text/javascript">
//<![CDATA[
  <%= get_templates %>
//]]>
</script>

Then the HTML parser will know to not do that. There may well be helpers in Sinatra to do tht already

1 Comment

That will stop an XML parser from treating the tags as tags, but that won't help unless it is an XHTML document being served as application/xhtml+xml. Explicit CDATA blocks are not supported by most HTML parsers on the market.
-1

This might be overkill but when i worked with Rails using to_json, i hated it and found RABL https://github.com/nesquena/rabl.

You should have a look at it.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.