2013-05-15 6 views
7

Wenn ich die folgenden Modelle in Rails habe, wie würde ich das in Ember/Ember-Daten darstellen?Rails-style polymorphes Modell in ember-Daten

class Attachment < ActiveRecord::Base 
    belongs_to :user 
    belongs_to :attachable, polymorphic: true 
end 

class Profile < ActiveRecord::Base 
    belongs_to :user 
    has_one :photo, class_name: 'Attachment', as: :attachable 
end 

class Post < ActiveRecord::Base 
    belongs_to :user 
    has_many :attachments, as: :attachable 
end 

Referenzen ich gefunden habe, sind the relevant ember-data pull request, the ember-data tests for polymorphic relationships und this related question aber es ist schwierig, aus ihnen ein kanonischen Beispiel zu erarbeiten.

Antwort

11

Ich verwende jetzt zwei verschiedene Arten der Arbeit mit "polymorphen" Modellen im Rails-Stil. Ich habe den folgenden Code aktualisiert, um beide Verwendungsmöglichkeiten anzuzeigen.

Attachment Modell: Dies ist "polymorph" auf der Rails-Seite, ist aber immer auf der Ember-Seite "eingebettet". Der Grund dafür ist, dass ich momentan nur Anhänge zusammen mit dem zugehörigen Modell speichern/aktualisieren muss.

Comment Modell: Dies ist sowohl auf der Rails-Seite als auch auf der Ember-Seite polymorph.

Ich habe auch Code für das Post Modell hinzugefügt, da es mehrere Anhänge und mehrere Kommentare haben kann.


Rails-Code:

class Attachment < ActiveRecord::Base 
    belongs_to :user 
    belongs_to :attachable, polymorphic: true 
end 

class Comment < ActiveRecord::Base 
    belongs_to :user 
    belongs_to :commentable, polymorphic: true 
end 

class Post < ActiveRecord::Base 
    belongs_to :user 
    has_many :attachments, as: :attachable 
    has_many :comments, as: :commentable 
end 

class ApplicationSerializer < ActiveModel::Serializer 
    embed :ids, include: true 
end 

class AttachmentSerializer < ApplicationSerializer 
    attributes :id, :url, :errors 
    has_many :comments 
end 

class CommentSerializer < ApplicationSerializer 
    attributes :id, :body, :created_at, :commentable_id, :commentable_type 
    has_one :user 
end 

class PostSerializer < ApplicationSerializer 
    attributes :id, :title, :body, :posted_at, :errors 
    has_one :user 
    has_many :attachments, embed: :objects, include: true 
    has_many :comments 
end 

class Api::V1::PostsController < Api::V1::BaseController 
    before_filter :auth_only!, only: :create 

    def create 
    # clean/capture ember-data supplied arguments 
    params[:post].delete(:user_id) 
    attachments_params = params[:post].delete(:attachments) 

    @post = current_user.posts.new(params[:post]) 
    process_attachments(attachments_params) 

    if @post.save 
     render json: @post, status: 201 
    else 
     warden.custom_failure! 
     render json: @post, status: 422 
    end 
    end 

    protected 

    def process_attachments(attachments_params) 
     return unless attachments_params.present? 

     attachments_params.each do |attachment_params| 
     # ignore ember-data's additional keys 
     attachment_params.delete(:created_at) 
     attachment_params.delete(:user_id) 

     attachment = @post.attachments.new(attachment_params) 
     attachment.user = current_user 
     end 
    end 
end 

Ember Code:

DS.RESTAdapter.configure 'App.Post', 
    alias: 'Post' 

DS.RESTAdapter.map 'App.Post', 
    attachments: { embedded: 'always' } 

App.Store = DS.Store.extend 
    adapter: DS.RESTAdapter.create 
    namespace: 'api/v1' 

App.Comment = App.Model.extend 
    user: DS.belongsTo('App.User') 
    commentable: DS.belongsTo('App.Commentable', { polymorphic: true }) 
    body:  DS.attr('string') 
    createdAt: DS.attr('date') 

App.Commentable = App.Model.extend 
    comments: DS.hasMany('App.Comment') 

App.Attachment = App.Commentable.extend 
    user: DS.belongsTo('App.User') 
    url: DS.attr('string') 

App.Post = App.Commentable.extend 
    user: DS.belongsTo('App.User') 
    attachments: DS.hasMany('App.Attachment') 

    title: DS.attr('string') 
    body: DS.attr('string') 
    postedAt: DS.attr('date') 

App.PostFormOverlayController = App.OverlayController.extend 
    # 'files' attribute is set by a widget that wraps the filepicker.io JS 
    updateAttachments: (-> 
    attachments = @get('attachments') 
    attachments.clear() 
    @get('files').forEach (file) => 
     attachment = App.Attachment.createRecord({fpFile: file}) 
     attachments.addObject(attachment) 
).observes('files') 

App.CommentNewController = App.ObjectController.extend 
    # this should be instantiated with it's model set to the commentable 
    # item. eg. `{{render 'comment/new' content}}` 

    save: -> 
    transaction = @get('store').transaction() 
    comment = transaction.createRecord App.Comment, 
     body: @get('body') 
     commentable: @get('model') 

    comment.one 'didCreate', @, -> 
     @set('body', null) 

    transaction.commit() 

Leider hat mein Rails-Code ein wenig verschmutzt mit glut-spezifischen Daten Merkwürdigkeiten geworden, da es versucht, Senden Sie alle Attribute zurück, die in den Modellen definiert sind. (Hinweis: Es gibt eine open proposal für Nur-Lese-Attribute, die das params Verschmutzung Problem lösen würden)

Wenn jemand einen besseren Weg kennt eine der oben genannten Ansatz lass es mich wissen!

NB: ich ein wenig besorgt bin, dass mit Modellen von App.Commentable verlängern wird mich hindern mehrere polymorphe Anhänge auf einem Modell, das, ich kann für einen anderen Weg suchen müssen, dass der Umgang mit.

+0

Vielen Dank für Ihre Lösung. Ich versuche, deinen Code als Leitfaden zu verwenden, um meine zu implementieren. Ich möchte klarstellen, ob dies genau die Art und Weise ist, wie Sie das Attachment-Modell in Ember-Daten definiert haben. Ich frage, weil die Links zu ember-Daten polymorphe Beispiele in Ihrer Frage das Attachment-Modell wie folgt definiert: ** App.Attachment = DS.Model.extend ({anfügbar: DS.belongsTo ('App.Attachable', {polymorph: true })}) ** und dann ** App.Attachable = DS.Model.extend ({Anhänge: DS.hasMany ('App.Attachment')}) **. Da rails ** ** attachable_type ** als Feld erwartet, wie bekommt man das mit dem aktuellen Code? – brg

+0

Gerade jetzt, ja. Ich denke, weil meine derzeitige Verwendung von "Attachments" sehr begrenzt ist, funktioniert es, ist aber nicht vollständig eingerichtet. Ich werde den Polymorphismus über das Wochenende richtig nutzen und den Code hier entsprechend aktualisieren.Ich umgehe das 'attachable_type'-Problem grundsätzlich, indem ich Anhänge immer so behandle, wie sie auf der Clientseite eingebettet sind, und die Server-Seite verwalten lassen, was sie benötigt. –

+0

Danke Kevin für die Klärung. Ich werde über das Wochenende nach dem aktualisierten Code für korrekten Polymorphismus zurückschauen. Ich wünsche ihnen einen wunderbaren Tag. – brg

3

Der Kommentar-Teil von Kevin Ansfields Antwort (hat den Post-Teil nicht benutzt) funktioniert ab Ember 1.3.0-beta/Ember Data 1.0.0-beta.4 außer dem Rails-Serializer, der nun sein sollte:

class CommentSerializer < ActiveModel::Serializer 
    attributes :id, :body, :created_at, :commentable_id, :commentable_type 
    has_one :user 

    def attributes 
    data = super 
    data[:commentable] = {id: data[:commentable_id], type: data[:commentable_type]} 
    data.delete(:commentable_type) 
    data.delete(:commentable_id) 
    data 
    end