4

Ember.js、Ember Data、およびRailsを使用して単一のフォームとhasManyの関連付けを永続化する正しい方法を決定するのに問題があります。クライアントには多くのプロジェクトがあります。プロジェクト名とクライアント名の2つのフィールドを持つ新しいプロジェクトフォームがあります。http://cl.ly/image/3z0P0R3M1t2u

作成ロジックをEmber.jsClientsControllerProjectsController内に保持しようとしましたが、その一部を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)
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-data埋め込みオブジェクト

Emberjs-埋め込みモデルまたは関連付けをクエリできません

アップデート

コードのどこでtoJSONを使用するかという質問に答える前に、コードの設計で観察したものに一歩戻りたいと思います。

プロジェクトが子であるのに対し、クライアントは親であるため、子レコード内にparentRecordを作成しようとしています。よく観察すると、リンクしたissue-115は、parentRecordストアを使用してレコードを作成することを明確に示しています。また、 issue-115に関してマージされた偶数のプルリクエストでテストを調べると、parentRecord内に子レコードを作成するとして再度示されていることがわかります。

ただし、逆のことを行っています。つまり、子レコード内にparentRecordを作成しています。あなたはそれを逆にする必要があります。

また、レール側では、 クライアントモデルaccepts_nested_attributes_for:projectsを呼び出しました。これは、emberjsと同様に、クライアントからのみプロジェクトレコードを作成でき、その逆はできません。Railsガイドのaccepts_nested_attributes_forrailscasts、およびネストされた属性でのthisの使用方法のすべての例は、親モデルのフォームから作成された子モデルのフィールドを示しています。

したがって、このユースケースでは、railsとemberjsの両方が、子レコードからparentRecordを作成します。これが、クライアントIDの問題が発生している理由である可能性があります。したがって、デザインを逆にして、もう一度試してください。それでもclient-Idが送信されない場合。次に、restAdapterのtoJsonで{associations:true}を呼び出すことをお勧めする、私が投稿した最初のリンクの最初のリンクに示されているように、親アソシエーションであるクライアントモデルでtoJSONを呼び出す必要があります。

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

これがお役に立てば幸いです。何がうまくいったか、何がうまくいかなかったかについてコメントしてください。そうすれば、同様の問題を経験している他の人が、この投稿を見つけて、どこから始めればよいかを知ることができます。

最後に、active_model_serializergemを使用してrailsapiを作成しても問題はありません。 これは、ember-dataおよびRestAdapterのrailsapi作成するためのember-coreチームが推奨するgemです。そうすれば、残り火側とレール側の両方からアソシエーションをサイドローディングして埋め込むことができます。

于 2012-09-18T20:33:09.213 に答える