4

In Ruby on Rails 4, I'm trying to make an API for my website and instead of using an array like so:

[{id: 1, name: "John"}, {id: 2, name: "Foo"}, {id: 3, name: "Bar"}]

I want to render it like this, because it makes it much easier to search through in javascript (and for other reasons):

{"1": {id: 1, name: "John"}, "2": {id: 2, name: "Foo"}, "3": {id: 3, name: "Bar"}}

This works:

# users/index.rabl

@users.each do |user|
  node(users.id.to_s) do
    partial('api/v1/users/show', object: user)
  end
end

But in the partial, I want another collection of elements (which belong to the user) and I can't get that working. Is there a more elegant way to do this?

hansottowirtz
  • 664
  • 1
  • 6
  • 16
  • Dynamic keys such as `id` is a bad choice for the API. Its hard to parse for other resources because it is dynamic. IMHO – Roman Kiselenko Aug 08 '15 at 16:04
  • @Зелёный Why do you think so? I asked it myself too, but I couldn't really think of any reason. It makes my javascript a lot easier for example. Now I can just do `users[1]` when another model has a `user_id` attribute, instead of looping through all the users. – hansottowirtz Aug 08 '15 at 16:08
  • I just say my opinions, because i already have build an api and make a choice keys with names, on a other side IOS app can't parse a dynamic key only through hardcoded names. It's just my opinion. For your case it's all about your app design. Looping through all users make you sad only if an users count more than 100_000, but here you can split it in parts. Easy way not always a good way. – Roman Kiselenko Aug 08 '15 at 16:14
  • Did you find a solution? What is that collection another collection of elements? Please share what doesn't work for you? – Anatoly Aug 19 '15 at 14:55
  • I am using Jbuilder now, which makes dynamic keys very easy: http://stackoverflow.com/questions/18154252/jbuilder-dynamic-keys-for-model-attributes – hansottowirtz Aug 19 '15 at 18:11

1 Answers1

0

To choose hash-map rather than array is definitely better option if have control on API backend codebase. From BigO notation hash lookup happens with constant O(1) time, not O(n) as for array.

Primary key lookup from the database is the most performant way to query data. Primary key is usually short and always indexed. In case of big data set use pagination.

Let's assume there is no RABL (you can always instantiate pure Ruby classes in RABL DSL code) but just an array:

array = [{id: 1, name: "John"}, {id: 2, name: "Foo"}, {id: 3, name: "Bar"}]
hash  = {}
array.each{ |elem,i| hash[elem[:id].to_s] = elem }

# {"1"=>{:id=>1, :name=>"John"}, "2"=>{:id=>2, :name=>"Foo"}, "3"=>{:id=>3, :name=>"Bar"}}

To pass the Ruby hash to Javascript on client you probably want to encode it appropriately:

# hash.to_json
# {"1":{"id":1,"name":"John"},"2":{"id":2,"name":"Foo"},"3":{"id":3,"name":"Bar"}}

From Javascript you query hash by its key:

hash = {"1":{"id":1,"name":"John"},"2":{"id":2,"name":"Foo"},"3":{"id":3,"name":"Bar"}}
hash[1]
# Object { id=1,  name="John"}
Anatoly
  • 15,298
  • 5
  • 53
  • 77