How to not lose hasMany changes on Ember query? - ember.js

In my application, I search for documents with query.
Then I edit one attribute in a single document, and then I call search query again.
Result is OK, I see document still in a dirty state with changed attribute.
Then I again pick one of documents and edit its hasMany relation (from 2 items to 4 items). And then I call search query again.
Result is NOT OK, hasMany relation change is lost/disposed/rollbacked.
Is there a way so Ember query (i guess it's some Ember internal reload) does not rollback not saved relation changes ?
I am using Ember 2.9.1
For now i have no other way than prohibit any filter query actions or route actions anything that could call query again, since that would cause lost data that user set.

Ember's store.query method always refetches the models from the backend (unlike the find* methods). With a query, it's the only way to make sure you have the most up-to-date data (and that the models loaded into the store are still valid). Even in your instance, you may run into unexpected results if you change the data such that it no longer meets your query criteria.
If you would like to keep edits around between queries, I would recommend making a copy of all models which are dirty (check the hasDirtyAttributes attribute). You can gather them with peekAll. Once copied, you can then make the query and patch the records by ID. Perhaps by using Ember.assign.
Even using that method, I would still think that you will get into trouble tracking the changes and making sure the records stay consistent with your query. Like what do you if that record wasn't returned (deleted on the server or no longer meets your criteria)? Do you drop your edits? What if you have a conflict between the data from the server and your local version (e.g. another user patched the hasMany relationship that the other user is now querying and modifying)?
ember-changeset seems like it could be useful here. However, it's not obvious how to get a ChangeSet to apply to a new instance of the same model. Though it may be possible to keep a snapshot and match them up manually. However, you still run into data consistency issues.

Related

Ember: Edit model object without setting isdirty

This topic har been discussed on stackoverflow before, but not with latest version of ember data, I think. At least none of the suggestions I have found have worked for me.
I use the latest version of Ember and Ember data (versjon 2.13.0). I use the JsonApiAdapter.
Scenario
After I load a record from the server I want to do a few changes to some of its properties. These changes shall not make the record dirty, and the changed attributes shall not show up in the record.changedAttributes(). Any changes the user may do after that shall make the record dirty.
Searching for a solution
I have tried to manually change the isDirty flag, but it didn't do it. I have also tried to find the place in the ember data code that sets the state after a record has been loaded (because essentially I am trying to do the same thing) but I haven't found where it is.
I have also tried record.send('pushedData'), but I didn't change anything of the state of the record.
Any help appreciated.
I know 3 methods which allow to modify server's response without dirtying records:
You can override adapter's handleResponse method and make modifications right in payload.
You can override serializer's normalize method.
You can load records from server with Ember.$.ajax method, modify response and then pass it to store's pushPayload method.
First two methods are good if you need to modify record after every load from server (no matter from what route/controller you do it). Both adapter and serializer can be model-specific. If you need to do it in only one place (controller or route), or if you need an access to route's/controller's variables - 3rd method is good.
I'm not aware about any way to mark record as dirty/not dirty. If you modify a record after it was stored, it becomes dirty.

How to implement memcached with Django & APIs while underlying Database objects may change

I am using Django's native Authorization/Authentication model to manage logins for my WebApp. This creates instances of the User model.
I would like to write a simple class-based-APIView that can tell me if a specific email is already used (IE: Is there already a user with the given email in my database?). The first time this API is called, it should get the matching User object from the DB. But subsequent times it is called, it should return it from the Memcache (if and only if, the underlying row in the database is unchanged). How can I do that??
Should I inherit from generic.APIView? Why or why not? What would the view look like? In particular I want to understand how to properly do the memcaching and cache-coherency checking. Furthermore, how would this memcaching scheme work if I had another API that modified the User object?
Thanks. I was unable to find detailed idiot-proof manual on using memcaching properly in Django.
Caching is perhaps the simplest part of django - so I'll leave that discussion to the last. The bigger problem is figuring out when your model changed.
You can decide what constitutes an update. For example, you might consider that only when a particular field is updated, then the cache is updated. Your cache update process should be limited to the writing/updating code or view. If you go about this method, then I would recommend django-model-utils and its StatusField - you can add this logic in save() method by overriding it; or implement it at the code that is updating models.
You can also do a simpler approach, that is, no matter what is updated - as long as save() is called, expire the cache and repopulate it.
The rest of the code is very simple.
Attempt to fetch the item from the cache, if the item doesn't exist (called a cache miss), then you populate the cache by fetching from the database. Otherwise, you'll get the item from the cache and then you save yourself a database hit.
The cache interface is very simple, you set('somekey', 'somevalue') you can optionally tell it when to expire the item. Then you try to get('somekey'), if this returns None, then its a cache miss (perhaps the item expired), and you have to fetch it and populate the cache. Otherwise, you'll get the cached object.

Ember-Model: How to establish a hasMany or belongsTo relationship by using a "foreign key"?

Summary
I have a bit of a problem using Ember-Model, trying to establish a unique relationship between two models.
Based on current responses that I have received here on S.O., Ember Forums, and #emberjs. I am beginning to believe that there is no built-in solution for this problem, and I am reformatting my question to specify what is needed.
Details
I am populating a template currently with a full set of debtor information. All the information comes from multiple calls to the server.
The first bit is the basic Debtor info. This part is easy because I can use the model hook and a dynamic segment to retrieve it.
My server returns a JSON for a Debtor... Here's the short version:
{
"debtor" = {
"debtor_id": 1003,
"debtor_name": Steve,
//... more JSON
"debtor_contact_id": 1345
}
}
The dynamic segment for Debtor is filled with the value of the debtor_id, but also notice this debtor has a debtor_contact_id. Every Debtor record retrieved from the server has a unique debtor_contact_id. On the database, this value is a "foreign key" that will tell which contact table belongs to which debtor table.
There is no way to predict which contact info relates to which debtor without this key/value pair.
I currently have "Contacts" belongsTo "Debtor", but that is not enough to do the job.
When it is time to fill the "Contacts" model. Ember-Model needs to know to build the value from debtor_contact_id into the ajax URL as a query parameter in order to GET the correct API.
I am still learning all of this stuff and so far I have not been able to fully follow any tutorials because my use case has an extra step needed somewhere.
This is the expected behavior I am hoping to see:
Model hook will work as expected to pull the specific debtor and put it into a "debtor" model (this part is currently working just fine)
Somehow "debtor_contact_id" is read from the payload
that value is added as part of a server query to find a separate API
the resulting contact info will be pulled into a "contact" model
hopefully a hasMany/belongsTo relationship can be established after both corresponding models are returned.
all this needs to be done in one promise before entering my template
You will also find the question at: discuss.emberjs.com if that is more appropriate place to discuss.
I can elaborate more if this does not make sense... thanks!
Assuming you are using ember-data, alongside the attributes of your model you need to add:
debtor_contact: DS.belongsTo('name_of_the_other_model')
This then provides you a promise which will resolve to the other model on demand. It won't resolve straight away, but bound variables in templates will update as it is resolved. The other API call will be made for you if things are set up properly.
http://emberjs.com/api/data/classes/DS.html#method_belongsTo
The answer I gave here might also be helpful if you need to force resolving the relationship for some reason: Ember Unbound & Belongsto

What can you do with Ember Data Models when in the error state?

I'm struggling to understand the workflow that would be used in the following scenario:
A user creates a model, let's call it Product. We present them with a form to fill in. The save errors for some reason other than validations (timeout, access denied etc...) In Ember, this puts the model into an error state. From a UI perspective, all I want to do is put a message on the screen (easy) and allow the user to try again (apparently not so easy).
I've seen it written many times not to reuse a transaction. I understand the logic of that. In the case of a new Product, I simple create another new Product, merge in the data from the original product (attributes, relationships) and replace the content of my controller with the new Product. This wasn't hard and appears to work nicely, although there may be (hopefully) a better way.
However, when I'm editing a Product, I have run into a serious issue and the above solution does not work. The Product model is now in the error state and I can not find any way to get a copy of this Product that isn't also in the same state.
What I cant' figure out is what I can do with this model once it hits the error state. I have tried the following:
Rollback: This doesn't work. You can't rollback a transaction in the error state.
Reload: Same as above. Not allowed to reload a record in the error state.
Grab a new copy of the record: So I try App.Product.find(id) with the same id as the existing record. It just gives me a copy of the existing record, in the error state.
I'm hoping I'm missing something fairly basic here. Is it possible to roll a record nicely out of an error state (or invalid state for that matter)?
If there is a simple way to change the state of these models, should we still be creating a new transaction for further attempts to commit?
So after a few days of reading source and experimenting, I have come to the conclusion that this is functionality that is not yet implemented. To move a record into another state you are supposed to send an event to it which passes it on the statemanager. There appears to be no events registered on the error state that allows us to recover the record.
There is an ugly workaround - I can call transitionTo on the statemanager of the record and force it into the state we want. I did not decide to do this lightly, but at this point I must continue on with the project while I wait for ember-data to evolve. So if the record is so far unsaved, we can rescue it from an invalid or error state by calling:
model.get('stateManager').transitionTo('loaded.created.uncommitted')
or for an existing record:
model.get('stateManager').transitionTo('loaded.updated')
Once this has been called, you can attempt to call commit again on the transaction that the model resides in. This will be the default transaction as the behaviour of ember-data is to move a model into the default transaction once commit has been called on it's original transaction. You can always retrieve the current transaction for a model by calling model.get('transaction')
So at the end of this, I have a way to create the typical CRUD scenario that we might see in Ruby on Rails, but I don't believe this is the ideal way to do it. I do believe however that at this point in time, neither does the ember-data team.
For those of you interested in having CRUD functionality as controller and route mixins for Ember, I have a Gist that contains the code I cam currently using. This is working fine, recovers from save errors as well as validation errors. Hopefully I can continue to refine this as ember-data evolves.
With the addition of DS.Errors in 1.0.0-beta5 (see https://github.com/emberjs/data/commit/994f3b234ef899b79138ddece60d8b214c5449e3) you should be able to call...
record.get("errors").clear();
This will clear out the previous errors and triggers becameValid.
You can trigger a becameValid event on it:
record.send("becameValid");
This should transition the model to uncommitted state.
You could try creating a parallel representation of the model as an Ember.Object that is not persisted but has the same properties as your persisted model. If your ajax bounces back in an error state you can use the error callback provided by the ajax method to do something.
In this case, the "something" might be to delete the record, and then clone the properties from your dummy object into a new record and re-save the record. On a success callback simply destroy your temp object and if all records are clean then clear your temp objects (to prevent lingering temp objects).
This could also be insane... but it strikes me as an option.

How can I easily mark records as deleted in Django models instead of actually deleting them?

Instead of deleting records in my Django application, I want to just mark them as "deleted" and have them hidden from my active queries. My main reason to do this is to give the user an undelete option in case they accidentally delete a record (these records may also be needed for certain backend audit tracking.)
There are a lot of foreign key relationships, so when I mark a record as deleted I'd have to "Cascade" this delete flag to those records as well. What tools, existing projects, or methods should I use to do this?
Warning: this is an old answer and it seems that the documentation is recommending not to do that now: https://docs.djangoproject.com/en/dev/topics/db/managers/#don-t-filter-away-any-results-in-this-type-of-manager-subclass
Django offers out of the box the exact mechanism you are looking for.
You can change the manager that is used for access through related objects. If you new custom manager filters the object on a boolean field, the object flagged inactive won't show up in your requests.
See here for more details :
http://docs.djangoproject.com/en/dev/topics/db/managers/#using-managers-for-related-object-access
Nice question, I've been wondering how to efficiently do this myself.
I am not sure if this will do the trick, but django-reversion seems to do what you want, although you probably want to examine to see how it achieves this goal, as there are some inefficient ways to do it.
Another thought would be to have the dreaded boolean flag on your Models and then creating a custom manager that automatically adds the filter in, although this wouldn't work for searches across different Models. Yet another solution suggested here is to have duplicate models of everything, which seems like overkill, but may work for you. The comments there also discuss different options.
I will add that for the most part I don't consider any of these solutions worth the hassle; I usually just suck it up and filter my searches on the boolean flag. It avoids many issues that can come up if you try to get too clever. It is a pain and not very DRY, of course. A reasonable solution would be a mixture of the Custom manager while being aware of its limitations if you try searching a related model through it.
I think using a boolean 'is_active' flag is fine - you don't need to cascade the flag to related entries at the db level, you just need to keep referring to the status of the parent. This is what happens with contrib.auth's User model, remember - marking a user as not is_active doesn't prompt django to go through related models and magically try to deactivate records, rather you just keep checking the is_active attribute of the user corresponding to the related item.
For instance if each user has many bookmarks, and you don't want an inactive user's bookmarks to be visible, just ensure that bookmark.user.is_active is true. There's unlikely to be a need for an is_active flag on the bookmark itself.
Here's a quick blog tutorial from Greg Allard from a couple of years ago, but I implemented it using Django 1.3 and it was great. I added methods to my objects named soft_delete, undelete, and hard_delete, which set self.deleted=True, self.deleted=False, and returned self.delete(), respectively.
A Django Model Manager for Soft Deleting Records and How to Customize the Django Admin
There are several packages which provide this functionality: https://www.djangopackages.com/grids/g/deletion/
I'm developing one https://github.com/meteozond/django-permanent/
It replaces default Manager and QuerySet delete methods to bring in logical deletion.
It completely shadows default Django delete methods with one exception - marks models which are inherited from PermanentModel instead of deletion, even if their deletion caused by relation.