Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Renaming model association attributes in Rails JSON serialization?

I have an existing Rails 3 application, to which I am adding a JSON API. We have a Vendor ActiveRecord model, and an Employee ActiveRecord model. An Employee belongs to a Vendor. In the API, we want to include an Employee's Vendor in the JSON serialization. For example:

# Employee as JSON, including Vendor
:employee => {
    # ... employee attributes ...
    :vendor => {
        # ... vendor attributes ...
    }
}

That's easy enough. However, I have a business requirement that the public API not expose the internal model names. That is, to the outside world, it needs to seem as though the Vendor model is actually called Business:

# Employee as JSON, including Vendor as Business
:employee => {
    # ... employee attributes ...
    :business => {
        # ... vendor attributes ...
    }
}

This is easy to do for the top-level object. That is, I could call @employee.as_json(:root => :dude_who_works_here) to rename Employee to DudeWhoWorksHere in the JSON. But what about for included associations? I have tried a few things without success:

# :as in the association doesn't work
@employee.as_json(:include => {:vendor => {:as => :business}})

# :root in the association doesn't work
@employee.as_json(:include => {:vendor => {:root => :business}})

# Overriding Vendor's as_json doesn't work (at least, not in a association)
    # ... (in vendor.rb)
    def as_json(options)
        super(options.merge({:root => :business}))
    end
    # ... elsewhere
    @employee.as_json(:include => :vendor)

The only other idea I have is to manually rename the key, something like this:

# In employee.rb
def as_json(options)
    json = super(options)
    if json.key?(:vendor)
        json[:business] = json[:vendor]
        json.delete(:vendor)
    end
    return json
end

But that seems inelegant. I'm hoping there's a cleaner, more Rails-y way to do what I want. Any ideas?

like image 972
thefugal Avatar asked Dec 15 '10 22:12

thefugal


Video Answer


1 Answers

Trying to generate complex JSON with the built-in options for as_json is clumsy. I would override as_json in your models, and not bother with calling super at all. Make up your own option keys for as_json to control what you want to include in the Hash.

# employee.rb
def as_json(options = {})
  json = {:name => name, ...} # whatever info you want to expose
  json[:business] = vendor.as_json(options) if options[:include_vendor]
  json
end
like image 196
icecream Avatar answered Sep 21 '22 15:09

icecream