Safely Drop User Table in Ruby on Rails Application - mysql

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.

Related

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

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.

How to correctly handle multiple privileged MySQL connection accounts

I have read many posts and articles that state quite clearly that for the best in worst-case damage limitation, MySQL accounts should only be able to do what they're intended to do, and nothing else. This makes perfect sense and so there would be a connection account to my Database that does all the SELECTing of data, and another account that does UPDATE and INSERT activities, so that if someone does get the compromise by SELECTing data they shouldn't, then they can't quite as easily then UPDATE that data or INSERT etc.
You get the idea.
But, I have various Databases and use accounts to read/SELECT data and the this is output to the client page, but often these accounts will need to be updated, small things such as updating when a (website) user logs into their account, or updating some sort of hitcounter or other minor feature. Given the ringfencing of concerns outlined above, I feel it's a bit like using a flood to put out a campfire, to allow UPDATEing (etc.) to a privileged MySQL connection simply to say that user Bob logged in last at 4:10pm.
I have been digging on the web for suitable guides, blog posts and articles about how to best structure using multiple MySQL privileged accounts to complete the nessecary work with as minimum a risk of excess privilege as possible, but I have found nothing that has been much use, (mostly because of my wording seems to be attracting articles about setting up website users, or other topics associated with these keywords :-/ )
I have a few ideas on current approach and wanted a bit of feedback on the best method for doing activities as described in paragraph 2, typically 95% SELECTing, and a few specific instances of UPDATEing, or if any of the following are possible (or on flipside, are very bad ideas)? :
I currently have seperate PHP connection objects for each connection privilege user. Is this the best approach?
Could I somehow giving a privilege user access to only update a certain table (or even a certain table column?), as well as SELECT from any table? This would be perfect.
Are using TRIGGERs a common approach and would this have any down sides if I created a Trigger (with a privileged user) and then let a SELECT user account access triggers?
Could I set certain users can only use certain triggers?
Is there another way of doing this?
MySQL allows for users to have different privileges set both at database and individual table levels. The documentation on the GRANT (http://dev.mysql.com/doc/refman/5.7/en/grant.html) syntax gives an example of setting all privileges to a user on one database while only select access to a table in another database.
Privileges can even be set for specific columns (http://dev.mysql.com/doc/refman/5.7/en/grant.html#grant-column-privileges) in a table & also for stored procedures (http://dev.mysql.com/doc/refman/5.7/en/grant.html#grant-routine-privileges).

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!

Trying to delete several thousand users from database

I checked one of my Joomla! websites this evening and to my horror found that I had thousands of spam registrations. I can't bring up all the users on one page on the website because it crashes, it's obviously too much for the server.
Even if I display 100 users per page, I've got 500 pages, it will take me until next week to delete them. So I thought maybe I can do from the database. The same thing happened, if I have 30 users showing, there are over 1000 pages. So I change the setting to show 1000 users, I wasn't able to delete the 1000 user because the page just crashed again.
So I'm thinking that maybe I can backup my own account from the user table. However, do I have to create another user table in order to reinstall my account? I hope you understand my dilemma
What I might do is go to phpmyadmin and export any data you want to keep even one at a time.
Then empty the table (i.e. delete all the rows).
Then import all of the data you exported back into the empty table.
Of it's just the one record you want to keep #Sparkup's answer will be quicker though.
Were you using a user profile plugin? If so you'll want to delete any records there also.
Then at minimum enable recaptcha, but also if you don't really want user registration, turn that off in the global configuration.
If you want to delete every user except your own you could do :
DELETE FROM users WHERE email != 'your_email';
Please note this will delete every other account
Be sure to make a backup of your database first.
If you want to remove emails with a certain extension :
DELETE FROM users WHERE email LIKE '%.co.uk';
DELETE FROM users WHERE email LIKE '%gmail.com';
Mysql Delete would be a good choice. Access Joomla database from terminal(linux) or cmd(windows) that would be fast .using captcha might be useful to stop spamming at certain extent.

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?