JSON for Rails delegated attributes?
In one of my Rails apps, I have the following architecture (as part of a current refactoring):
- Contact (a lot of attributes common to all people)
- Prospect (specific attributes to just prospects, delegates other attributes to contact
- Lead (specific attributes to leads, delegates common attributes to contact
Both Prospect and Lead do the following (below). I've gone back and forth in testing on STI and / or MTI inheritance using acts_as gem, but this is actually the cleanest way for me for now (because leads and prospects are both contacts, but not mutually exclusive).
delegate :first_name, :last_name, :address_1, :address_2, :address_3, :zip, :city, :state, :email_address, :phone_number, :client_id, :unsubscribed, :original_list_id, :to => :contact
My code that isn't refactored yet renders prospect objects instances to json to use attributes in various client side needs. Using JSON the delegated attributes don't show up. I know you can explicitly declare methods in render :json declarations (and I do so elsewhere, on calculated columns), but this is clumsy for a lot of attributes in potentially multiple controllers. Using includes would require parsing them as separate object attributes (instead of these attributes appearing to be coming from Prospect or Lead).
I've looked into ActiveModel Serializer and it seems like it fits my needs, but I can't find a way to make it work with delegated attributes. Any ideas or suggestions would be appreciated...
Also, maybe another thought would be to override to_json for my Prospect and Lead models. Maybe I'll look there next (b/c ActiveModel Serializer could be overkill for this need).
I'm a big fan of just using jbuilder for this kind of stuff. It makes it rather easy to render out absolutely anything you want and is pretty much just like using the xml builder if you're familiar with that. No need to override
to_json or anything. I believe it's intended to do pretty much the same thing as ActiveModel::Serializer, but jbuilder makes it feel more like a view that you're creating. You'll have full access to any instance variables set in the view and should be able to do what you want.
You'll just do this in your controller:
respond_to do |format| format.html format.json end
And then create the view file as
Chris, thanks. That worked great. Here's how I implemented this (which seems like it's working great).
@prospect.attributes.each do |attr_name, attr_value| json.set! attr_name, attr_value end @prospect.contact.attributes.each do |attr_name, attr_value| json.set! attr_name, attr_value unless attr_name == "id" end