4

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

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

更新:发现这个问题后我更新了我的代码。我越来越近了,但 Rails ProjectsController仍然没有收到关联的 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)
4

1 回答 1

1

@David 我不是专家,但我再次查看您的问题,我认为要获取关联的 client_id,您必须调用RestAdapter 上的 toJSON 方法并传递它:

{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,因为Client是父项,而project是子项。如果您观察良好,您链接到的 issue-115明确表示 parentRecord 存储将用于创建记录。此外,如果您在最终的pull-request 中检查与issue-115合并的测试,您将再次看到它被声明为在 parentRecord 中创建子记录

但是您正在做相反的事情,即在 child record 中创建 parentRecord。你需要扭转这一点。

此外,在 Rails 方面,在 Client Model中,您调用了accept_nested_attributes_for :projects,就像 emberjs 一样,它只允许您从 Client 创建项目记录,反之亦然。所有关于如何在rails guiderailscasts和 this 在嵌套属性上使用accept_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并没有什么坏处,这是 ember-core 团队推荐的 gem,用于为 ember-data 和 RestAdapter创建rails api 。这样你就可以从 ember 端和 rails 端加载和嵌入关联。

于 2012-09-18T20:33:09.213 回答