Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Question: rendering raw JSON #204

Closed
disbelief opened this issue Jul 2, 2014 · 13 comments
Closed

Question: rendering raw JSON #204

disbelief opened this issue Jul 2, 2014 · 13 comments

Comments

@disbelief
Copy link

So this might be too unusual a use case, but I have some pre-rendered JSON stored in memory already and I'd like to include it in my Jbuilder templates without needing to deserialize it first. Seems silly to deserialize JSON just to pass it to Jbuilder for serialization again.

What I'm doing now:

hash = JSON.parse(raw_json_string)
json.some_key hash

Ideally I'd like to do something like:

json.raw! :some_key, raw_json_string

Is this silly?

@rwz
Copy link
Collaborator

rwz commented Jul 3, 2014

You could implement this feature like this:

# config/initializers/jbuilder_raw.rb

require "jbuilder"

class Jbuilder
  def set_raw!(attribute_name, json_string)
    set! attribute_name, MultiJson.load(json_string)
  end
end

And in your views use like this:

json.set_raw! :foo, bar

@rwz rwz closed this as completed Jul 3, 2014
@disbelief
Copy link
Author

Thanks for the reply, however this is essentially just moving what I was already doing down to the Jbuilder layer

I'm trying to avoid having to deserialize the JSON string entirely. Since Jbuilder just serializes it back into JSON after it's passed in as a Ruby hash. Ideally the set_raw! method would inject the raw JSON string into its final JSON output.

The conversion: JSON string -> Ruby Hash -> JSON String seems redundant to me, and slows performance if the JSON String is large/complex.

@rwz
Copy link
Collaborator

rwz commented Jul 3, 2014

Jbuilder is doing MultiJson.dump(attributes_object) as the final step. There is no conventional way to inject raw json into serialiation process.

@disbelief
Copy link
Author

Ah okay thanks @rwz! Wanted to see how feasible a set_raw! method would be. Sounds like it would require more modifications to Jbuilder than I'd like so I'll consider something else.

Out of curiosity, how does the cache! method work? If there's a cache hit, does the cached JSON also get deserialized by MulitJson before being dumped back into JSON?

@rwz
Copy link
Collaborator

rwz commented Jul 3, 2014

cache! caches hash structure that later gets merged into the result before passing to MultiJson.dump.

As far as I know, partial injection of JSON is not yet implemented anywhere.

@disbelief
Copy link
Author

I see, thanks again @rwz!

I might try to use the cache mechanism instead of a raw json string then. Sounds like there's still some serialization/deserialization that takes place, but performance might be better.

@shaokun
Copy link

shaokun commented Aug 26, 2014

It would be useful to support partial injection of JSON in some case. For example, extremely high performance are required.
After some googleing, I found that I could do something like:

require 'oj'

class CompiledJson
  def initialize(s); @s = s; end
  def to_json(*args); @s; end
  def to_s; @s; end

  undef_method :as_json
end

Oj.default_options = {:mode => :compat, use_to_json: true}

result = Jbuilder.new do |json|
  json.a CompiledJson.new('{x: "y"}')
end

puts result.target!
# => {"a": {x: "y"}}

@rwz
Copy link
Collaborator

rwz commented Aug 26, 2014

@shaokun it's already there and works since forever.

class CompiledJson
  def initialize(s); @s = s; end
  def to_json(*); @s; end
end

Jbuilder.encode do |json|
  json.thing CompiledJson.new("foobar")
end # => "{\"thing\":foobar}"

@disbelief
Copy link
Author

@rwz @shaokun thanks! This is actually exactly what I was looking for originally.

@shaokun
Copy link

shaokun commented Aug 27, 2014

@rwz The example you given doesn't work in a newly created rails 4.1.4 project. But it seems to work in rails 4.0.x. It returns # => "{"thing":{"s":"foobar"}}"

I am using oj and I followed the instruction here: ohler55/oj#140
It's something related to as_json and that's why I undefine that method.

I am also wondering it's possible to provide some API in jbuilder to support this cached json string? Something similar to the cache! API. It's difficult when I think about it, because the jbuilder is based on hash and array merging, so given an string, we will need to manually specify a key for it.

@rwz
Copy link
Collaborator

rwz commented Aug 31, 2014

Well, that is actually because active support changed the way it handles json since 4.1. And because it defines to_json/as_json behavior for all classes, there is practically no way around it that doesn't involve modifying its internals.

So, here's the code I ended up with having a very similar problem: https://gist.github.com/rwz/14c0d8a5187b69922bb4

@waissbluth
Copy link

Thank you @rwz that was really helpful. I wonder if support for this could be added to jbuilder though.

@skensell
Copy link

skensell commented Aug 2, 2016

Any chance jbuilder will support raw JSON in the near future? My use case is that I'm doing a postgres database query using the aggregate function 'json_agg' which conveniently returns the needed raw json. It would be great if I could just inject it into my jbuilder templates. I guess for now I'll go with the gist @RWS provided, thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants