Как сохранить ассоциацию hasMany в одной форме Ember.js с помощью Ember Data & Rails?

У меня возникли проблемы с определением правильного способа сохранения ассоциации hasMany с одной формой с использованием Ember.js, Ember Data и Rails. У клиента много проектов. У меня есть новая форма проекта с двумя полями: имя проекта и имя клиента. http://cl.ly/image/3z0P0R3M1t2u

Я попытался сохранить свою логику создания в Ember.js ClientsController и ProjectsController, но мне нужно будет переместить часть этого в действие отправки на моем ПроектыНовый вид?

Обновление: я обновил свой код, обнаружив эту проблему. . Я приближаюсь, но 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)

person David    schedule 15.09.2012    source источник
comment
Если никто не отвечает, вы можете добиться большего успеха, вставив ссылку Stackoverflow в канал IRC для emberjs и оставаясь там некоторое время после публикации ссылки. Я сделал это несколько раз, и люди ответили на ссылку Stackoverflow и решили мою проблему. Я знаю, что вы разместили его в твиттере, где я его и видел, но попробуйте канал IRC.   -  person brg    schedule 16.09.2012
comment
Я думаю, что теперь это возможно с использованием сопоставления embed_always RESTSerializer для сохранения hasMany, которое также должно работать с accepts_nested_attributes_for или без него. Ссылка на образец приложения на github, демонстрирующий его, приведена ниже. Приложение на Github Соответствующий раздел приложения, демонстрирующий сохранение ассоциации hasMany с одной формой ассоциация ActiveRecord, показывающая has_many [контроллер rails, обе модели используют один контроллер ](github.com/dgeb/ember_data_   -  person brg    schedule 28.02.2013
comment
Спасибо за обновление @brg. Я обязательно посмотрю ресурсы.   -  person David    schedule 02.03.2013


Ответы (1)


@David Дэвид, я не эксперт, но я снова рассмотрел ваш вопрос и думаю, чтобы получить связанный client_id, вам нужно будет вызвать метод toJSON в RestAdapter и передать его:

{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 store будет использоваться для создания записи. Кроме того, если вы изучите тест в обычном pull-request, который был объединен в отношении < strong>issue-115, вы увидите, что он снова указан как Создать дочернюю запись в родительской записи.

Но вы делаете обратное, то есть создаете parentRecord в дочерней записи. Вам нужно обратить это вспять.

Кроме того, на стороне rails в Модели клиента вы вызвали accepts_nested_attributes_for :projects, что, как и emberjs, позволяет вам создавать только < strong>project записи от клиента, а не наоборот. Все примеры использования accepts_nested_attributes_for в rails руководство, railscasts и это на вложенные атрибуты , показать поля для дочерней модели, созданной из форм родительской модели.

Таким образом, и rails, и emberjs в этом случае используются для создания parentRecord из дочерней записи. Возможно, поэтому у вас возникла проблема с идентификатором клиента. Поэтому измените дизайн и попробуйте еще раз. Если он по-прежнему не отправляет идентификатор клиента. Затем вы должны вызвать toJSON в клиентской модели, которая является родительской ассоциацией, как показано в первая ссылка из исходных ссылок, которые я разместил, рекомендуя вам вызывать {associations: true} для toJson в restAdapter.

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

Надеюсь, это поможет. Пожалуйста, прокомментируйте, что сработало или не сработало, чтобы другие, столкнувшиеся с подобными проблемами, которые нашли этот пост, могли знать, с чего начать.

Наконец, не помешает создать свой rails API с помощью гема active_model_serializer. , рекомендованный командой ember-core для создания rails API для ember-data и RestAdapter. Таким образом, вы можете загружать и встраивать ассоциации как со стороны Ember, так и со стороны Rails.

person brg    schedule 18.09.2012
comment
Где в моем коде вы предлагаете мне использовать метод toJSON? Извините, что мне нужно немного больше объяснений. Спасибо! - person David; 24.09.2012
comment
@David, посмотри все, что я написал в разделе update в ответ на твой комментарий. - person brg; 24.09.2012
comment
Спасибо за дополнительную информацию. На самом деле я использую гем active_model_serializer. Я также считаю, что создаю дочернюю запись из родительской, как вы описали в моем ClientsController с помощью client.get('projects').createRecord(project_data), не так ли? - person David; 25.09.2012
comment
Спасибо за ответ. Вы правы, извините, я сделал неверный вывод. Произошло следующее: когда я прочитал код и добрался до нижней части, мне показалось, что я этого не видел. В любом случае, не забудьте опубликовать здесь, как вы решили эту проблему, поскольку я считаю, что это будет очень полезно для многих людей по мере роста внедрения emberjs. Вы также можете случайным образом отправить этот вопрос по электронной почте нескольким гуру emberjs, которые также используют рельсы, они просто могут ответить вам предложениями. Вот как я решил stackoverflow.com/questions/11218108/. - person brg; 25.09.2012
comment
Ну, на самом деле я еще не заработал, так как client_id все еще не отображается в параметрах для Rails ProjectsController. Если разберусь, отпишусь как сделал. - person David; 25.09.2012
comment
@ Дэвид, могу я узнать, есть ли у тебя какое-нибудь решение? Спасибо. - person Anh Nguyen; 10.03.2013
comment
@AnhNguyen В последнее время я не пытался найти решение. Если я вернусь к этой проблеме, я обязательно опубликую свои выводы. - person David; 10.03.2013