Rendering a simple Ruby hash with RABL
Asked Answered
K

7

20

I have a ruby hash that I'd like to render using RABL. The hash looks something like this:

@my_hash = {
    :c => {
        :d => "e"
    }
}

I'm trying to render this with some RABL code:

object @my_hash => :some_object
attributes :d
node(:c) { |n| n[:d] }

but I'm receiving {"c":null}

How can I render this with RABL?

Koziol answered 20/1, 2012 at 3:17 Comment(0)
A
22

Currently RABL doesn't play too nicely with hashes. I was able to work around this by converting my hash to an OpenStruct format (which uses a more RABL-friendly dot-notation). Using your example:

your_controller.rb

require 'ostruct'
@my_hash = OpenStruct.new
@my_hash.d = 'e'

your_view.rabl

object false
child @my_hash => :c do
    attributes :d
end

results

{
  "c":{
    "d":"e"
  }
}
Apron answered 22/3, 2012 at 15:4 Comment(1)
Looks like you don't have to use dot notation if you wrap the hash in a OpenStruct. github.com/nesquena/rabl/wiki/Rendering-hash-objects-in-rablCol
A
32

This works for arbitrary hash values.

object false

@values.keys.each do |key|
  node(key){ @values[key] }
end

Worked for me using Rails 3.2.13 and Ruby 2.0.0-p195

Ariminum answered 28/6, 2013 at 16:44 Comment(1)
This is by far the most elegant answer, buried at the bottom. Much nicer than forcing you to create an OpenStruct!Thurman
A
22

Currently RABL doesn't play too nicely with hashes. I was able to work around this by converting my hash to an OpenStruct format (which uses a more RABL-friendly dot-notation). Using your example:

your_controller.rb

require 'ostruct'
@my_hash = OpenStruct.new
@my_hash.d = 'e'

your_view.rabl

object false
child @my_hash => :c do
    attributes :d
end

results

{
  "c":{
    "d":"e"
  }
}
Apron answered 22/3, 2012 at 15:4 Comment(1)
Looks like you don't have to use dot notation if you wrap the hash in a OpenStruct. github.com/nesquena/rabl/wiki/Rendering-hash-objects-in-rablCol
K
6

Sometimes its easy to do too much imho.

How about just

render json: my_hash

And just like magic we can delete some code !

Kish answered 6/3, 2013 at 21:49 Comment(1)
The question is specifically for Rabl rendering and not using render :json.Discerning
C
5

RABL deals in objects but does not require a particular ORM. Just objects that support dot notation. If you want to use rabl and all you have is a hash:

@user = { :name => "Bob", :age => 27, :year => 1976 }

then you need to first turn the hash into an object that supports dot notation:

@user = OpenStruct.new({ :name => "Bob", :age => 27, :year => 1976 })

and then within a RABL template treat the OpenStruct as any other object:

object @user
attributes :name, :age, :year

Consider that if everything you are doing in your app is just dealing in hashes and there is no objects or databases involved, you may be better off with an alternative more custom JSON builder such as json_builder or jbuilder.

Pasted from the official wiki page on RABL's github: https://github.com/nesquena/rabl/wiki/Rendering-hash-objects-in-rabl

Caravansary answered 4/5, 2014 at 5:5 Comment(0)
L
4

RABL actually can render ruby hashes and arrays easily, as attributes, just not as the root object. So, for instance, if you create an OpenStruct like this for the root object:

@my_object = OpenStruct.new
@my_object.data = {:c => {:d => 'e'}}

Then you could use this RABL template:

object @my_object

attributes :data

And that would render:

{"data": {"c":{"d":"e"}} }

Alternatively, if you want :c to be a property of your root object, you can use "node" to create that node, and render the hash inside that node:

# -- rails controller or whatever --
@my_hash = {:c => {:d => :e}}

# -- RABL file --
object @my_hash
# Create a node with a block which receives @my_hash as an argument:
node { |my_hash|
  # The hash returned from this unnamed node will be merged into the parent, so we
  # just return the hash we want to be represented in the root of the response.
  # RABL will render anything inside this hash as JSON (nested hashes, arrays, etc)
  # Note: we could also return a new hash of specific keys and values if we didn't
  # want the whole hash
  my_hash
end

# renders:
{"c": {"d": "e"}}

Incidentally, this is exactly the same as just using render :json => @my_hash in rails, so RABL is not particularly useful in this trivial case ;) But it demonstrates the mechanics anyway.

Law answered 4/2, 2013 at 17:32 Comment(0)
R
2

By specifying a node like that, you are given access to the @my_hash object which you can then access attributes of. So I would just slightly change your code to be:

object @my_hash
node(:c) do |c_node|
  {:d => c_node.d}
end

where c_node is essentially the @my_hash object. This should give you what you're expecting (shown here in JSON):

{
   "my_hash":{
      "c":{
         "d":"e"
      }
   }
}
Rommel answered 20/1, 2012 at 6:41 Comment(2)
Unfortunately I get this error undefined method 'd' for :c:Symbol when using the above code.Koziol
Is .d a valid attribute of @my_hash? It needs to be, otherwise what you're trying to do is not possible. I tested this code on my own and it worked for a valid attribute of the object.Rommel
S
2

My answer is partially based on the below listed site:

Adapted from this site:

http://www.rubyquiz.com/quiz81.html

    require "ostruct"

    class Object
     def to_openstruct
       self
     end
    end

    class Array
     def to_openstruct
       map{ |el| el.to_openstruct }
     end
    end

    class Hash
     def to_openstruct
       mapped = {}
       each{ |key,value| mapped[key] = value.to_openstruct }
       OpenStruct.new(mapped)
     end
    end

Define this perhaps in an initializer and then for any hash just put to_openstruct and send that over to the rabl template and basically do what jnunn shows in the view.

Stein answered 21/9, 2012 at 0:52 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.