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

Generating JSOS suitable for use by jQuery DataTables #405

Closed
davesag opened this issue Feb 13, 2013 · 6 comments
Closed

Generating JSOS suitable for use by jQuery DataTables #405

davesag opened this issue Feb 13, 2013 · 6 comments

Comments

@davesag
Copy link

davesag commented Feb 13, 2013

I am making extensive use of jQuery Datatables and they require JSON feeds in a specific format which Rabl can't provide. The issue is I need to return un-named arrays which I can't work out how to get Rable to do.

I have resorted to coding up a helper in my Sinatra app to generate the appropriate JSON but would prefer to have this logic in a Rabl file if possible. Maybe I'm just missing something.

My working method is:

def recipe_datatable_json(recipes, echo, table_name)
  result = {
    'sEcho' => echo,
    'iTotalRecords' => recipes.count,
    'iTotalDisplayRecords' => recipes.count
  }
  aaData = []
  recipes.each do |r|
    aaData << {
      'DT_RowId' => "#{table_name}-id-#{r.id}",
      '0' => UnicodeUtils::titlecase(r.name),
      '1' => UnicodeUtils::titlecase(t.people(r.serves)),
      '2' => summarise(r.description),
      '3' => human_readable_time(r.preparation_time),
      '4' => human_readable_time(r.cooking_time),
      '5' => r.serves,
      '6' => r.preparation_time,
      '7' => r.cooking_time
    }
  end
  result['aaData'] = aaData
  return result.to_json
end

How would I get the same result in Rabl?

I tried this:

node do
  {
    'sEcho' => @echo,
    'iTotalRecords' => @recipes.count,
    'iTotalDisplayRecords' => @recipes.count
  }
end
node :aaData do
  @recipes.each do |r|
    {
      'DT_RowId' => "#{@table_name}-id-#{r.id}",
      '0' => UnicodeUtils::titlecase(r.name),
      '1' => UnicodeUtils::titlecase(t.people(r.serves)),
      '2' => summarise(r.description),
      '3' => human_readable_time(r.preparation_time),
      '4' => human_readable_time(r.cooking_time),
      '5' => r.serves,
      '6' => r.preparation_time,
      '7' => r.cooking_time
    }
  end
end

but that wraps the array of recipes in a 'recipes' object and also seems to include all the other recipe attributes (not shown), even though I don't require them.

I'd love to move all my JSON rendering into Rabl but this example has me stumped.

@nesquena
Copy link
Owner

try adding:

object false

# ...
node do
  {
    'sEcho' => @echo,
    'iTotalRecords' => @recipes.count,
    'iTotalDisplayRecords' => @recipes.count
  }
end

to the top of the template

@davesag
Copy link
Author

davesag commented Feb 13, 2013

Adding object false didn't seem to make any difference.

I get this from my Rabl

{"sEcho":1,"iTotalRecords":10,"iTotalDisplayRecords":10,"aaData":[{"recipe":{"cooking_time":15000,"description":"test","id":1,"meal_id":null,"method":"test","name":"test","owner_id":1,"preparation_time":8400,"requirements":"test","serves":6}},{"recipe":{"cooking_time":4260,"description":"Delicious fish soup. Yumo!","id":2,"meal_id":null,"method":"Mix the stuff up and cook it.","name":"Fish Soup","owner_id":1,"preparation_time":2700,"requirements":"Pot","serves":6}},{"recipe":{"cooking_time":900,"description":"Scrape and eat it all up. Yummy!","id":3,"meal_id":null,"method":"Cook and eat. Yum!","name":"Roadkill Salad","owner_id":1,"preparation_time":176760,"requirements":"A roa, and the willingness to use it.","serves":8}},{"recipe":{"cooking_time":900,"description":"A delicious salad made of fish.","id":4,"meal_id":null,"method":"Fry the fish and sprinkle with lettuce.  Serve hot.","name":"Fish Salad","owner_id":1,"preparation_time":1800,"requirements":"","serves":2}},{"recipe":{"cooking_time":900,"description":"A fish in the shape of a biscuit","id":5,"meal_id":null,"method":"Cook fish in oil, then cover in flour and cut into biscuits.","name":"Fish Biscuit","owner_id":1,"preparation_time":0,"requirements":"None","serves":1}},{"recipe":{"cooking_time":5100,"description":"A very yummy stew.","id":6,"meal_id":null,"method":"Add veggies to the water and boil it dry.","name":"Yummalishous Stew","owner_id":1,"preparation_time":2700,"requirements":"A big pot.","serves":11}},{"recipe":{"cooking_time":7200,"description":"meal for one","id":7,"meal_id":null,"method":"just cook it.","name":"testing again","owner_id":1,"preparation_time":900,"requirements":"time and space","serves":1}},{"recipe":{"cooking_time":129600,"description":"prep = 10m","id":8,"meal_id":null,"method":"Yum!","name":"test 3","owner_id":1,"preparation_time":600,"requirements":"testing","serves":2}},{"recipe":{"cooking_time":5400,"description":"test 4 d","id":9,"meal_id":null,"method":"test m","name":"test 4","owner_id":1,"preparation_time":1500,"requirements":"blah","serves":4}},{"recipe":{"cooking_time":900,"description":"A classic.","id":10,"meal_id":null,"method":"First up, lightly toast the bread and pan fry the bacon until it is cooked but not crisp.  Remove half of the bacon and continue to fry the other half until it is crisp.\nIn the meantime, slice the lettuce and tomatoes without bruising it then layer the lettuce and tomatoes onto the bread.  Salt the tomatoes lightly.\nAdd the soft bacon.  You might also want to apply a thin smear of mayo here too. Grind on some pepper and layer on the crispy bacon. \nClose the sandwich with the other piece of bread and slice into triangles.\n","name":"Bacon lettuce and tomato sandwich","owner_id":1,"preparation_time":300,"requirements":"It's best to use lettuce and tomatoes from your own garden if you can, and use a good heavy bread.\nSlice the tomato as thinly as you can.\n","serves":6}}]}

but this is the JSON I need to get (and that I do get from my Ruby method.)

{"sEcho":1,"iTotalRecords":10,"iTotalDisplayRecords":10,"aaData":[{"DT_RowId":"test-id-1","0":"Test","1":"6 People","2":"test","3":"2 hours 20 minutes","4":"4 hours 10 minutes","5":6,"6":8400,"7":15000},{"DT_RowId":"test-id-2","0":"Fish Soup","1":"6 People","2":"Delicious fish soup.","3":"45 minutes","4":"1 hour 11 minutes","5":6,"6":2700,"7":4260},{"DT_RowId":"test-id-3","0":"Roadkill Salad","1":"8 People","2":"Scrape and eat it all up.","3":"2 days 1 hour 6 minutes","4":"15 minutes","5":8,"6":176760,"7":900},{"DT_RowId":"test-id-4","0":"Fish Salad","1":"2 People","2":"A delicious salad made of fish.","3":"30 minutes","4":"15 minutes","5":2,"6":1800,"7":900},{"DT_RowId":"test-id-5","0":"Fish Biscuit","1":"One Person","2":"A fish in the shape of a biscuit","3":"none","4":"15 minutes","5":1,"6":0,"7":900},{"DT_RowId":"test-id-6","0":"Yummalishous Stew","1":"11 People","2":"A very yummy stew.","3":"45 minutes","4":"1 hour 25 minutes","5":11,"6":2700,"7":5100},{"DT_RowId":"test-id-7","0":"Testing Again","1":"One Person","2":"meal for one","3":"15 minutes","4":"2 hours ","5":1,"6":900,"7":7200},{"DT_RowId":"test-id-8","0":"Test 3","1":"2 People","2":"prep = 10m","3":"10 minutes","4":"1 day 12 hours ","5":2,"6":600,"7":129600},{"DT_RowId":"test-id-9","0":"Test 4","1":"4 People","2":"test 4 d","3":"25 minutes","4":"1 hour 30 minutes","5":4,"6":1500,"7":5400},{"DT_RowId":"test-id-10","0":"Bacon Lettuce And Tomato Sandwich","1":"6 People","2":"A classic.","3":"5 minutes","4":"15 minutes","5":6,"6":300,"7":900}]}

As you can see, the Rabl version includes all sorts of extra info from the Recipe object, and the 'aaData' array is an array of named 'recipe' objects, not an array of anonymous objects.

@nesquena
Copy link
Owner

Ahh i see it now:

@recipes.each do |r|

needs to be

@recipes.map do |r|

in node :aaData do. .each returns the entire recipe object.

@davesag
Copy link
Author

davesag commented Feb 13, 2013

Kick ass, that worked! Thanks.
So in summary if I use @recipes.map do |r| instead of @recipes.each do |r| the node will only take the info I give it rather than trying to be clever.

@davesag davesag closed this as completed Feb 13, 2013
@davesag
Copy link
Author

davesag commented Feb 13, 2013

FYI the presence of object false makes no difference to the output in this instance.

@nesquena
Copy link
Owner

Yeah exactly, use map along with node.

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

2 participants