Challenge: best way to handle devise user/profile/account removal from database? - ruby-on-rails

Challenge (deactivating):
Having a social media type application in Rails 4 using Devise.
Im looking for a good way to delete users from the system. Since Facebook allows users to reactivate there accounts I have now implemented this feature with a
user.deactivated
boolean, thus not actually deleting records from the database.
Delete users that have not confirmed
Using a rake task I now be able to filter all users that have not confirmed there account for 7 days, These users I would like to really remove from the database. Since users cannot do anything on my application without confirming, I consider them "lost" registrations.
I wonder what would be the best strategy to delete these users in a real removal from the database?
Since each user has its own profile/account what would be the best way to delete everything from the system? Im using:
belongs_to :user, :dependent => :destroy
In profile/account models so the deleting the user from database should delete all there other relations. Is this best way to go? Any things to take into consideration that would break the system?

As You already started going this putting dependencies between models is a good approach, this will remove everything linked on destroy (don't mix up with delete it executes SQL query without Rails callbacks). Though I started to avoid this technique in latest projects.
I am kind of old school about DB cleanliness, so we usually also use gems to enforce FK integrity. It adds another layer of maintenance when deleting objects (as it will throw SQL error when triggered), but I find it more reliable, then a single line in a model. Also we usually overcome this added complexity by providing models with custom_destroy methods that executes delete on all dependent objects.
def custom_destroy
self.class.transaction do
child_objects.delete_all
some_other_child_objects.delete_all
delete
end
end
This provides an advantage of speed, because using destroy_all on 10 child objects will execute 10 SQL queries (+ all the callbacks), this method on the other hand will do only one query.
We seldomly have a need to clean up old unneeded data (expired items), we use a rake tasks for that. If You are on Heroku simply use Heroku scheduler, if You are on a VPS/dedicated machine I advice on using whenever gem, it should have a good integration with Capistrano as well.

Related

Ruby on Rails database workflow

I'm a bit of a Rails beginner, so I'm sorry if this question is easy. I'm wondering how I am supposed to modify the Rails database as a developer without letting users of the site modify data.
More information:
Let's say I am trying to create a website that lists books along with their information. I want users to be able to see these books, but not add/delete them. As a developer, I want a way to add books without using the command line (hard to edit mistakes). What's the easiest way for me to do this? Would there be any differences between the development database and a live hosted one?
I think there are a few approaches to do this.
different user roles. This technically breaks the rule of without letting users of the site modify data, but being able to differentiate between normal and admin users means you can limit who actually can add data into the database. I used cancancan as a way to authorize requests but I know there are others.
I agree doing it using the command line isn't ideal, but rails do support rake tasks. You can create a task that will handle most of the logic and all you need to do is something like
rake create_book["name here"]
This will make the process less error-prone.
Create data using rails migrations. Rails can generate the skeleton file for you, and you just ran any ActiveRecord methods. However, the main purpose of migration is to update the database schema, but they can seed the database as well. here's the example from the dcos
Would there be any differences between the development database and a live-hosted one?
Yea, they should be totally separate database instances. You don't want to have your development database be the same as the live one. This would cause major problems. Rails have a concept of environments where you can use different configurations, so you can pick and choose what database URL to use.
like #davidhu said here The best approach really is the use of authorization. If only admin can see a page to CRUD the books then you don't have to worry about normal users doing same plus it makes it easy for you as the admin to make changes or add to the collection. Add the gem (or reinvent the wheel) then Rails will take care of the rest for you.

Using the gem paper_trail for tracking the latest news-activity on my website

I'm using the gem paper_trail for keeping track of versions. I wonder, is there any way to create some kind of activity news out of the models it's been included into? For example, I've added it into the models Commentary, User and Article. I want to be to get a list of the latest changes of these models and create something like news of activities:
user A has created a new Category
user B has edited an Article
admin had added a new Article
etc
Is it possible? And how? Seems like yes, but how exactly? Note that, I don't want to retrieve that kind of information from all the models I've included the gem into, but only from the ones I want to.
Since you want it by the user, you should integrate https://github.com/ankit1910/paper_trail-globalid to link the whodunnit part.
PaperTrail::Version.where_object(attr1: val1, attr2: val2)
NOTE: paper_trail gem is for auditing.
Do not forget to check your indexes on your database since relational databases slow as your no. of indexes increase.
Based on my experience with [spree][1] framework and a similar gem, versions table was the largest we had and it grew quiet fast. You may face similar challenges in maintaining this table and adding indexes may cause it to slow down.
My suggestion would be to use a Redis like store to maintain a list of 10 or so recent updates per user which the user may be notified of instead of querying MySQL (essentially caching)

How to share a database, migrations, and models between Rails projects?

I know there are some questions to this effect already on StackOverflow, but they tend to be pretty outdated and don't adequately address how migrations are supposed to work in the following scenario, which should be fairly common:
You have some kind of application, implemented in Rails.
You have some kind of admin application for your data, and it is a separate application implemented in Rails.
Both applications operate on the same database and models.
My question is: what is the best way to factor our models such that both of these applications don't have to duplicate model code?
We are concerned with the following:
For the shared models, where should database migrations live?
What if each individual application wishes to add additional models on top of shared models? Where do these migrations live?
What is the best way to move existing migrations into the proposed shared migration scheme?
Thanks.
I don't know if this is THE approach, and would love to see other ideas, but what we do in one of our products that matches this model:
For the shared models, where should database migrations live?
We keep all of our migrations under the admin system. You don't need them to exist twice, so that's where they go.
What if each individual application wishes to add additional models on top of shared models? Where do these migrations live?
We share all models. It might only be relevant to one application at the moment, say - a favourited_items concept might only matter to the end user. But at a later date the admin might want to know what items are most frequently favourited.
Secondly, if you want to investigate anything via console, it's really quite helpful if you don't need to visit separate applications because they don't both have models for every table.
Functionality in shared models that differs per application detects the rails environment variable, which we have extended to include more context. E.g.: if Rails.env == 'admin_production'
What is the best way to move existing migrations into the proposed shared migration scheme?
Again, migrations should only ever exist once, and the shared database knows which have already been run, so unless you're renaming the migrates you just need to pick a location and move the files.

How I delete a complete feature from my rails app?

Initially I built a forum on rails with the user and the post model but now I am planning to pivot to something else and I don't need the posts functionality anymore.
My question is how do I completely delete it and what would be correct order if I have to just delete the files generated.
By deleting I mean everything like that feature never existed in the app, no database connections and no properties remaining on the other user model.
I am not sure how I do I proceed, there are many ways to do it, by running commands or by just deleting the generated files but I want to know the correct way because I don't want to run into trouble if something goes wrong.
There is no "correct" way, just delete the files, create a migration removing the tables and then audit your remaining files for methods that are no longer used.
In simple cases, you can use the generators that generated your code to also remove that code. If you used rails generate model MyModel to produce your model and migration, you can use rails destroy model MyModel.

Should I use multiple databases?

I am about to create an application with Ruby on Rails and I would like to use multiple databases, basically is an accounting app that will have multiple companies for each user. I would like to create a database for each company
I found this post http://programmerassist.com/article/302
But I would like to read more thoughts about this issue.
I have to decide between MySQL and PosgreSQL, which database might fit better my problem.
There are several options for handling a multi-tenant app.
Firstly, you can add a scope to your tables (as suggested by Chad Birch - using a company_id). For most use-cases this is fine. If you are handling data that is secure/private (such as accounting information) you need to be very careful about your testing to ensure data remains private.
You can run your system using multiple databases. You can have a single app that uses a database for each client, or you can have actually have a seperate app for each client. Running a database for each client cuts a little against the grain in rails, but it is doable. Depending on the number of clients you have, and the load expectations, I would actually suggest having a look at running individual apps. With some work on your deployment setup (capistrano, chef, puppet, etc) you can make this a very streamlined process. Each client runs in a completely unique environment, and if a particular client has high loads you can spin them out to their own server.
If using PostgreSQL, you can do something similar using schemas.
PostgresQL schemas provide a very handy way of islolating your data from different clients. A database contains one or more named schemas, which in turn contain tables. You need to add some smarts to your migrations and deployments, but it works really well.
Inside your Rails application, you attach filters to the request that switch the current user's schema on or off.
Something like:
before_filter :set_app
def set_app
current_app = App.find_by_subdomain(...)
schema = current_app.schema
set_schema_path(schema)
end
def set_schema_path(schema)
connection = ActiveRecord::Base.connection
connection.execute("SET search_path TO #{schema}, #{connection.schema_search_path}")
end
def reset_schema_path
connection = ActiveRecord::Base.connection
connection.execute("SET search_path TO #{connection.schema_search_path}")
end
The problem with answers about multiple databases is when they come from people who don't have a need or experience with multiple databases. The second problem is that some databases just don't allow for switching between multiple databases, including allowing users to do their own backup and recovery and including scaling to point some users to a different data server. Here is a link to a useful video
http://aac2009.confreaks.com/06-feb-2009-14-30-writing-multi-tenant-applications-in-rails-guy-naor.html
This link will help with Ruby on Rails with Postgresql.
I currently have a multi-tenant, multi-database, multi-user (many logons to the same tenant with different levels of access), and being an online SaaS application. There are actually two applications one is in the accounting category and the other is banking. Both Apps are built on the same structure and methods. A client-user (tenant) can switch databases under that user's logon. An agent-user such as a tax accountant can switch between databases for his clients only. A super-user can switch to any database. There is one data dictionary i.e. only one place where tables and columns are defined. There is global data and local data. Global data such as a master chart-of-accounts which is available to everyone (read only). Local data is the user's database. A new user can get a clone of a master database. There are multiple clones to choose from. A super-user can maintain the clone databases.
The problem is that it is in COBOL and uses ISAM files and uses the CGI method. The problem with this is a) there is a perception that COBOL is outdated, b) getting trained people, c) price and d) online help. Otherwise it works and I'm happy with it.
So I'm researching what to replace it with and what a minefield that is.
It has past time and the decission for this has been to use PostgreSQL schemas, making multitenant applications, I have a schema called common where related data is stored.
# app/models/organisation.rb
class Organisation < ActiveRecord::Base
self.table_name = 'common.organisations'
# set relationships as usual
end
# app/models/user.rb
class User < ActiveRecord::Base
self.table_name = 'common.users'
# set relationships as usual
end
Then for migrations I have done that with this excellent tutorial. http://timnew.github.com/blog/2012/07/17/use-postgres-multiple-schema-database-in-rails/ use this, this is way better than what I saw in other places even the way Ryan Bates did on railscasts.
When a new organisation is created then a new schema is created with the name of the subdomain the organisation. I have read in the past that it's not a good idea to use different schemas but it depends on the job you are doing, this app has almost no soccial component so it's a good fit.
No, you shouldn't use multiple databases.
I'm not really sure what advice to give you though, it seems like you have some very basic misunderstandings about database design, you may want to educate yourself on the basics of databases first, before going further.
You most likely just want to add a "company id" type column to your tables to identify which company a particular record belongs to.

Resources