I have some nested Ember Data models week->hasMany('workout')->hasMany('exercises')
In my app I need to create an entire new week. I accomplish this by
var newWeek = WT.PlanWeek.store.createRecord('planWeek', attributes );
// create a couple new workouts
newWorkout = WT.PlanWorkout.store.createRecord('planWorkout', attributes);
newWeek.get('workouts').pushObject(newWorkout);
// repeat...
// create exercises on the workouts the same way and push them on the the workout
newExercise = WT.PlanWeek.store.createRecord('planExercise', attributes);
newWorkout.get('exercises').pushObject(newExercise);
newWorkout.save();
I have a couple problems with this save.
I save the both the workout and the child exercises in the workout API call - when the call returns this appends a second set of exercises to the workout instead of replacing the existing exercises (even though I set workout.exercises to the newly persisted exercises in the serializer extractSingle).
When the server returns it doesn't update the workouts in the week with the new ids. I end up with the new persisted workouts that correctly belongTo the week, but week.get('workouts') still points to the unpersisted workouts with no id.
Any ideas or suggestions?
Related
When a user updates an invoice form, i want to create a new invoice record with the updated attributes, but also change one or two fields of the old record and save it, too.
How would the outline of a controller action look like which could accomplish this?
Instead of a controller action i put the code in the model, using callbacks:
before_save do |rec|
if !rec.new_record?
attrb = rec.attributes.delete_if{|k, v| ["id"].include? k }
Book.create(attrb)
rec.restore_attributes
rec.year = rec.year + 2 # some custom change
true
end
end
I keep all attributes unless the 'id' (otherwise i get an error) for create a new record with the new attributes.
Then i restore the attributes of the existing record. I do some custom change before saving.
I am rather new with Rails but this seems pretty straightforward. As you mention the user is 'updating" an invoice, your controller view has probably been passed all the data available to the user for further change.
When submitting the form, your update action can easily update the current record data, as well as creating a new one on top of this
Though as it is automated, you need to make clear:
if a new invoice record is created each time an invoice record is
updated (thi can create a lot of copies of the same invoice)
how you make the old record an archive to avoid duplicates
can the 'additional" amendments be automated and easily processed through an algorithm...
Nested attributes made things a bit tricky. So in order to create new instances I had to use the dup method for both the resource and its nested items.
Generally, it is advisable to keep the controllers slim and make the models fat. Nevertheless, I have decided to include this code into my Invoices controller:
def revise_save
#contact = Contact.find(params[:contact_id])
#invoice = #contact.invoices.find(params[:invoice_id])
#invoice_old = #invoice.dup
#invoice.invoice_items.each do |item|
#invoice_old.invoice_items << item.dup
end
#invoice.datum = DateTime.now.to_date
# archive old invoice
# #invoice_old. ...
#invoice_old.save
# make old new invoice
#invoice.datum = Time.now
# ...
#invoice.update(invoice_params)
redirect_to invoices_path
end
Note that in this solution the currently edited (original) invoice becomes the new invoice, the old one is paradoxically created anew.
Thanks to #iwan-b for pointing me in the right direction.
I'm wonder why my template doesn't get updated after createRecord when using findQuery to fetch data.
When changing this return this.store.findQuery('timetracking', {year: year, month: month, user_id: user_id}); to return this.store.find('timetracking'); the template gets updated with my new records.
I don't want to fetch all records to save bandwith, but when using only find/findQuery with query params, my newly created records doesn't show up in my template.
Do I have to do a "force" reload? And how to do this?
Update
The Ember inspector shows the new records.
findQuery puts the job of filtering on the server's back. Ember Data assumes that the results that were returned are the only results that are associated with that collection. find with no query or id (findAll) will always return all records found in the store, because it realizes you weren't looking for any filtered set, if you create a new record it gladly knows to include it in all of the available records. You can manually push a record into a collection of records using pushObject.
// assuming you're in the context of your `findQuery` results, and they are the model
var model = this.get('model'),
record = this.store.createRecord('timetracking', {...});
model.pushObject(record);
Learning emberjs
I am not sure if this is a stackoverflow question or git issue. So I decided to put it on stackoverflow first.
Here is my Jsbin (Open in firefox ..not in chrome as raw.github file is used)
When I click on "<- All Department" in department template which I reached after creating a new department it does navigate back to departments template
but the #each does not display the newly added department name in list.
It does show the newly added department on refreshing the browser on /departments
UPDATE
It seems that the .set() method is working but for some reason the new object created is returning the name and ID as undefined. Might be a bug with ember-model perhaps.
The best solution for the moment would be to have 2 save methods, one on the edit controller as you currently do and then adding a different save method for creating a new department.
App.NewController = Ember.ObjectController.extend({
save:function(){
var newDep = App.Department.create({name: this.get('name')});
newDep.save();
this.get('target').transitionTo('department', this.get('model'));
}
});
Here is a jsbin with the New controller added - http://jsbin.com/EVUlOyo/1/edit
End Update
It looks like when you are creating the record it is not setting the name value correctly on the object.
I changed the following -
newDepartment = self.get('model');
newDepartment.set('name',this.get('name'));
newDepartment.save();
to -
var newDep = App.Department.create({name: this.get('name')});
newDep.save();
Here is an updated jsbin also http://jsbin.com/EkEXInO/1/edit
Hope that helps and works for you.
I am working in a Symfony 1.4 project with Propel 1.4.2.
I have 2 related tables. workshop and trainers which is a many to many relation mapped by a join table (workshop_trainers) which contains the workshop_id and the trainer_id).
In my Workshop Form I have a select box for adding the trainers to the workshop. The problem is when the workshop is new (Create) I get an error:
Cannot add or update a child row: a foreign key constraint fails
This happens because, when saving the workshop_trainers relation the workshop_id field is null. Isn´t Propel intelligent enough to know that there is a relation between the tables and save the base object first? What I am doing wrong?
My trainer list widget.
$this->widgetSchema['workshop_trainer_list'] = new sfWidgetFormChoice(array(
'choices' => $trainers,
'multiple' => true,
));
Thanks for your help.
This is not fixing the problem but that's the easiest practical solution to this problem:
In the form, simply deactivate the workshop_trainer_list field if the object is a new one (doesn't have an ID yet).
Something like:
if ($this->getObject()->isNew())
{
$this->offsetUnset('workshop_trainer_list'); // not sure of that method name
}
A better solution is to update the doSave method to have the ID first, something like this:
protected function doSave($con = null)
{
$isNew = $this->getObject()->isNew();
if (null === $con)
{
$con = $this->getConnection();
}
// retrieve the value of workshop_trainer_list here and remove it from the form
$trainers = ...
$this->offsetUnset('workshop_trainer_list');
// save without it
parent::doSave($con);
// add it back
$this->getObject()->set...
// save
$this->getObject()->save($con);
}
Im playing a little bit with heavy-client app.
Imagine I have this model:
class Category(models.Model):
name = models.CharField(max_length=30)
color = models.CharField(max_length=9)
Im using knockoutjs (but I guess this is not important). I have a list (observableArray) with categories and I want to create a new category.
I create a new object and I push it to the list. So far so good.
What about saving it on my db? Because I'm using tastypie I can make a POST to '/api/v1/category/' and voilà, the new category is on the DB.
Ok, but... I haven't refresh the page, so... if I want to update the new category, how I do it?
I mean, when I retrieve the categories, I can save the ID so I can make a put to '/api/v1/category/id' and save the changes, but... when I create a new category, the DB assign a id to it, but my javascript doesn't know that id yet.
in other words, the workflow is something like:
make a get > push the existing objects (with their ids) on a list > create a new category > push it on the list > save the existing category (the category doesnt have the id on the javacript) > edit the category > How I save the changes?
So, my question is, what's the common path? I thought about sending the category and retrieving the id somehow and assign it to my object on js to be able to modify it later. The problem is that making a POST to the server doesn't return anything.
In the past I did something like that, send the object via post, save it, retrieve it and send it back, on the success method retrieve the id and assign it to the js object.
Thanks!
Tastypie comes with an always_return_data option for Resources.
When always_return_data=True for your Resource, the API always returns the full object event on POST/PUT, so that when you create a new object you can get the created ID on the same request.
You can then just read the response from your AJAX and decode the JSON (i dont know about knockout yet).
see the doc : http://readthedocs.org/docs/django-tastypie/en/latest/resources.html?highlight=always_return_data#always-return-data
Hope this helps