0

I'm kinda new to the whole rails/ruby thing. I've built a restful API for an invoicing app. Summary of models is below.

class Invoice < ActiveRecord::Base
    has_many :pages
end

class Page < ActiveRecord::Base
    belogs_to :invoice
    has_many :rows
end

class Row < ActiveRecord::Base
    belogs_to :page
end

I would like to be able to include related models in one rest call. I can currently do one level of nesting. For example i can get an Invoice with all its pages /invoices?with=pages is the call i would make. In controller i would create a hash array from this as per below(probably not the best code you've seen):

def with_params_hash
  if(params[:with])
    withs = params[:with].split(',')
        withs.map! do |with|
        with.parameterize.underscore.to_sym
    end
    withs
  else
    nil
  end
end

This will return a hash as array e.g [:pages]

In the controller i use it as

@response = @invoice.to_json(:include => with_params_hash)

This works fine. I would like to be able to include nested models of say page.

As you know this can be done this way:

@invoice.to_json(:include => [:page => {:rows}])

The first question i guess is how do i represent this in the URL? I was thinking: /invoices?with=pages>rows. Assuming thats how I decide to do it. How do i then convert with=pages>rows into [:pages => {:rows}]

3
  • After a quick scan of your problem (apologies if I miss vital info) The RESTful route for all rows would be: invoices/3/pages/5/rows - resource/id/resource/id/resource for lists and resource/id/resource/id for individual resources. Or just resource/id of course, depending on the problem. Also, see here: asciicasts.com/episodes/230-inherited-resources for something which may or may not help, but should give an idea of a Rails-ey way of handling nested resources. Commented Aug 28, 2014 at 12:41
  • @AFaderDarkly thanks for the reply. I've already got routes like invoices/3/pages, invoices/3/pages/5/rows and so forth. The reason i wanted to do this is so i can reduce overhead and minimise api calls. Cause if an invoice had 5 pages with 10 rows each. I'd have to make 5 More calls plus another 5 to get rows. I'd like to get everything at one go. Hope that helps. Commented Aug 28, 2014 at 13:32
  • Apologies, I see your problem. Why not default to serving a deep object (with relevant associations) as a sensible default use case, then allow a 'shallow' option to get just the parent object? Or do you require the ability to be specific about the included associations? Commented Aug 28, 2014 at 17:29

2 Answers 2

2

Why don't you use jbuilder? Will be easiest and you will can nest all models you want.

https://github.com/rails/jbuilder

Sign up to request clarification or add additional context in comments.

2 Comments

Hi @david was trying to avoid using views. But that's an excellent answer. I'd hate to have to rewrite/modify my controllers.
You know the fact that i'm lazy to change my code doesnt make this the wrong answer. So I changed to using Jbuilder. Worked okay. But in the end i prefered RABL github.com/nesquena/rabl
0

So i ended up going with the format below for url:

/invoices?with=pages>rows

The function below will generate the function required:

def with_params_hash
    final_arr = []
    with_array = params[:with].split(',')
    with_array.each do |withstring|
        if withstring.include? ">"
            parent = withstring[0..(withstring.index('>')-1)].parameterize.underscore.to_sym
            sub = withstring[(withstring.index('>')+1)..withstring.length].parameterize.underscore.to_sym
            final_arr << {parent => {:include => sub}}
        else
            final_arr << withstring.parameterize.underscore.to_sym
        end
    end
    final_arr
end

Usage in the controller looks like:

@invoice.all.to_json(:include => with_params)

Alternatively as per @DavidGuerra's idea https://github.com/rails/jbuilder is not a bad option.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.