Note that there are some explanatory texts on larger screens.

plurals
  1. POHow to persist hasMany association in a single Ember.js form using Ember Data & Rails?
    text
    copied!<p>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. <a href="http://cl.ly/image/3z0P0R3M1t2u" rel="nofollow">http://cl.ly/image/3z0P0R3M1t2u</a></p> <p>I've tried to keep my create logic within the Ember.js <em>ClientsController</em> &amp; <em>ProjectsController</em>, but will I need to move some of that to the submit action on my <em>ProjectsNewView</em>?</p> <p><strong>Update:</strong> I've updated my code after finding this <a href="https://github.com/emberjs/data/pull/115" rel="nofollow">issue</a>. I'm getting closer, but the Rails <em>ProjectsController</em> 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.</p> <p><strong>Models:</strong></p> <p><em>Rails</em></p> <pre><code>class Client &lt; ActiveRecord::Base attr_accessible :name has_many :projects accepts_nested_attributes_for :projects validates :name, :presence =&gt; true end class Project &lt; ActiveRecord::Base attr_accessible :name, :client_id belongs_to :client validates :name, :presence =&gt; true validates :client, :presence =&gt; true end </code></pre> <p><em>Ember.js</em></p> <pre><code>App.Client = DS.Model.extend name: DS.attr('string') projects: DS.hasMany('App.Project', { embedded: true }) validate: -&gt; 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: -&gt; 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.' </code></pre> <p><strong>Controllers:</strong></p> <p><em>Rails</em></p> <pre><code>class Api::ClientsController &lt; 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 &lt; 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 </code></pre> <p><em>Ember.js</em></p> <pre><code>App.ClientsController = Em.ArrayController.extend createClient: (data) -&gt; @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) -&gt; @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') </code></pre> <p><strong>Views:</strong></p> <p><em>Ember.js</em></p> <pre><code>App.ProjectsNewView = Em.View.extend classNames: ['form row'] tagName: 'form' templateName: 'projects/new' init: -&gt; @_super() submit: (event) -&gt; 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) </code></pre>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload