Using Eloquent Events/Observers, is it possible to detect which properties were updated within an Update event? Or, can you gain access to the previous/new values to do a comparison?
I'm finding the only solution is to manually fire events by detecting the specific field exists in the validated request data, in the controller.
Yes, absolutely. You can use the Model class's existing methods to gain access to various sets of data. The following methods should be helpful for what you want to do.
getChanges()
Get the attributes that were changed. (and saved)
$model->getChanges()
getOriginal()
Get the model's original attribute values.
$model->getOriginal()
getDirty()
Get the attributes that have been changed since last sync. (but not saved yet)
$model->getDirty()
Related
I want to add selection field in a model which should be array of references. If I add this to model selection: types.array(types.reference(Todo)) then I have some undesirable side-effects like selection is being saved/loaded in snapshots and also changes to selection are recorded to the undo/redo history when using UndoManager middleware. If I put selection in volatile properties as just plain array then I lose reference sync capabilities(ie if one of selected elements removed from model selection will not be updated automatically).
Is there an approach which would allow to get benefits of both? Is there a way to ignore model field in patches/snapshots without moving it to volatile?
Good approach for models is to only have fields that belong to this entity and that you need in snapshots to send to server or elsewhere. Otherwise models become confusing and hard to manage.
Usually in such cases I put property like that into separate store or sub-store which bound to particular page/view for example. So this is structural issue more then anything else in my opinion.
This is just a theoretical question, I am new to PyQT. I am not able to identify classes or code examples that will show how the model updates the data (if that is done via Qt)
Right now my understanding is that the programmer is responsible for writing the methods/code for updating the data when a change is done in the model data.
Am I correct ?
Update: It seems that my question needs a drawing :-)
So it is data as in data stored in a database. By my understanding the data in this picture is the data stored in the database not the data that the model is based on which is a subset of the data in the database
Try following some of the tutorials and look at the example programs provided with PyQt or PySide.
A model is an object which stores data. This can be as simple as a list of strings. A view is an object which displays data. Qt provides some standard models for storing common types of data and some standard views for displaying common types of data. For simple cases you can use these pre-built components. These components have standard methods for adding or removing data from the model, or updating the view as the model changes. These changes are propagated from the model to the view, or from the view or control widgets to the model, using signals. Thanks to standardized naming of methods and signals this all works pretty seamlessly.
However your specific data storage or data presentation needs might be a bit different. In this case you can implement a custom model or a custom view, or if necessary both. You implement your custom model (or view) by subclassing one of the classes provided by the framework. You have to implement specific named methods on these subclasses because it's the standard naming that makes the automatic behavior with other components work, but can also add your own custom methods and such as you see fit.
Further to MiniMe's comment:
Lets look at an example. Qt Models have a xx.setData() method to update a data item, which takes parameters specifying where in the model the data goes (index) and the new data. When you implement that method, you perform the work of updating the data to whatever underlying storage mechanism you use (e.g. a list or dictionary) and emit the xx.dataChanged() signal. If any views are linked to this model, they will have subscribed to this signal and so will update themselves automatically.
def setData(self, index, value):
# Update the data in the underlying python list self.my_list
# The index object is of a data type provided by Qt. To perform
# this operation we have to extract the row number where the change
# is to be made, then use that to update the appropriate entry in
# the list.
self.my_list[index.row()] = value
# Create a PyQt modelIndex object based on the row number that was
# updated. The self.index() method is provided by Qt.
modelIndex = self.index(index.row())
# Send the modelIndex of the change to any connected views so they
# know to update themselves
self.dataChanged.emit(modelIndex)
# In reality we'd do some validation checks and return False if there
# was a problem and the data change didn't happen.
return True
Similar methods would need to be implemented for adding a new data item in the list or removing a data item from the list. These methods would make the change, send a signal indicating which part of the model had changed to any attached views, then return. I hope this is more helpful.
For testing reasons, I want to check that one of my methods doesn't update a specific entry in my database. Is there a simple way to ask an instance of an ActiveRecord model if its in sync with the database? for instance, if we had a method foobar? that could do this:
old_post = Post.find(1)
updated_post = Post.find(1)
updated_post.update_attributes(name: "this is a new name not like the old name")
old_post.foobar? #should return true, as its attributes are no longer up to date
updated_post.foobar? #should return false, as its attributes match the database directly
So is there a method that acts like foobar, or something like it? Thanks in advance.
I think your problem lies beyond finding a method which tells you wether an attribute has been updated, but in the relationship among the different objects that are instantiated. First it is important to understand, that old_post and updated_post are unrelated ruby objects. They know about how to save their own state to the database, but they do not know about each other.
Therefore your first requirement for foobar? cannot be fulfilled, as old_post will think it is up-to-date as long as no attribute has been updated. In contrast the changed? method will roughly answer in the way you are trying to achieve for updated_post. However it does so because it thinks nothing has happened since it was last saved, this will not be verified against the database upon each call of changed? as this would be wasting a database call in 99.9% of all cases.
This means it is all too easy to generate anomalies between the objects you created as there is no direct connection between the two (except the implicit connection that they once represented the same database row). If you change an attribute in one object (using e.g. title='?' it will change the value of the object and take note of the change in the changed-array. Once you save this object it will save its changed attributes to the database (by creating an individually constructed update-statement).
Another object that is already instantiated (as old_post in your example) will not know about this change and might change other attributes if you are not careful (or even the same ones if they have been changed again). Depending on your database adapter you may try to use the lock! method which will synchronize your object with the database before allowing any modifications. This however will not happen automatically as in most controller methods updates do not conflict nearly often enough to merit the synchronization as it will be idempotent in most cases.
This does not go without saying that rails can not save you from thinking about your transaction semantics if you want to guarantee specific ACID semantics for your controller methods.
I'm really confused by this... still.
I asked a similar question to this a while before, but i'll ask it even simpler now.
I see this in a lot of samples and tutorials. How could you put [Bind(Exclude="ID")] on an entire Model, and expect to do Edits on the model? If you get pack all the properties of a model on a POST but not the ID, then how do you know which ID to edit?
Even if i'm using ViewModels... i'm probably creating them without IDs. So in that case... also... how do I know which ID was updated on an Edit?
Yes, i understand that there is a "security" element to this. People can hijack the ID... so we need to keep people from updating the value during a POST. But... what is the correct way to handle edits then? What's common practice?
I feel like i'm missing something VERY trivial.
In MVC requests are processed by the model binder when the client makes a request. If you include models on your controllers then, as far as I'm aware, you actually have to specify the model you wish to bind to by prefixing your arguments with the model name (unless you only have one argument which is the model)
SomeModel_ID
Now, in some cases you might want to exclude certain properties from being bound to because they pose a security risk, which you seem to be happy with as a concept. We will exclude ID on the model, preventing any client request from posting this value in plain text.
Now why might we exclude an entire model? Well not all controller arguments are pre-processed by a model binder. RedirectToAction for example does not pass through the model binder, so it is conceivable in this instance for you to create a new model in a POST controller action, and redirect to a GET controller action, passing along a sanitised model. That model cannot be populated by the client, but we are free to populate it ourselves on the server side.
The only time I bind to a model is when I have a view model and an associated editor for that model. This makes it really easy to inject a common editor into a page and to encapsulate those properties. If you have to exclude certain properties from being bound to I would argue that you are doing it wrong.
Update
Following your comments I think I can see why you might be confused. The model bind excluder prevents the client from ever setting a model property. If you need this property to do your updating then you simply can't exclude it. What this does mean then is that the user could potentially post back any ID. In this case you should check that the user has permission to be modifying any objects or database records associated with this ID before serving the requested update. Validating the arguments is a manual process. You can use data annotations for validating inputs, but this isn't likely to help very much with access permissions. It's something you should be checking for manually at some stage.
You know the ID because it's passed to you through the page address. So:
http://yoursite.com/admin/users/edit/20
Will populate your ID parameter with 20. If it's used in a POST (ie, the information is filled in), just manually fill in the ID field and pass it to the database controller in whatever manner you have devised.
This is also immune to (trivial) hijacks because if they were to write some other ID besides 20, they wouldn't be updating the user with ID 20 now would they? :)
I have a model and two views set up like this:
Model ---> OSortFilterProxyModel ---> OListView
Model ------------------------------> OTableView
When the user selects something in one of the views, I want the other view to mirror that selection. So I thought I'd use a QSelectionModel to link them together. But this does not work. I have a feeling it is because the views think they have two different models, when in fact they have the same model. Is there a way to get this to work?
What is probably happening is that the views do have two different models. One is your original model, the other is the sort filter model.
I'm not sure if this would work, and it depends on what Qt considers "activated", but you could connect a function to each of the view's activated slots. These will pass you a model index. You'll have to send the model index through the proxy model in the appropriate direction (mapFromSource and mapToSource). Then, call the setCurrentIndex on the other view.
The documentation for the activated signal states that what is considered "activated" varies by platform. There might be other signals you could latch onto, such as the selection model's selection changed signal. You might have to do a different call to change the selection as seen by the user. And finally, it might be possible or even easier to do in a derived QSelectionModel, as long as you remember about mapping to/from the source model.
Not quite sure how your model subclass is implemented - but the selection depends on persistent model indexes being correct. Can you provide some source code? Are you using the same selection model on both?
You propably need to use void QItemSelectionModel::select combined with QAbstractProxyModel::mapSelectionFromSource and QAbstractProxyModel::mapSelectionToSource. In QListView's selectionChange signal handler you should have
tableView->selection()->select(
proxyModel->mapSelectionToSource(selected),
QItemSelectionModel::ClearAndSelect);
and analogically with mapSelectionFromSource in QTableView's signalChange signal handler.
Note that i am not sure if Qt will prevent infinite recursion when table will change selection of list which in turn will change selection of table and so on...