如何使用 Ember Data & Rails 在单个 Ember.js 表单中保持 hasMany 关联?



我很难确定使用Ember.js、Ember Data和Rails将hasMany关联与单个表单持久化的正确方法。客户有许多项目。我有一个新的项目表单,它有两个字段:项目名称和客户名称。http://cl.ly/image/3z0P0R3M1t2u

我试图将我的创建逻辑保留在Ember.jsClientsController&ProjectsController,但我是否需要将其中一些移动到我的ProjectsNewView上的提交操作?

更新:发现此问题后,我已经更新了代码。我离它越来越近了,但是RailsProjectsController仍然没有接收到相关的client_id。它不是控制器接收的参数的一部分。我仍然觉得我可能不会以最好的方式去做这件事。

型号:

轨道

class Client < ActiveRecord::Base
  attr_accessible :name
  has_many :projects
  accepts_nested_attributes_for :projects
  validates :name, :presence => true
end
class Project < ActiveRecord::Base
  attr_accessible :name, :client_id
  belongs_to :client
  validates :name, :presence => true
  validates :client, :presence => true
end

Ember.js

App.Client = DS.Model.extend
  name: DS.attr('string')
  projects: DS.hasMany('App.Project', { embedded: true })
  validate: ->
    if @get('name') is null or @get('name') is ''
      'Client requires a name.'
App.Project = DS.Model.extend
  name: DS.attr('string')
  client: DS.belongsTo('App.Client')
  validate: ->
    if @get('name') is `undefined` or @get('name') is null or @get('name') is ''
      return 'Projects require a name.'
    if @get('client') is `undefined` or @get('client') is null or @get('client') is ''
      'Projects require a client.'

控制器:

轨道

class Api::ClientsController < Api::BaseController    
  def create
    @client = Client.find_or_create_by_name(params[:client][:name])
    respond_to do |format|
      if @client.save
        format.json { render json: @client, status: :create }
      else
        format.json { render json: @client.errors, status: :unprocessable_entry }
      end
    end
  end
end
class Api::ProjectsController < Api::BaseController
  def create
    @project = Project.new(params[:project])
    respond_to  do |format|
      if @project.save
        format.json { render json: @project, status: :created, location: @project }
      else
        format.json { render json: @project.errors, status: :unprocessable_entry }
      end
    end
  end
end

Ember.js

App.ClientsController = Em.ArrayController.extend
  createClient: (data) ->
    @transaction = App.store.transaction()
    client = @transaction.createRecord(App.Client, data)
    project_data = data.projects_attributes[0]
    client.get('projects').createRecord(project_data)
    validation_errors = client.validate()
    if validation_errors
      App.displayError validation_errors
      client.destroy()
    else
      @transaction.commit()
App.ProjectsController = Em.ArrayController.extend
  createProject: (data) ->
    @transaction = App.store.transaction()
    project = @transaction.createRecord(App.Project, data)
    validation_errors = project.validate()
    if validation_errors
      App.displayError validation_errors
      project.destroy()
    else
      @transaction.commit()
      App.get('router').transitionTo('projects')

视图:

Ember.js

App.ProjectsNewView = Em.View.extend
  classNames: ['form row']
  tagName: 'form'
  templateName: 'projects/new'
  init: ->
    @_super()
  submit: (event) ->
    event.preventDefault()
    client = {}
    client.name = @get('client')
    project = {}
    project.name = @get('name')
    client.projects_attributes = []
    client.projects_attributes.push project
    App.router.clientsController.createClient(client)

@David我不是专家,但我又看了你的问题,我认为要获得相关的client_id,你必须调用RestAdapter上的JSON方法并将其传递:

{associations: true}

下面的链接解释了如何做到这一点:

https://stackoverflow.com/questions/10184213/is-there-a-way-to-post-embedded-objects-back-to-the-api-with-ember-data

Ember数据嵌入对象存储为单独的对象

Emberjs-无法查询嵌入式模型或关联

更新

在回答代码中使用toJSON的位置问题之前,我想回到我刚刚在代码设计中观察到的内容。

您正试图在子记录中创建parentRecord,因为客户端是父记录,而项目则是子记录。如果你观察得很好,你链接到的issue-115明确表示parentRecord存储将用于创建记录。此外,如果您在针对issue-115合并的evenutual pull请求中检查测试,您将再次看到它被声明为在parentRecord中创建子记录。

但您正在执行相反的操作,即在子记录中创建parentRecord。你需要扭转这种局面。

此外,在轨道侧上,在客户端模型中,您调用了accepts_nested_attributes_for:projects,这与emberjs一样,只允许您从客户端创建项目记录,反之亦然。关于如何在rails指南、railscasts和嵌套属性中使用accepts_nested_attributes_for的所有示例,都显示了从父模型中的表单创建的子模型的字段。

因此,rails和emberjs在本用例中都是从子记录创建parentRecord的。这可能就是您出现客户端id问题的原因因此,请反转您的设计并重试。如果它仍然不发送客户端Id。然后,您应该在客户端模型上调用toJSON,它是父关联,如我发布的初始链接中的第一个链接所示,该链接建议您在restAdapter中的toJSON上调用{associations:true}

 App.Client 
 ##
 toJSON: (options={}) ->
   options['associations'] = true
   @_super(options)

我希望这能有所帮助。请评论哪些有效或无效,以便其他遇到类似问题的人知道从哪里开始。

最后,使用active_model_serializer-gem创建rails-api也无妨,这是成员核心团队推荐的用于为成员数据和RestAdapter创建rails-api的gem。通过这种方式,您可以从ember侧和rails侧侧面加载和嵌入关联。

最新更新