yuяi
yuяi

Reputation: 2715

Ember.js with Rails accepts_nested_attributes_for and polymorphic has_many/belongs_to

On the Rails API side I have the following 2 models:

class Grower < ActiveRecord::Base
 has_many :addresses, as: :addressable
 accepts_nested_attributes_for :addresses
end

class Address < ActiveRecord::Base
  belongs_to :addressable, polymorphic: true
end

as well as a Growers controller which returns and can create/update Growers with embedded Addresses attributes. I also have an Addresses controller with proper routing so that Addresses can be viewed/created/updated for a specific Grower. The latter is more of an "in-case", and I'm not sure I'll be needing to return/update/create addresses as a separate payload.

I am starting to try and piece together an Ember app that would allow me to view/edit/create a Grower at the same time as its Address(es). Can anyone point me to an existing real or sample app that does this? I will be posting my code as I go along, but I already have an idea of some areas where I will be running into trouble:

  1. Rails returns/expects nested params named addresses_attributes. Ember, I am sure, doesn't use that convention. What's the best approach of resolving this?

  2. Because of the polymorphic association (objects other than Grower can be addressable), on the API/Address side, to get the correct belongs_to object, Rails uses addressable_id in conjunction with addressable_type. In this example the addressable_type would be "Grower", and the addressable_id would be the grower_id value. How would one go about translating that on the Ember side?

UPDATE:

I got it to work at least a couple different ways. My preferred solution, at least for this particular case, is in the answer section.

Upvotes: 4

Views: 1289

Answers (2)

Etienne Depaulis
Etienne Depaulis

Reputation: 120

Here is a sample of code based @yuяi's strategy that worked well for me:

App.Post = DS.Model.extend
    comments: DS.hasMany('comment')

App.PostSerializer = DS.ActiveModelSerializer.extend( DS.EmbeddedRecordsMixin,
    attrs:
        comments: {embedded: 'always'}

    keyForAttribute: (attr) ->
        if attr == "comments"
            "comments_attributes"
        else
            @_super(attr)
)

This solution worked well with Ember 1.6.1 and Ember Data 1.0.0-beta.8.2a68c63a.

Upvotes: 8

yuяi
yuяi

Reputation: 2715

I found a couple ways to get it done, but the final approach doesn't require any changes on the Rails/API side.

On the client (Ember) side:

  1. I added the addresses hasMany property to the App.Grower model. I also mapped it on the RESTAdapter to what's expected from the API, by setting the key for addresses to addresses_attributes.
  2. I added the grower (for now - will change to addressable once I have other addressable models) belongsTo property on App.Address. It's not really required for what I'm doing, but it might be useful in the future.
  3. I set the addresses on the RESTAdapter to be embedded: 'always'.
  4. On the App.GrowersEditController, I just do a model.save (transaction.commit), and the child addresses are automatically saved via the API call.
  5. On the App.GrowersAddController, I use the App.Address.createRecord and App.Grower.createRecord methods using the user-entered Grower and Address data. Then I use the pushObject method to append the Address to the Grower, and then call a save on the Grower (commit on transaction). Again, the address data gets submitted and saved automatically.

Upvotes: 6

Related Questions