Ember.js 余烬数据2-以一种形式提交两个相关模型

Ember.js 余烬数据2-以一种形式提交两个相关模型,ember.js,ember-data,Ember.js,Ember Data,总余烬新手在这里。我的后端是用Rails编写的。这一部分很好,所以假设服务器端一切正常。具体情况如下: 我有两种型号 项目(包含许多项目详细信息) 项目详细信息(属于项目) 我已经确认: 我可以从我的projects/new.hbs模板创建一个新项目 我的索引路由检索所有项目以及与它们关联的项目详细信息 “我的显示路线”检索单个项目及其关联的项目详细信息 我想做的是,从我的projects/new.hbs模板提交一个项目模型和一个项目详细信息模型 我知道new.hbs中的表单应该在一个组件中,但

总余烬新手在这里。我的后端是用Rails编写的。这一部分很好,所以假设服务器端一切正常。具体情况如下:

我有两种型号 项目(包含许多项目详细信息) 项目详细信息(属于项目)

我已经确认:

  • 我可以从我的projects/new.hbs模板创建一个新项目
  • 我的索引路由检索所有项目以及与它们关联的项目详细信息
  • “我的显示路线”检索单个项目及其关联的项目详细信息
  • 我想做的是,从我的projects/new.hbs模板提交一个项目模型和一个项目详细信息模型

    我知道new.hbs中的表单应该在一个组件中,但我现在保持简单。一旦我能够创建我的关联模型,我将与表单组件做同样的工作

    项目模型

    export default DS.Model.extend({
     project_details: DS.hasMany('project_detail', { async: true }),
    
     project_name: DS.attr('string'),
     status: DS.attr('string')
    });
    
    export default DS.Model.extend({
     project: DS.belongsTo('project', { async: true }),
    
     project_id: DS.attr('number'),
     feature_name: DS.attr('string'),
     hours_billed: DS.attr('number'),
     available_hours: DS.attr('number'),
     amout: DS.attr('number')
    });
    
    项目详细信息模型

    export default DS.Model.extend({
     project_details: DS.hasMany('project_detail', { async: true }),
    
     project_name: DS.attr('string'),
     status: DS.attr('string')
    });
    
    export default DS.Model.extend({
     project: DS.belongsTo('project', { async: true }),
    
     project_id: DS.attr('number'),
     feature_name: DS.attr('string'),
     hours_billed: DS.attr('number'),
     available_hours: DS.attr('number'),
     amout: DS.attr('number')
    });
    
    项目/New.js路线

    export default Ember.Route.extend({
      model: function() {
        return Ember.RSVP.hash({
          projects: this.store.createRecord('project'),
          project_details: this.store.createRecord('project_detail')
        });
      },
     actions: {
      create: function() {
        var self = this;
        this.controller.get('model').save().then(
        function() {
          self.transitionTo('projects.index');
        });
      }
     }
    });
    
    项目/New.hbs

    <form {{ action "create" on="submit" }}>
      <label for="project_name">Project Name</label>
      {{ input value=project_name }}
      <label for="status">Status</label>
      {{ input value=status }}
      <label for="feature_name">Feature Name</label>
      {{ input value=feature_name }}
      <label for="available_hours">Available Hours</label>
      {{ input value=available_hours }}
      <label for="hours_billed">Hours Billed</label>
      {{ input value=hours_billed }}
      <label for="amount">Amount</label>
      {{ input value=amount }}
      <button type="submit">Save</button>
    </form>
    
    Router.map(function() {
      this.route('home');
      this.route('dashboard');
      this.route('login');
      this.resource('projects', function() {
        this.route('new');
        this.route('show', {path: '/:id'});
        this.route('edit', {path: '/:id/edit'});
      });
    });
    

    当我提交表单时,似乎调用了操作,但提交的所有数据都是
    NULL
    ,因此很明显,我的输入没有被识别。我已经搜索了几天,还没有看到提交多个模型的解决方案。我的代码是在一篇标准文章上扩展的结果,以及我如何处理通过RSVP散列检索关联模型的问题。任何建议都很好。谢谢

    有些东西没有正确连接

    当您从您的路线返回以下路线时:

    model: function() {
      return Ember.RSVP.hash({
        projects: this.store.createRecord('project'),
        project_details: this.store.createRecord('project_detail')
      });
    },
    
    setupController(controller, model) {
      controller.set('model', model.projects);
      controller.set('myProjectDetails', model.project_details);
    }
    
    在模板中,您可以使用
    {{model.something}
    来访问该信息,在您的例子中,您可以访问
    {{model.projects}
    {model.project\u details}

    您可能希望在
    路线中执行以下操作
    ,以便在模板中设置对模型的更轻松访问

    setupController(controller, model) {
      //this._super(controller, model) I'll explain why this is commented
      controller.set('project', model.projects);
      controller.set('project_details', model.project_details); 
    }
    
    如果执行此操作,则可以在模板中执行以下操作:

    <label>Project Name</label>
    {{input value=project.project_name}}
    {{project.project_name}}
    
    您所做的是将
    输入
    值绑定到控制器的
    项目名称
    属性。如果您使用(提示,如果您不使用它,您应该这样做。它使生活变得更加轻松),您可能可以使用您键入的值检查控制器是否具有该属性
    project\u name

    在Ember 2.0之前,有一个叫做的东西(你不再使用了),它允许将模型代理给控制器。这意味着你可以在你的路线上这样做:

    model() {
       return this.store.createRecord('project');
    }
    
    在模板中,您可以有效地:

    <label>Project Name</label>
    {{project_name}}
    
    在模板中,您现在可以执行以下操作:

    {{ input value=project_name }}
    
    <form {{ action "create" on="submit" }}>
     <label for="project_name">Project Name</label>
     {{ input value=model.project_name }}
     <label for="status">Status</label>
     {{ input value=model.status }}
     <label for="feature_name">Feature Name</label>
     {{ input value=myProjectDetails.feature_name }}
     <label for="available_hours">Available Hours</label>
     {{ input value=myProjectDetails.available_hours }}
     <label for="hours_billed">Hours Billed</label>
     {{ input value=myProjectDetails.hours_billed }}
     <label for="amount">Amount</label>
     {{ input value=amount }}
     <button type="submit">Save</button>
    </form>
    
    然后您必须将
    create
    操作更改为:

    actions: {
      create: function() {
        var self = this;
        this.controller.get('project').save().then(
        function() {
         self.transitionTo('projects.index');
        });
      }
    }
    
    另外,请注意,您的模型是用

    //Project
    project_details: DS.hasMany('project_detail', { async: true }),
    //Project Detail
    project: DS.belongsTo('project', { async: true }),
    
    但是你没有在你发布的代码中设置关系。如果您想让模型相互关联,那么在创建操作中,您需要这样的东西(或者在任何其他地方)。在下面的代码段中,我假设我的
    setupController
    示例位于路由中,因此
    项目
    作为
    项目
    在控制器中,而
    项目_细节
    作为
    项目_细节
    在控制器中

     create: function() {
     var self = this;
     var project = this.controller.get('project');
     var projectDetails = this.controller.get('project_details');
     project.get('project_details').pushObject(projectDetails);
     project_details.set('project', project);
    
     project.save().then(function() {
        self.transitionTo('projects.index');
     });
    }
    
    假设您使用的是Ember Data 2.0,那么这还存在另一个问题。保存
    项目时
    只会发出post请求来保存项目本身(不会保存新创建的
    项目详细信息
    )。目前,
    JSONAPI
    (默认情况下,标准的Ember数据2.0使用)没有一个一次性更新多个资源的解决方案()。这意味着您必须先保存
    项目详细信息
    ,然后才保存
    项目
    (查看模型可能没有意义,因为
    项目详细信息
    似乎只存在于
    项目下


    据我所知,这是目前的情况。我也在为这个问题寻找一个好的解决方案(我已经拼凑了一些解决方案,比如只允许在项目创建后创建一个项目详细信息,或者在项目中有一个额外的属性,其中包含一个序列化的项目详细信息json字符串,然后拥有它所需要的东西的后端)

    有些东西没有正确连接

    当您从您的路线返回以下路线时:

    model: function() {
      return Ember.RSVP.hash({
        projects: this.store.createRecord('project'),
        project_details: this.store.createRecord('project_detail')
      });
    },
    
    setupController(controller, model) {
      controller.set('model', model.projects);
      controller.set('myProjectDetails', model.project_details);
    }
    
    在模板中,您可以使用
    {{model.something}
    来访问该信息,在您的例子中,您可以访问
    {{model.projects}
    {model.project\u details}

    您可能希望在
    路线中执行以下操作
    ,以便在模板中设置对模型的更轻松访问

    setupController(controller, model) {
      //this._super(controller, model) I'll explain why this is commented
      controller.set('project', model.projects);
      controller.set('project_details', model.project_details); 
    }
    
    如果执行此操作,则可以在模板中执行以下操作:

    <label>Project Name</label>
    {{input value=project.project_name}}
    {{project.project_name}}
    
    您所做的是将
    输入
    值绑定到控制器的
    项目名称
    属性。如果您使用(提示,如果您不使用它,您应该这样做。它使生活变得更加轻松),您可能可以使用您键入的值检查控制器是否具有该属性
    project\u name

    在Ember 2.0之前,有一个叫做的东西(你不再使用了),它允许将模型代理给控制器。这意味着你可以在你的路线上这样做:

    model() {
       return this.store.createRecord('project');
    }
    
    在模板中,您可以有效地:

    <label>Project Name</label>
    {{project_name}}
    
    在模板中,您现在可以执行以下操作:

    {{ input value=project_name }}
    
    <form {{ action "create" on="submit" }}>
     <label for="project_name">Project Name</label>
     {{ input value=model.project_name }}
     <label for="status">Status</label>
     {{ input value=model.status }}
     <label for="feature_name">Feature Name</label>
     {{ input value=myProjectDetails.feature_name }}
     <label for="available_hours">Available Hours</label>
     {{ input value=myProjectDetails.available_hours }}
     <label for="hours_billed">Hours Billed</label>
     {{ input value=myProjectDetails.hours_billed }}
     <label for="amount">Amount</label>
     {{ input value=amount }}
     <button type="submit">Save</button>
    </form>
    
    然后您必须将
    create
    操作更改为:

    actions: {
      create: function() {
        var self = this;
        this.controller.get('project').save().then(
        function() {
         self.transitionTo('projects.index');
        });
      }
    }
    
    另外,请注意,您的模型是用

    //Project
    project_details: DS.hasMany('project_detail', { async: true }),
    //Project Detail
    project: DS.belongsTo('project', { async: true }),
    
    但是你没有在你发布的代码中设置关系。如果您想让模型相互关联,那么在创建操作中,您需要这样的东西(或者在任何其他地方)。在下面的代码片段中,我假设我的
    setupController
    示例位于路由中,因此
    项目作为
    项目位于控制器中