Rendering a simple Ruby hash with RABL

10.2k Views Asked by At

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?

7

There are 7 best solutions below

1
On BEST ANSWER

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"
  }
}
2
On

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"
      }
   }
}
1
On

Sometimes its easy to do too much imho.

How about just

render json: my_hash

And just like magic we can delete some code !

0
On

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.

1
On

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

0
On

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

0
On

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.