How to restrict one user to update the record while its being used by another using MVC, EF? - mysql

I've an application using MVC5 & EF6. I want to restrict one user to modify the particular record when it's being used by another user. I'm trying by all ways like concurrency in EF but, still looking for the better way. I want to 'Lock' table records for users. So one user can not change another users record. Anybody tried?

EF implements an optimistic concurrency model. In other words, it assumes there will be no conflict and then returns an exception if there is. That usually works pretty well for programmatic updates, but is pretty lacking in the user experience department.
For example, assume two users are editing the same object simultaneously. User 1 saves first, followed by User 2. User 1 wins, of course, and they go on about their day, but now User 2 is in a predicament. It is on them, now to resolve this conflict. They can either discard their work, and start over based on the update made by User 1, or overwrite User 1's work, discarding that user's changes. If User 1's work is overwritten, there's no notification that that has occurred.
Pessimistic concurrency is far better in this scenario. The record is "locked" while User 1 edits. User 2 must wait for User 1 to finish. Only then can they edit the record. As a result, there are never conflicts that need to be resolved and no risk of one user's work being lost.
Implementing this type of concurrency is pretty straight-forward. You just need some place to record that a particular object is being edited by a particular user at a particular time. This could be on the record itself or some sort of access log. Regardless of where you put that information, you then retrieve it when a user wants to edit a record. If there's no current user editing or the lock has expired, you open the record and log the current user and time. If there is an existing user and the lock is still active, then you deny access or simply make the record read-only, so the user can view it but not edit.

Related

Safely Drop User Table in Ruby on Rails Application

I'm running a Ruby on Rails application. In this system, Users can login and logout as necessary. I used gem devise as well. I've realized now that I have a lot of Users in my system, but most of them are no longer users. I can delete them from the system, but I want to start afresh.
My question is, is it safe to drop the Users table, User.delete_all? Then insert myself using seed.rb as admin user. Then add all Users (new and old) from the system (Add New User feature I have on the system).
What I believe you're looking for is the delete_all-action, if you have no callbacks etc in the User-model. Dropping the table, is not what you'll want, as you would have to rebuild and recreate the table. By deleting the rows in it, you're simply removing the content.
Depending on your use of Users, you could argue, that it's safe/unsafe to delete content. If the users are persisted, and you're storing password etc, you should not empty it.
If, on the other hand, a User is in fact a "session", or similar, you should be safe to empty it, as that would simply "log out" your users.
Another consideration is, if you need to cleanup the users, maybe add a field last_logged_in or similar. Leave it for a while (And of course update it, when a user logs in), and then delete anyone that hasn't logged in for, say 1 month; User.where("last_logged_in < ?", 1.month.ago).delete_all.
I cannot recommend, just deleting content, without testing first, and ensuring that Users data are stored, or 'easily recoverable', by a new login. Or atleast that they're actually able to login without being baffled. Also, ensure that any relations from User, is handled, or you'll end up with orphaned records in other tables.

Dynamically Customizable Group-Based Authorization in Rails

Currently, in my app there are just 3 roles visitors can have:
admin that has all privileges
user that can can perform several actions about him/her-self within the system
guest that can just watch and send bug reports
Everything is primitively implemented, as follows: in a DB each user has a field where his being admin (stands for 2 in the field) or user (1) is indicated, and in the application_controller.rb it is just checked if logged_in? && current_user.DB_FIELD == 2 (or > 0), and in the necessary controller there occurs a before_filter check, etc.
However, such a simple implementation worked great till recently when we decided to extend the functionality of the system, that is, partly, to allow admin to join users into groups, but there are some moments. For better understanging of what I am going to ask, let me describe the situation from the way I see it (maybe you can suggest something much better and logical):
I am an admin. I open /groups, and see a list of groups.
What is a group? A group, on the one hand, is a set of permissions, and on the other hand, is a combination of users that should have the same permissions within my app.
What is a permission? A permission is one action that each user of the group it assigned to can perform.
I want to unite new users in one group, but this group doesn't exist. So I click the button (which stands for /groups/new), and the Create Group window pops up. There, I have a textfield for a group name, a bulk of checkboxes, each stands for a permission, a field for adding users, and a Save button. I write the group name, check all the permissions I want to assign to this group, add users to this group (I am going to implement this through ajax search: starting typing a user's name, he/she appears, click Enter, and one user is added, then repeat these actions if needed - is it an OK approach?), and click Save.
Ok, I got a new group with several users. But stop, I realized I forgot to add one more person! I return to the Edit Group window (/groups/edit), and refill the misfilled fields. Click Save - and again some magic (I mean, update operations over the DB).
And so, what I have at the final stage? I can freely c/r/u/d the groups, managing users and permissions in them, and perform it in a very GUI-driven way (I mean, checkboxes, ajax search field, etc.)
For two weeks I have been googling/stackoverflowing/scrutinizing info about rails role- and group-based authorizations; have found a lot of solutions like cancan, easy_roles, troles, etc. gems, but cannot find in any of them how to implement a group-based approach, which is dynamic (or customizable? or dynamically customizable?). The only thing that really 100% suits my needs is a redmine permission and permission group approach, but it is overcomplicated due to its over9000-functionality, so I couldn't even fully understand how it is implemented, let alone implement it on my own.
And the questions are (assuming that the set of permissions is permanent so can be hardcoded, and the set of groups is absolutely free; also, if the user doesn't belong to any group he/she has default user permissions; moreover, permissions are not just for c/r/u/d operations, but also for the manually created methods):
What is the best way to implement the above mentioned system? Any existing yet not found by me gem or approach?
How to painlessly-for-scalability store the permissions and the permission groups? A bitmask, or separate permission, permission-to-group assignment, and group tables?
How to painlessly put users into groups? A group field in the user's DB row, or a separate user-to-group assignment table?
Preferably, that the permissions assigned to the group the user being added to, instantly, without any user relogins, apply to him.
Thank you in advanced!
Through several nights I finally came to a solution, which is, to my mind, rather easy yet powerful, but obviously not the best (but still an) implementation.
So, we have now +1 tables, which is of groups, where the columns are id, name, and permission. The last column is a usual integer which represents all the permissions in a decimal number.
The permissions are "aliased" in the controller: e.g. 1 stands for can_manage_smth, 2 stands for can_view_smth, etc.
The permission choice panel is in the /groups section, and is a simple set of checkboxes, applying an onchange action to each we ajaxly perform an OR operation with the permission stored in the table (e.g. we select 3 checkboxes standing for the values of 1, 8, and 16, then we get in our table 25, which is, in turn, a result of 1 | 8 | 16).
So answering my questions:
Not the best but still a solution.
It almost does not affect the scalability because adding a new permission (which is a very rare action) will just demand a new alias of the permission and its before_filter checkings in the beginning of the controller. And I used a bitmask but not as a binary but just a usual decimal value with which simple binary logic operands can play.
No separate user-to-group assignment tables, just a single group_id column in a user table (which already existed).
Hope everything implemented will work perfectly. If any issues occur, I will indicate here. Also, if any new implementation ideas come.
Anyway, thanks to everybody!

What kind of locking/transaction isolation level is appropriate for this situation?

Let's say I have a Student and a School table. One operation that I am performing is this:
Delete all Students that belong to a School
Modify the School itself (maybe change the name or some other field)
Add back a bunch of students
I am not concerned about this situation: Two people edit the School/Students at the same time. One submits their changes. Shortly after, someone else submits their changes. This won't be a problem because, in the second user's case, the application will notice that they are attempting to overwrite a new revision.
I am concerned about this: Someone opens the editor for the Schools/Students (which involves reading from the tables) while at the same time a transaction that is modifying them is running.
So basically, a read should not be able to run while a transaction is modifying the tables. Additionally, a write shouldn't be able to occur at the same time either.
Only in serializable isolation level MySQL won't allow you to read the rows that are being modified by another transaction. In any lower isolation level, you will see the rows in the state they were before the transaction, that modifies them, have been started. Of course, in READ_UNCOMITTED, the rows will be seen as deleted / modified, although transaction hasn't been completed.
If you use select for update,
You can use locking of tables to prevent this. Check this for more info on lock tables
EDIT
Have a look at this how to lock some row as they don't be selected in other transaction . Think a similar method can be applied for tables also

Question for Conflict in insertion of data in DB by user and admin, see below for description

I have a case that what will happen when at one end Admin is editing the Details of user "A" in a table "users" and at the same time user "A" itself edits its details in table users. Whose effect will reflected.. And what can be done to make it specific to some one or to give the priority?
Thanks and Regards...
As Michael J.V. says, the last one wins - unless you have a locking mechanism, or build application logic to deal with this case.
Locking mechanisms tend to dramatically reduce the performance of your database.
http://dev.mysql.com/doc/refman/5.5/en/internal-locking.html gives an overview of the options in MySQL. However, the scenario you describe - Admin accesses record, has a lock on that record until they modify the record - will cause all kinds of performance issues.
The alternative is to check for a "dirty" record prior to writing the record back. Pseudocode:
User finds record
Application stores (hash of) record in memory
User modifies copy of record
User instructs application to write record to database
Application retrieves current database state, compares to original
If identical
write change to database
If not identical
notify user
In this model, the admin's change would trigger the "notify user" flow; your application may decide to stop the write, or force the user to refresh the record from the database prior to modifying it and trying again.
More code, but far less likely to cause performance/scalability issues.

MySQL - Saving and loading

I'm currently working on a game, and just a while ago i started getting start on loading and saving.
I've been thinking, but i really can't decide, since I'm not sure which would be more efficient.
My first option:
When a user registers, only the one record is inserted (into 'characters' table). When the user tries to login, and after he/she has done so successfully, the server will try loading all information from the user (which is separate across multiple tables, and combines via mysql 'LEFT JOIN'), it'll run though all the information it has and apply them to the entity instance, if it runs into a NULL (which means the information isn't in the database yet) it'll automatically use a default value.
At saving, it'll insert or update, so that any defaults that have been generated at loading will be saved now.
My second option:
Simply insert all the required rows at registration (rows are inserted when from website when the registration is finished).
Downsides to first option: useless checks if the user has logged in once already, since all the tables will be generated after first login.
Upsides to first option: if any records from tables are deleted, it would insert default data instead of kicking player off saying it's character information is damaged/lost.
Downsides to second option: it could waste a bit of memory, since all tables are inserted at registration, and there could be spamming bots, and people who don't even manage to get online.
Upsides to first option: We don't have to check for anything in the server.
I also noted that the first option may screw up any search systems (via admincp, if we try looking a specific users).
I would go with the second option, add default rows to your user account, and flag the main user table as incomplete. This will maintain data integrity across your database, whereas every user record is complete in it's entirety. If you need to remove the record, you can simply add a cascading delete script to clean house.
Also, I wouldn't develop your data schema based off of malacious bots creating accounts. If you are concerned about the integrity of your user accounts, add some sort of data validation into your solution or an automated clean-house script to clear out incomplete accounts once the meet a certain criteria, i.e. the date created meeting a certain threshold.
You mention that there's multiple tables of data for each user, with some that can have a default value if none exist in the table. I'm guessing this is set up something like a main "characters" table, with username, password, and email, and a separate table for something like "favorite shortcuts around the site", and if they haven't specified personal preferences, it defaults to a basic list of "profile, games list, games by category" etc.
Then the question becomes when registering, should an explicit copy of the favorite shortcuts default be added for that user, or have the null value default to a default list?
I'd suggest that it depends on the nature of the auxiliary data tables; specifically the default value for those tables. How often would the defaults change? If the default changes often, a setup like your first option would result in users with only a 'basic' entry would frequently get new auxiliary data, while those that did specify their own entries would keep their preferences. Using your second option, if the default changed, in order to keep users updated, a search/replace would have to be done to change entries that were the old default to the new default.
The other suggestion is to take another look at your database structure. You don't mention that your current table layout is set in stone; is there a way to not have all the LEFT JOIN tables, and have just one 'characters' table?