0
votes

I have a rails backend for which I'm trying to make an Ember.js admin panel. Basically there are categories that can be parents to other categories and categories can have many "stickers" but "stickers" can also have many categories. Please consider the backend structure immutable in this(I can fiddle with the serializer, but that's it). Here are my serializers:

Category Model:

class Category < ActiveRecord::Base
  has_many :parent_cats, class_name: "CatToCat",foreign_key: "child_id"
  has_many :children_cats, class_name: "CatToCat",foreign_key: "parent_id"

  has_many :parents, through: :parent_cats
  has_many :children, through: :children_cats
end

Category to Category Model:

class CatToCat < ActiveRecord::Base
  belongs_to :parent, class_name: "Category"
  belongs_to :child, class_name: "Category"
end

Sticker:

class StickerSerializer < ActiveModel::Serializer
  embed :ids, include: true
  attributes :id, :text, :audio, :created_at, :image, :smallImage, :updated_at, :stickerServerID
    has_many :categories
end

Category:

class CategorySerializer < ActiveModel::Serializer
  embed :ids, include: true
  attributes :id, :name, :catImage, :created_at, :catOrder, :catServerID, :updated_at
  has_many :stickers
  has_many :children
  has_many :parents
end

Here are the Ember Models:

Sticker:

App.Sticker = DS.Model.extend({
    audio: DS.attr("string"),
    image: DS.attr("string"),
    smallImage: DS.attr("string"),
    stickerServerID: DS.attr("string"),
    text: DS.attr("string"),
    updated_at: DS.attr("date"),
    created_at: DS.attr("date"),

    categories: DS.hasMany("category")
});

Category:

App.Category = DS.Model.extend({
    name: DS.attr("string"),
    catImage: DS.attr("string"),
    catOrder: DS.attr("string"),
    catServerID: DS.attr("string"),
    updated_at: DS.attr("date"),
    created_at: DS.attr("date"),

    stickers: DS.hasMany("sticker"),

    children: DS.hasMany("category",{inverse:'parents'}),
    parents: DS.hasMany("category",{inverse:'children'})
});

Store:

App.ApplicationSerializer = DS.ActiveModelSerializer.extend({
  keyForAttribute: function(attr){
    console.log("keyForAttribute:"+attr+"->"+this._super(attr));
  if (attr == "smallImage" || attr == "stickerServerID" || attr == "catOrder" || attr == "catImage" || attr == "catServerID"){
    console.log("try:"+attr);
    return attr;
  }else{
    return this._super(attr);
  }
});

App.ApplicationStore = DS.Store.extend({
  adapter: '-active-model'
});

The error that Chrome reports:

Error while loading route: Error: No model was found for 'child'

The error that Firefox reports is useless :-/

Happy to add any other info that is helpful! Thanks in advance!

1
Having this same problem setting up ancestry in ember: stackoverflow.com/questions/24474369/… I've gotten various advice, but not sure what is supposed to be best practices and haven't gotten it working properly. - BJ McDuck
Please let me know if you do find something that works^^; - Matthew Clark
The closest I've found to work is stackoverflow.com/questions/13727512/self-join-with-ember-data but my use of it only gives me correct data on page load, when I link to anything else it doesn't reload the data. I could use reload(), but this seems sucky. - BJ McDuck
Having the same issue, I guess the problem lies in Rails because it is rendering the children in a separate array in the JSON output, Which should just be rendered in the same array as it parents; the categories array. - Tim Baas
oh and then make the connect to the parents/children on the ember side? - Matthew Clark

1 Answers

1
votes

There is a way to do this, but it's not perfect.

  • Add child_ids to the attributes in your serializer.
  • Set children to a DS.hasMany in your model in Ember.

Rails:

# app/serializers/category_serializer.rb    
class CategorySerializer < ActiveModel::Serializer
  embed :ids, :include => true
  attributes :id, :name, :child_ids
end

Ember (EmberCLI):

// app/models/category.js
import DS from 'ember-data';

export default DS.Model.extend({
  children: DS.hasMany('category'),
  name: DS.attr('string'),
});

The problem is the serializer doesn't load the children automatically, so you need to always load all categories at once.