Hstore and multitenancy - ruby-on-rails

I'm bulding an app where users can add custom fields and submit data. I'm using Postgresql so I thought that Hstore would be the perfect solution for this. Also because it allows to query the custom data that the users may introduce. My problem is that Hstore can only be installed into one schema and I'm using apartment gem for multitenancy. So each User has one schema in the database.
The data into the Hstore column is private, so I don't want other users to get access to it. How can I acomplish this? I prefer to store this data into the same user's schema. Is there another solution?

Craig is telling you to install hstore in its own schema. That means doing something along these lines.
create schema hs;
create extension hstore with schema hs;
This has nothing to do with how and where you store hstore data.
If I had a personal schema named "mike", I would build tables in the "mike" schema with hstore data types like this.
create schema mike;
create table mike.test (
some_column_name hs.hstore
);
You can avoid having to use the "hs" schema name (as in "hs".hstore) by putting that schema in the search path. If you were doing a "normal" client/server application, you'd probably want to set it at the database level.
alter database your_database_name set search_path TO mike, hs, public;
But in your multi-tenant architecture, which has one schema per tenant, you'd probably want one database role per tenant, and you'd probably want to set the search path for each role. (I'm not familiar with the "apartment" gem; I presume it creates one role per tenant and one schema per tenant. Verify that by checking the database schema.)
alter role one_role_name set search_path to one_role_name, hs, public;
I'd also want to verify sensible privileges on the schemas. For example, in a multi-tenant architecture like yours, I'd want to verify that only "mike" has privileges in the "mike" schema.
The first schema in the search path becomes the default schema for new objects. On the other hand, database objects in that schema can hide database objects of the same name in other schemas. Keep that in the back of your mind.
Finally, thousands of rows is a tiny database. Performance problems will probably have nothing to do with your database search path.

Related

How do I reverse engineer a PostgreSQL 9.6.6 database for Rails?

I have a database in PostgreSQL 9.6.6 already defined, how do I reverse engineer that into Ruby on Rails?
[Please don't flame me if this has already been asked, I couldn't find an answer when I searched.]
Thank you.
Understood, i read your comment. But the thing is, Model with relations and attributes in rails provide by Active Record, in fact you cant export all stuff from random database.
You need to create migrations/models with Active Record Associations and object attributes, and after that Seed new database.
Somebody correct me if I'm wrong:
It would seem to me that since rails determines what columns are in a table by actually looking at the table definition in the database, that we (I) don't have to "reverse engineer" the database.
If rails is interrogating the database for the definitions, then the only thing we would have to do is define the relationships in the ORM classes and that we don't have to create migrations.

How to export the DDL of domains(Database schema) of new version for update

I have developed a application with Grails earlier.Now as per new requirement there is a need to modify the existing domain classes as well as adding a new classes and changing / establishing new relationship between the as well.
Now the new requirement has been implemented and I am going to deploy to production environment. however, the DBA want a script change the production database DDL. DBA is not allowing the auto create / update of database schema while bootstrapping the application.
I know how to export DDL of for creating tables. but that script will drop tables which means all data will be lost.
But I don't know how to export DDL for DDL-update (no drop tables/recreate tables). Anybody has good suggestion ?
You can not expect the existing data to get stored according to the new database schema as is.
For example, you have a table Sample with the contactNumber field with the nullable : true constraint in your existing schema and in your new schema this constraint has been changed to nullable : true & unique : true.
In such cases database will fail to keep the existing data intact or adapt to new schema.
To preserve the existing data, you may have to go through a tedious process like -
Take backup of the existing database.
Make a note of the modification you have made to the existing Domain classes.
Find out which modifications may lead to failure / data loss.
Drop the earlier database schema & Deploy the new application and let it create the database schema.
Write a script or utility which will process & store the data from database backup according to new database schema.Make sure the utility you have written has the capalibility to handle the modification(constraint, field added, field removed) done to the database schema.

Create HSTORE with multiple schemas

I have been trying to migrate my database to have HSTORE but the extension only works for public SCHEMA when I want to add an HSTORE column in other schemas it does not work
def up
# My hstore looks like this
execute "CREATE EXTENSION hstore SCHEMA public"
# I have also tried
# execute "CREATE EXTENSION hstore"
end
but when I run my next migration it just doesn't work and if I go to psql console and alter tables I get this:
set search_path to public;
alter table accounts add column extras hstore; -- Works fine
set search_path to schema2;
alter table accounts add column extras hstore; -- Raises an error
I'm using rails 4
Thanks.
You need to refer to your objects in a way that is consistent with your schema naming and search path. For example:
CREATE EXTENSION hstore SCHEMA public;
SET search_path TO schema2;
ALTER TABLE accounts ADD COLUMN extras public.hstore;
or
SET search_path TO public;
ALTER TABLE schema2.accounts ADD COLUMN extras hstore;
If you're using multiple different schemas, I suggest putting hstore in its own and ensuring it is always on the search_path. You might not want public on your search_path at all times, and it's nice to keep things compartmentalized.
CREATE SCHEMA hstore;
CREATE EXTENSION hstore WITH SCHEMA hstore;
... then either amend your search_path consistently, or just always schema-qualify everything, using hstore.hstore as the type name, OPERATOR(hstore.->). E.g.
SELECT hstore.hstore('"x" => "42"') OPERATOR(hstore.->) "x"
Alternately, it's safe to install hstore into pg_catalog:
CREATE EXTENSION hstore WITH SCHEMA pg_catalog;
pg_catalog is always implicitly on the search path.
the alternative to Peter Eisentraut's answer is to amend your search path so that the public schema is always on the search path.
This is particularly useful if you rely on schemas for a multitenant app (which is my case).
In your database.yml file you would put the following instruction:
schema_search_path: "schema2, public"
note: put your main schema first.
if you want to change the search path in a more dynamic way in your code, you can play with connection.schema_search_path

How do define the schema that a rails model is set to?

For instance, when I generate an Event model, the table automatically sets to the public schema. How do I specify it to get set to a different schema?
Furthermore, how do you alter the schema of an existing table? Perhaps move it to a different schema?
Thank you!
Disclaimer: I don't know rails, so I'm going to give very postgresql-oriented answers here. For the first part of your question, there is quite possibly a much better way to do this, by making rails specify the schema when creating tables.
In PostgreSQL, tables are searched for in schemas according to the search_path setting. This is set by default to "$user",public. Tables are created in the first schema found in the search path that exists. So if you connect as "my_user", it will try to create tables in "my_user", and fall back to creating them in "public" if "my_user" doesn't exist.
So one approach is to update the "search_path" setting used for the user you connect to the database to make schema changes. For example you can say ALTER USER my_user SET search_path = my_app, public. If you then create a "my_app" schema then subsequent CREATE TABLE foo(...) commands executed by "my_user" will put the new table into "my_app".
You can change the schema of a table using ALTER TABLE foo SET SCHEMA my_app.
Create a migration to generate your new schema. ActiveRecord can't update you schema to you it's the pattern system. You can try sequel or DataMapper if you want update you schema from your code.

Rails: Accessing a database not meant for Rails?

I have a standard rails application, that uses a mysql database through Active Record, with data loaded through a separate parsing process from a rather large XML file.
This was all well and good, but now I need to load data from an Oracle database, rather than the XML file.
I have no control how the database looks, and only really need a fraction of the data it contains (maybe one or two columns out of a few tables). As such, what I really want to do is make a call to the database, get data back, and put the data in the appropriate locations in my existing, Rails friendly mysql database.
How would I go about doing this? I've heard* you can (on a model by model basis) specifiy different databases for Rails Models to use, but that sounds like they use them in their entirety, (that is, the database is Rails friendly). Can I make direct Oracle calls? Is there a process that makes this easier? Can Active Record itself handle this?
A toy example:
If I need to know color, price, and location for an Object, then normally I would parse a huge XML file to get this information. Now, with oracle, color, price, and location are all in different tables, indexed by some ID (there isn't actually an "Object" table). I want to pull all this information together into my Rails model.
Edit: Sounds like what I'd heard about was ActiveRecord's "establish_connection" method...and it does indeed seem to assume one model is mapped to one table in the target database, which isn't true in my case.
Edit Edit: Ah, looks like I might be wrong there. "establish_connection" might handle my situation just fine (just gotta get ORACLE working in the first place, and I'll know for sure... If anyone can help, the question is here)
You can create a connection to Oracle directly and then have ActiveRecord execute a raw SQL statement to query your tables (plural). Off the top of my head, something like this:
class OracleModel < ActiveRecord::Base
establish_connection(:oracle_development)
def self.get_objects
self.find_by_sql("SELECT...")
end
end
With this model you can do OracleModel.get_objects which will return a set of records whereby the columns specified in the SELECT SQL statement are attributes of each OracleModel. Obviously you can probably come up with a more meaningful model name than I have!
Create an entry named :oracle_development in your config/database.yml file with your Oracle database connection details.
This may not be exactly what you are looking for, but it seems to cover you situation pretty well: http://pullmonkey.com/2008/4/21/ruby-on-rails-multiple-database-connections/
It looks like you can make an arbitrarily-named database configuration in the the database.yml file, and then have certain models connect to it like so:
class SomeModel < ActiveRecord::Base
establish_connection :arbitrary_database
#other stuff for your model
end
So, the solution would be to make ActiveRecord models for just the tables you want data out of from this other database. Then, if you really want to get into some sql, use ActiveRecord::Base.connection.execute(sql). If you need it as a the actual active_record object, do SomeModel.find_by_sql(sql).
Hope this helps!
I don't have points enough to edit your question, but it sounds like what you really need is to have another "connection pool" available to the second DB -- I don't think Oracle itself will be a problem.
Then, you need to use these alternate connections to "simply" execute a custom query within the appropriate controller method.
If you only need to pull data from your Oracle database, and if you have any ability to add objects to a schema that can see the data you require . . . .
I would simplify things by creating a view on the Oracle table that projects the data you require in a nice friendly shape for ActiveRecord.
This would mean maintaining code to two layers of the application, but I think the gain in clarity on the client-side would outweigh the cost.
You could also use the CREATE OR REPLACE VIEW Object AS SELECT tab1., tab2. FROM tab1,tab2 syntax so the view returned every column in each table.
If you need to Insert or Update changes to your Rails model, then you need to read up on the restrictions for doing Updates through a view.
(Also, you may need to search on getting Oracle to work with Rails as you will potentially need to install the Oracle client software and additional Ruby modules).
Are you talking about an one-time data conversion or some permanent data exchange between your application and the Oracle database? I think you shouldn't involve Rails in. You could just make a SQL query to the Oracle database, extract the data, and then just insert it into the MySQL database.

Resources