Is there a recommended practice for managing multiple testing and production database users under one Rails app? I've a Rails app with four different database users associated with it:
owner, the DB user who owns the app schemaPermissions: Just about everything. (This is the maintenance/migration account.)
app, the DB account that powers the web applicationPermissions: Read on most tables and views, write on some temporary caching tables.
writer, the DB account that feedsPermissions: Write on a few tables.
auditor, the DB account that logs DB write activityPermissions: Owns a few triggers and functions.
Right now my migration files contain GRANT/REVOKE logic for these specific, named users. However, in the "development" environment all it is often convenient for these users to all be the very same account. Additionally, the hardcoded names of these users may conflict with already-existing DB user names in the final production environment.
It sounds like you're going to need to manage 2 different database connections for each of the classes of users you've got (app/writer). This is often managed by mixing in helpers to set these up to different classes of Models that need to use them.
There's no reason you can't configure this in your development environments, but you'll get the most bang for the buck by using a Staging environment that exactly resembles your Production environment for issues like this, where you can do a final shakedown of behavior before something is pushed live.
Related
I want to run 2 ruby on rails apps which share users, creating one app to do it all is not an option unfortunately. So I want to have single sign on, and user data shared across them. I'm unsure as to what the best solution to this would be.
Should I run them both off the same database?
Have 2 databases with both apps using the users table in one database only?
Some other solution?
You would have to have a dedicated development rails environment to manage migrations. And have the two "apps" pointing at this database. The downside is just generating models and relationships twice for those two apps is a manual task.
A cleaner solution is to have one rails environment with migrations, models and relationships. But build an API endpoint into this environment that those two apps can call in order to use the shared database.
Our Rails suite is comprised of three independent Rails apps:
JSON API (Rails app)
Admin dashboard (Rails app)
Shared data models (Rails engine)
Both the API and Admin dashboard require the shared data models engine in their Gemfiles. All models and custom classes are stored in the engine, and both apps make heavy use of the shared components. The API lives on one Heroku server, and the Admin dashboard lives on another separate Heroku server (two separate Heroku apps). Each use their own respective Postgres databases. All three apps have their own GIT repos.
The API database stores information pertinent to our public users, and the Admin database stores mostly statistical information for admin eyes only.
A caveat of the setup is that the Admin dashboard app has direct access to the API database, and vice-versa. I understand that this is bad practice and may not seem to make sense, but there was a reason for this (mainly because the Admin dashboard needed to access all records of certain API tables, and the use of a custom API to communicate over the wire was not feasible). A similar reason exists for the API-to-Admin database communication.
This setup works for our purposes, nothing is broken, and resources are allocated efficiently. However, productivity is beginning to suffer due to the slow and uncomfortable development process. An example: a change to the API is required. Chances are that the shared models engine needs a change and therefore a feature branch is needed in both repos. After committing and pushing, the Admin dashboard now contains an old version of the models engine (is behind by one patch version). The problem lies in trying to coordinate all three Rails apps, when only one app needs a change. Another problem is migrations. Since the models engine contains two different database connections, I must create the migration once in the models engine then create it again in the appropriate app (API or Admin).
My ideal setup would involve one large Rails container app with separate engines contained within. The separate engines would be: API, Admin, Models. Also, I’m beginning to think that using only one database might make things easier. I would also like to keep the API on its own server instance, and the Admin on a separate server. The reason for this is that the API is public facing (communicates with a public iOS app) and the Admin is used mainly as a CMS and reporting engine.
I am looking for solutions and advice from experience managing similar Rails / Heroku architectures. Specific questions:
Should I attempt to combine the three Rails apps into one container
app and use the engine approach?
Should I attempt to combine the two
databases into one database?
Is it possible to have one Rails
container app, and allocate different servers to different engines?
If I should keep all apps separate, is their an easier and more
productive way to implement new features and fixes on a daily basis?
I am planning on using Devise and Apartment in my upcoming application to create subdomains for each organization that creates an account. I would like to host my application on Heroku, but ran across the following quote:
The most common use case for using multiple schemas in a database is
building a software-as-a-service application wherein each customer has
their own schema. While this technique seems compelling, we strongly
recommend against it as it has caused numerous cases of operational
problems. For instance, even a moderate number of schemas (> 50) can
severely impact the performance of Heroku’s database snapshots tool,
PG Backups.
What technique would work well with Heroku to host basecamp-style subdomains in rails 4 where many users can log in to the subdomain which they are part of?
If Heroku does not work, what other PaaS options are there that would do this well?
Domain
Firstly, you need to be sure that you're using your own custom domain for the subdomains.
Heroku's standard xxx.herokuapp.com won't be able to handle another subdomain on top of that - so you'll basically need to use your custom domain from the get-go
It will be good to reference this documentation for more information!
Multi Tenancy
Although I don't have experience with PGSQL's schemas, I do have some with multi tenancy as a whole.
There are a number of great resources here:
Basecamp-style Subdomains (by DHH)
Multitenancy Railscasts (Pro)
Apartment Gem Documenatation
Essentially, multi-tenancy is just a way to scope the data so that it's only the tenant's that you see / interact with. In the sense of the DB, the two ways to achieve this are either to use different DB's (as you would with MYSQL), or use a schema (like with PGSQL)
Whilst I can't give you a direct fix for your issue, I can help you with some ideas:
Models
One way to achieve multi-tenancy, especially with the likes of MYSQL, is to do it through the model:
How do i work with two different databases in rails with active records?
#lib/admin.rb
class Admin < ActiveRecord::Base
self.abstract_class = true
establish_connection "#{Rails.env}_admin"
end
#app/models/option.rb
Class Option < Admin
# do stuff
end
This works very well for us, although we have not got it working for scoped accounts yet. We've been thinking of setting a ##class_variable for the Account or something, but haven't been working on that right now.
This works very well for MYSQL - powered databases, but also means you'll have to create db's for every account, which will not work with PGSQL (as far as I'm aware)
PGSQL Schemas
I feel this is kind of a cheat way to do this, as all the data is still stored in 1 database - it's basically just scoped around different types of data.
The problem here is that real multi tenancy should be where you completely separate the user's data, so you could cut it out of the app completely if they wanted. From a security & access perspective, it's the most flexible & modular way.
The problem for Heroku is they can only use one database (they give everyone access to their AWS database instances), meaning they can't allow you to create 50+ free databases (it just won't work very well).
You can, of course, use your own stack to create the databases you require, but in terms of PGSQL, it's just about creating the schemas for your data & then using something like -Apartment to make it happen:
PostgreSQL works slightly differently than other databases when
creating a new tenant. If you are using PostgreSQL, Apartment by
default will set up a new schema and migrate into there. This provides
better performance, and allows Apartment to work on systems like
Heroku, which would not allow a full new database to be created.
Most Rails database-deployment discussions assume there are two facets of a database: the schema, which is handled in code via migrations, and the data, which is all user-generated and never needs to move from test to production. What about the stuff that lies in between?
For example, we have a number of mostly-static tables that contain complex surveys our users can take: questions, choices, branching. We want to be able to edit those surveys via our web app, but we want to be able to test changes on the staging server before we push them to production.
What's a good way to handle this in Rails, which wants all the models to exist in one database, and certainly wouldn't like the same model (with different contents) to exist in two databases? Are there any good discussions online, or any gems that have abstracted out this type of functionality?
I've worked with a large, complex CMS system that had its own multi-environment version control and deployment, so you could deploy your change to the test system (without riskily linking the test and production databases), test it thoroughly, and then do a one-click deploy to production. I guess I'm looking for something like that on a smaller scale.
I would use ActiveResource to pull the desired records from the staging environment to production. Alternatively, you could create a name-spaced set of ActiveRecord models to connect to the staging database directly. Either way, the implementation is roughly the same, but ActiveResource allows more flexibility with changing deployment details and the ActiveRecord method requires less setup code.
The actual implementation code should be fairly simple - pull a list of un-imported records from staging (you'll probably want to map the production records to their source staging records to easily prevent duplication) and copy the data.
Not sure about Rails but I am using one python script called Migraine, its useful to synchronizing development, staging, and live (production) sites' databases for Drupal CMS. For more info refer this :
Presentation
Get Migraine script here
It's an application that we use internally at the office that I would like to offer as a hosted service for anyone.
How can I do that without making major code changes?
The first thing that occurs to me is to have the app select which database to connect to based on the domain.
So each instance of the app would have its own database, but all instances would share the same code.
The only changes required to the code would be the database selection.
Is this approach maintainable? I've heard wordpress.com does this and that it offers a couple of advantages. I'm mainly looking to do it this way to avoid have to scope my entire set of database queries to a certain site within the same database.
Thanks!
The simplest way to do this is to clone the application, and create another server instance to handle it. This actually the way I handle multiple wordpress blogs on my server
Pro:
This process can be streamlined into a utility script.
Can be easily maintained if symlinks are used for the common code. IE: Everything but branding and some of the things in the config directory.
Cons:
- If you're using passenger it will require an apache restart for each new instance.
- Same if you're using Apache to route subdomains on different virtual hosts to different mongrel clusters.
However the better way comes from the question: Rails - Separate Database Per Subdomain
The method in the accepted answer is much more robust. It might require more changes than you're looking for, but it has all the benefits without the drawbacks of any other methods. Each new instance requires a new entry in the master database with the table name and other instance specific information. You'll also want custom rake task to build the database for each new instance.
I would suggest switching the database connection and adding a view_path based on the domain, I have posted code in this question.
I hope this helps!
I wouldn't do this with multiple databases as you mentioned. Keeping all your schemas/migrations in sync with all the db's could become painful.
I would look into simply making it a multi-tenant app where you have some sort of "Account" model and then all your existing models are scoped to it ... in other words, if this was a blog app, your Account has_many :posts, etc.
With this approach, you can identify accounts by subdomain ... have people choose their subdomain when they create an account and go from there.
It's pretty straightforward to do. If you need add billing into the mix, you might look at the SaaS Railskit (which handles all the signup and subdomain stuff) or Chargify.
You can also identify accounts Twitter-style ... with http://myapp.com/someuser