我很难确定使用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侧侧面加载和嵌入关联。