如何在单个Ember.js窗体中使用Ember Data& Rails的? [英] How to persist hasMany association in a single Ember.js form using Ember Data & Rails?

查看:129
本文介绍了如何在单个Ember.js窗体中使用Ember Data& Rails的?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I'm having trouble determining the correct way to persist a hasMany association with a single form using Ember.js, Ember Data and Rails. A Client hasMany Projects. I have a new project form that has two fields: project name and client name. http://cl.ly/image/3z0P0R3M1t2u

我试图将我的创建逻辑保留在Ember.js ClientsController & ProjectsController ,但是我需要将其中一些提交到我的项目新视图上的提交操作?

I've tried to keep my create logic within the Ember.js ClientsController & ProjectsController, but will I need to move some of that to the submit action on my ProjectsNewView?

更新:在找到此问题后,我已更新我的代码。我越来越近了,但是Rails 仍然没有收到相关的client_id。它不是控制器接收的参数的一部分。它仍然觉得我可能不会这样做最好的方法。

Update: I've updated my code after finding this issue. I'm getting closer, but the Rails ProjectsController is still not receiving the associated client_id. It is not a part of the params that the controller receives. It still feels like I'm probably not going about this the best way.

模型:

Rails

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上调用JONON方法并传递它:

@David i am no expert but i was looking at your question again and i think to get the associated client_id, you will have to call toJSON method on the RestAdapter and pass it:

{associations: true}

以下链接说明如何做到这一点:

The links below explain how to do that:

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

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

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

更新

在我之前回答在JSON代码中使用哪个方面的问题,我想一步一步回到我刚刚观察到的代码设计。

Before i answer the question of where in the code to use toJSON, i want to go one step back to something i just observed with the design of your code.

你正在尝试在子记录中创建一个parentRecord,因为客户端是父级,而项目是子级。如果观察结果良好,您链接的 issue-115 ,断然说parentRecord存储将用于创建记录。此外,如果您在即时合并的拉动请求中检查测试, strong> issue-115 ,您将再次看到它,表示为在parentRecord 中创建子记录。

You are trying to create a parentRecord within child record because Client is the parent while project is the child. If you observe well, issue-115 that you linked to, categorically says that the parentRecord store would be used to create the record. Also if you examine the test in evenutual pull-request that was merged in respect to issue-115, you will see it again stated as Create a child record within the parentRecord.

但是您正在做的相反,那就是在子记录中创建parentRecord 。您需要逆转。

But you are doing the reverse, that is creating parentRecord within child record. You need to reverse that.

另外,客户端模型中的 strong> acceptable_nested_attributes_for:项目,就像emberjs只允许您从客户端创建项目记录,反之亦然。关于如何在 rails中使用 acceptable_nested_attributes_for 的所有示例指南 railstasts ,这在嵌套属性 ,显示从父模型中的表单创建的子模型的字段。

Also, on the rails side, in the Client Model, you called accepts_nested_attributes_for :projects, which just like emberjs does only allows you to create project records from Client and not vice-versa. All the examples of how to use accepts_nested_attributes_for in the rails guide, railscasts and this on nested attributes, show the fields for the child model created from the forms in the parent model.

所以在这种用例中,rails和emberjs都是从​​子记录创建parentRecord。这可能是为什么你有客户端ID问题。 所以反转您的设计,然后重试。如果仍然不发送客户端Id。那么你应该在客户端模型上调用JSON,该模型是父组合,如第一个链接建议您在restAdapter中的json上调用 {associations:true} / p>

So both rails and emberjs are in this use case to create parentRecord from child record. This could be why you having the client-id issue. So reverse your design and try it again. If it still doesn't send the client-Id. Then you should called toJSON on the Client Model which is the parent association as shown in the first link from the initial links i posted recommending you call {associations: true} on toJson in the restAdapter.

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

我希望这有帮助。请回覆一下哪些工作或不起作用,让其他遇到类似问题的人发现这篇文章可以知道从哪里开始。

I hope this helps. Kindly comment back on what worked or did not work, so that others experiencing similar issues, who find this post can know where to start from.

最后,使用 rails api 不会伤害active_model_serializersrel =nofollow noreferrer> active_model_serializer gem ,这是ember-core团队为ember数据和RestAdapter创建 rails api 的推荐宝石。这样,您可以从ember侧和rails侧面加载和嵌入关联。

Finally, it wouldn't hurt to create your rails api with active_model_serializer gem, which is ember-core team's recommended gem for creating rails api for ember-data and the RestAdapter. That way you can sideload and embed associations both from the ember side and the rails side.

这篇关于如何在单个Ember.js窗体中使用Ember Data&amp; Rails的?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆