Detect whether new Ember Data records have been changed by the user - ember.js

When a new record is created using Ember Data, then get("isDirty") returns true. But as yet, the user has made no changes to the record, and we can discard it without losing any of the user's work.
Is there any official, supported way to detect this situation, where a record has been created but no properties have been set?
(There's in incomplete answer to this question for a much older version of Ember Data, before it was substantially overhauled. The didSetProperty function still exists in current releases, but it's undocumented. Still, it might be a possible path to a solution if nothing official can be found.)

Internally, the changed properties are tracked by the _attributes property. You could do a check of
record.get('isNew') && Ember.keys(record._attributes).length === 0
to see that it has just been created and nothing has been changed on it.
Note that this is not meant to be part of the external API, but I'm not aware of any external API to accomplish this.

Related

Non-backwards compatible state upgrade in Corda using SignatureConstraint

I want to perform a non-backwards compatible state upgrade using SignatureConstraint. If it were a backwards compatible change, for example adding a property, I'd just added a nullable property in the state and that would work. However I don't have any idea how should I act in the following scenarios:
Scenario1: A new non-null field is added to the state
Scenario2: A field was removed from state
Scenario3: A field was modified in the state. E.g. a field of type Date transformed into an object which contains that date and some other fields.
Scenario4: A field in the state was renamed.
The problem is that explicit upgrade does not support SignatureConstraint and I get the following error message Legacy contract does not satisfy the upgraded contract's constraint, so I need to find a solution for implicity upgrade.
ContractUpgradeFlow doesn't support the upgrade of state with SignatureConstraint. However, the flexibility of Signature Constraint allows you to add any CorDapps as long as it's signed by the same key. You could easily write a simple flow to mimic an ExplicitUpgrade for the scenario you mentioned.
Here is what you could do:
Add both the corDapps jar files (old and updated) in the nodes cordapps folder.
Write another cordapp with a flow that consumes your existing state and outputs the new state (the upgraded one).
Add this flow jar to the nodes cordapps folder.
Execute the new flow to consume the older states and output the upgraded state.
Points to Note:
Make sure to have the correct set of signers to avoid incorrect spending of the states.
This is just an overall idea. The actual way of doing this might get a little complicated depending on the contract rules for your Exit transaction of the state.
I would rather add a new upgrade command to cater to this scenario.
You could have got the overall idea and do the tweaking at your end to perform the upgrade of your usecase. Hope this helps!
As a workaround I made the incompatible change to become a compatible one. Here is how it works.
I've created a state which has propertiesV1 object. This object includes all the fields that CompanyState should.
#CordaSerializable
#BelongsToContract(CompanyContract::class)
data class CompanyState(
override val linearId: UniqueIdentifier,
val propertiesV1: CompanyV1?
) : LinearState
Now when I need to make an incompatible change in the properties, I just add another version of the object to the state.
#CordaSerializable
#BelongsToContract(CompanyContract::class)
data class CompanyState(
override val linearId: UniqueIdentifier,
val propertiesV1: CompanyV1?,
val propertiesV2: CompanyV2?
) : LinearState
Neither contract, nor flows are changed. They are just being updated to handle propertiesV2 field.

Sharing data across Sitecore pipelines

I´m trying to perform some actions in the pipeline "httpRequestBegin" only when necessary.
My processor is executed after Sitecore resolves the user (processor type="Sitecore.Pipelines.HttpRequest.UserResolver, Sitecore.Kernel" ), as i´m resolving the user too if Sitecore is not able to resolve it first.
Later, i want to add some rendering in the pipeline "insertRenderings", only if actions in the previous pipeline were executed (If i resolved the user, show a message), so i´m trying to save some "flag" in the first step, to check in the second.
My question is, where can I store that flag? I´m trying to find some kind of "per request" cache...
So far, I've tried:
The session: Wrong, it's too early, session doesn't exists yet.
Items (HttpContext.Current.Items): It doesn't work either, my item is not there on the seconds step.
So far i'm using the application cache (HttpContext.Current.Cache) with some unique key, but I don´t like this solution.
Anybody body knows a better approach to share this "flag"?
You could add a flag to the request header and then check it's existence in the latter pipelines, e.g.
// in HttpRequest pipeline
HttpContext.Current.Request.Headers.Add("CustomUserResolve", "true");
// in InsertRenderings pipeline
var customUserResolve = HttpContext.Current.Request.Headers["CustomUserResolve"];
if (Sitecore.MainUtil.GetBool(customUserResolve, false))
{
// custom logic goes here
}
This feels a little dirty, I think adding to Request.QueryString or Request.Params would been nicer but those are readonly. However, if you only need this for a one time deal (i.e. only the first time it is resolved) then it will work since in the next request the Headers are back to default without your custom header added.
HttpContext.Current.Cache or HttpRuntime.Cache could be the fastest solution here. Though this approach would not preserve data when the AppPool gets recycled.
If you add only a few keys to the cache and then maintain them, this solution might work for you. If each request puts an entry into the cache, it may eventually overflow the memory used by worker process in a long run.
As alternative to this you may try to use Sitecore.Context.ClientData property. It uses ClientDataStore that employs a database (look for clientDataStore section in the web.config file) to store data. These entries can survive the AppPool recycle.
Though if you use them a lot, it may become a bottleneck under the load when you need to write to and/or read from the entries.
If you do know that there could be a lot of entries created for sharing purposes, I'd create a scheduled task to clean up the data store from obsolete entries.
I know this is a very old question, but I just want post solution I worked around
Below will hold data per http request basis.
HttpContext.Current.Items["ModuleInfo"] = "Custom Module Info"
we can store data to httpcontext in one sitecore pipeline and retrieve in another...
https://www.codeproject.com/Articles/146455/When-Can-We-Use-HttpContext-Current-Items-to-Store

How to manually set an object state to clean (saved) using ember-data

Explanation:
I'm using ember-data for a project of mine and I have a question that revolves around the possibility of dirtying an object and then setting its state to clean again on purpose - without commiting the changes. The scenario is this:
Say I've fetched an object via banana = App.Fruit.find('banana'); and it has a description of "Yellow fruit!". Using XHR long-polling (or WebSockets), I may receive an updated version of the object because of another user having changed the description to "A tasty yellow fruit!" at any given point in time after I fetched the original object.
Then, what I would like to do is to update the object to reflect the newly received data. For this, I've tried different approaches:
I've tried calling App.Store.load(App.Fruit, new_data);. First of all, this approach doesn't work and secondly, this is not really what I want. I could've made uncommitted changes to the object myself and in this case, it would be undesirable to just discard those (assuming the load() call would overwrite them).
I've tried looping through the new data, calling .set() - like so: banana.set('description', new_data.description); - in order to update the object properties with the new data (where applicable = not dirty). This works but it leaves the object in a dirtied state.
In order to make the object clean/updated again - and not have the adapter commit the changes! - I've taken a look at the states the object travels through. These are (at least):
Step 1: Initially, the object is in the rootState.loaded.saved state.
Step 2: Calling .set() on a property pushes it to the rootState.loaded.updated.uncommitted state.
Step 3: Calling App.store.commit(); returns the object to the rootState.loaded.saved state.
Therefore, I've tried to manually set the object state to saved after step 2 like so: banana.get('stateManager').goToState('saved');.
However, this doesn't work. The next time the store commits for any other reason, this maneuver produces an inFlightDirtyReasons is undefined error.
Question:
My question is: how can I manually change the state of a dirtied object back to clean (saved) again?
Solution for Ember Data 1.0.0-beta.7:
// changing to loaded.updated.inFlight, which has "didCommit"
record.send('willCommit');
// clear array of changed (dirty) model attributes
record.set('_attributes', {});
// changing to loaded.saved (hooks didCommit event in "inFlight" state)
record.send('didCommit');
I've searched the source code of Ember-data and I've found that loaded.saved state has a setup function that checks whether a model is clean, before setting "saved" state. If it is not clean, then it rejects a request to change state and returns to loaded.updated.uncommitted.
So you have to clean model._attributes array, which keeps attributes names and Ember will let you change state manually.
I know it isn't very good solution, because is needed to set private property of a model, but I've not found any other solutions yet.
Looking at ember-data the uncommitted state has a 'becameClean' event which consequently sets the record as loaded.saved.
This should do the trick
record.get('stateManager').send('becameClean');
Solution for Ember Data 2.6.1
record.send('pushedData');
set dirty record as loaded and saved
https://github.com/emberjs/data/blob/fec260a38c3f7227ffe17a3af09973ce2718acca/addon/-private/system/model/states.js#L250
It's an update to #Kamil-j's solution.
For Ember Data 2.0 which I am currently using I have to do the following:
record._internalModel.send('willCommit');
record._internalModel._attributes = {};
record._internalModel.send('didCommit');
As of 1.0.0.rc6.2....
This will move a model into the state of a model that has been saved.
record.get('stateManager').transitionTo('loaded.saved')
This will moves a model to a the state of a new model that has not been committed. Think new dirty model.
record.get('stateManager').transitionTo('loaded.created.uncommitted')
This will move a model into the sate of an old model that has been updated, think old dirty model:
record.get('stateManager').transitionTo('loaded.updated')
As of ember-data 1.0.0-beta.12:
record.transitionTo('loaded.saved');
It seems that record.get('stateManager') is not required anymore.
Here's what seems to work for Ember Data 1.0.0-beta.10:
record.set('currentState.stateName', 'root.loaded.saved');
record.adapterWillCommit();
record.adapterDidCommit();
record.set('currentState.isDirty', false);
Not sure if all those lines are required but just following what others have done prior to this.
Ember 2.9.1
record.set('currentState.isDirty', false);
Tested on Ember Data 2.9
pushedData action is the way to go but besides that the "originalValues" need to be reset as well.
Ember.assign(record.data, record._internalModel._attributes);
Ember.assign(record._internalModel._data, record._internalModel._attributes);
record.send('pushedData');
It looks like with newer versions everything methioned here got broken.
This worked for me with ember-data 1.0.0.beta4:
record.adapterWillCommit();
record.adapterDidCommit();
Another method that worked for me when using Ember Data 1.0.0-beta.18:
record.rollback()
This reversed the dirty attributes and returned the record to a clean state.
Seems like this may have been since deprecated in favor of record.rollbackAttributes: http://emberjs.com/api/data/classes/DS.Model.html#method_rollbackAttributes
I work on Ember data 1.13 so I used the following solution (which seems a mix between the one provided by #Martin Malinda and the other by #Serge):
// Ensure you have the changes inside the record
Object.assign(record.data, record._internalModel._attributes);
Object.assign(record._internalModel._data,record._internalModel._attributes);
// Using the DS.State you can first simulate the record is going to be saved
record.get('_internalModel').send('willCommit');
// Cleaning the prevous dirty attributes
record.get('_internalModel')._attributes = {};
// Mark the record as saved (root.loaded.created.uncommitted) even if it isn't for real
record.get('_internalModel').send('didCommit');
In this way, if we will call a further rollbackAttributes() on this record, if we will have some dirty attributes, the record will be reset to this last state (instead of having the original properties) which was exactly what I was looking for in my use case.
If we won't have any dirty attributes, nothing will change and we will keep the last attributes set using this code without having them rolled back to the original ones. Hope it helps.
Tested on Ember Data 3.8.0
Just an update to Martin Malinda's answer:
// Clear changed attributes list
record._internalModel._recordData._attributes = {};
// Trigger transition to 'loaded.saved' state
record.send('pushedData');
In my case I also needed to override serializer's normalize method.

Ember.js: OK to avoid this.get('attr')?

My Ember.js model, view, and controller classes are getting a bit verbose. Part of this comes from writing this.get('attr') instead of this.attr.
Is it OK to always just write this.attr, as long as the attribute is declared directly, not via a binding?
(I understand that setting is a different issue -- you always have to call this.set('attr', value) in order to update dependent attributes and templates.)
IIRC, you can do this for private properties that you know will not be observable.
The convention is to prefix your private properties with an underscore (eg _myProperty) which tells Ember not to bind it.
See the docs for .get(), or check the source code if you're so inclined.
If the property is being observed or bound, you DON'T want to do 'this.attr'. The get command is the nexus through which observers and bindings are triggered.
The previous answers to that question are outdated by recent version of Ember. Since 3.1, which was released in April 2018, native ES5 getters could be used for computed properties also. In Ember 3.1 this.get('attr') is the object uses unknownProperty, is an Ember Data PromiseProxyObject or if using with a path and some elements of it may not be an object. Please refer to release notes for details. You will get a helpful assertion in that cases.

Repository Pattern

I've got a quick question regarding the use of repositories. But the best way to ask is to show a bit of pseudocode and you guys tell me what the result should be
Get a record from the repository with ID of 1 (assume it exists)
Edit a couple of properties
Query the repository again for an item with ID of 1
Result = ??
Should I get the object with updated values or the object without (original state), bearing in mind that since updating the values of properties (step 2) I have not told the repository to update this record.
I think I should get a copy of the original item and not a reference to the edited version.
Please tell me what is correct.
Cheers
The repository pattern is suppose to act like a collection of your objects, so ideally I think it should return the same object instance which would have the updates in it.
Generally there is an identity map somewhere so your repositories can keep track of what has already been loaded. With an identity map, when you fetch an object with the same Id you should always get the already loaded object back regardless of how many times. This is how all more sophisticated ORMs work and is generally a good practice. An identity map helps keep things in sync while you are in the same transaction and saves you some data access.
NHibernate's session has an identity map it keeps track of so you don't have to worry about trying to implement your own in your repositories. Also I believe you can use NHibernate's stateless session if you want to load another instance without change tracking, but I'm not positive on that.
Judging from your past questions I'm assuming you are using LINQ/C#?
If you are using a DataContext and you haven't called SubmitChanges() then you should get back the original unchanged object.
Just tested it. I was wrong, you get back the changed object.
If you set ObjectTrackingEnabled = false on the DataContext you will get the unchanged object.