How to set PostgreSQL table names in Rails with schema information? - ruby-on-rails

I have to connect my rails app in a legacy Postgre database. It uses schemas so in a SQL its is common to use something like
SELECT * FROM "Financial".budget
I want to write a Budget model but I don't know how to set the table name in this case. I've tried the following:
set_table_name 'budget'
set_table_name '"Financial".budget'
None have worket.

ActiveRecord::Base.establish_connection(
:schema_search_path => 'Financial,public'
)
If you're using Postgres, the above is probably "good enough" for most situations.

I had similar issue with Oracle adapter. By default ActiveRecord always quotes table names in SQL and therefore if you specify
set_table_name "Financial.budget"
then generated SQL will be
SELECT * FROM "Financial.budget"
which will not work.
To solve this issue you need to monkey patch PostgreSQL adapter. Put into your environment.rb or in separate initializer the following code:
ActiveRecord::ConnectionAdapters::PostgreSQLAdapter.class_eval do
# abstract_adapter calls quote_column_name from quote_table_name, so prevent that
def quote_table_name(name)
name
end
end
Now you should define in your model class
set_table_name "Financial.budget"
and generated SQL will be
SELECT * FROM Financial.budget

Now, this bug seems to be solved in 2-3-stable. Take a look at this post

Look at your logs -- what SQL is Rails generating with your various options?

set_table_name "Financial.budget"

Perhaps extending the search path with your schema will help you?
SET SEARCH_PATH TO "Financial", public;
Then you could write your query unqualified without the schema:
SELECT * FROM budget;

We designed a gem to make ActiveRecord work with PostgreSQL. Here is a small usage example:
http://greyblake.com/blog/2012/09/06/pg-power-activerecord-extension-for-postgresql/

Related

Alternative to the globalize gem

I tried out the globalize gem but this seems like a big overhead. Most of the time I just need one attribute translated. I'm using postgreSQL and would rather use a hstore for this. That way I won't get additional tables and performance should be at least as good if not better.
Are there any gems that use this approach or would this mean a custom development?
Seems like you're searching for the hstore_translate gem. I have not tested it but it appears to suit your needs precisely from the description:
Rails I18n library for ActiveRecord model/data translation using PostgreSQL's hstore datatype. It provides an interface inspired by Globalize3 but removes the need to maintain separate translation tables.
I've been using the hstore_translate gem and love it.
Say for example you have a Project model schema with title:string and content:text. If you want content to be translated, all that needs to be done is to create a migration:
class AddTranslationToProjects < ActiveRecord::Migration
def change
add_column :projects, :title_translations, 'hstore'
end
end
and inside of project.rb:
class Project < ActiveRecord::Base
translates :title
end
thats it! Nothing else to do in the form or wherever. Works for integers and booleans as well. The only extra step to do is activate hstore if using postgres: CREATE EXTENSION hstore
I've recently created the gem awesome_hstore_translate, which is based on the original hstore_translate by Rob Worley.
hstore_translate uses alias_method_chain, which got deprecated with Rails 5.0.
My gem has the same functionality as it's original, but it's a bit more modern. It stores it's data in columns without a suffix, because I think the database model looks more clean that way. The raw data is still available. E. g. Page.first.title_raw will give you the hstore hash.

Rails console how do I 'show tables' like I would in mySQL [duplicate]

I was wondering if you could list/examine what databases/objects are available to you in the Rails console. I know you can see them using other tools, I am just curious.
Thanks.
You are probably seeking:
ActiveRecord::Base.connection.tables
and
ActiveRecord::Base.connection.columns('projects').map(&:name)
You should probably wrap them in shorter syntax inside your .irbrc.
I hope my late answer can be of some help.
This will go to rails database console.
rails db
pretty print your query output
.headers on
.mode columns
(turn headers on and show database data in column mode )
Show the tables
.table
'.help' to see help.
Or use SQL statements like 'Select * from cars'
To get a list of all model classes, you can use ActiveRecord::Base.subclasses e.g.
ActiveRecord::Base.subclasses.map { |cl| cl.name }
ActiveRecord::Base.subclasses.find { |cl| cl.name == "Foo" }
You can use rails dbconsole to view the database that your rails application is using. It's alternative answer rails db. Both commands will direct you the command line interface and will allow you to use that database query syntax.
Run this:
Rails.application.eager_load!
Then
ActiveRecord::Base.descendants
To return a list of models/tables
Its a start, it can list:
models = Dir.new("#{RAILS_ROOT}/app/models").entries
Looking some more...

Query Remote Database from Rails 3.2 Application

I need to query a 3rd party database which is entirely separate from the Rails 3.2 application I'm building (belongs to a different application which my company uses internally).
Ultimately, I'll be setting up a cron to load new rows from the "other" database which my Rails application will be processing.
I have the access to otherdb set up, and I'm wondering where to go from hereā€”do I create a new entry in config/database.yml? If so, how do I then specify when a query is to be directed to otherdb, instead of my default Rails development or production db?
There's a few ways to implement this requirement, the easiest of which would be to use config/database.yml and custom namespaced model(s).
Setting up something similar to the below, using a suffix of Rails.env to follow the naming convention will provide the functionality you outlined.
First, create new entries for the external database each of your existing environments. It'll help you to be able to test the functionality.
# database.yml
development:
# add configuration as required
otherdb_development:
# add configuration as required
Second, add a model for each of the specific tables you need to access in the otherdb database. I'd recommend adding a namespace directory for these models (otherdb in the example below) to avoid confusion and potential clobbering:
# /app/models/otherdb
class Otherdb::Foo < ActiveRecord::Base
establish_connection "otherdb_#{Rails.env}"
set_table_name "foo" # customize this if the table name will be different from the classname and is required
end
You can then use (as an example) methods on Otherdb::Foo and use the resulting data as required.
I had the same problem yesterday. Since you are using Rails 3.2, all your models that connect to the external database will have to be subclasses of a single, abstract class that establishes the connection. In earlier versions of Rails, #Sasha's answer would have worked. But in 3.2, that answer will lead you to getting various confusing database errors. (What errors you get depends on what DB you use.)
In Rails 3.2, this is the only way I have found that will work:
Make a common base class for all models that need to talk to a
non-default database.
Tell ActiveRecord that this base class is abstract by calling self.abstract_class = true.
Call establish_connection in the base class.
Here is an example with students and courses from an external table:
# database.yml:
development:
# default configuration goes here
other_development:
# external db configuration goes here
class OtherTable < ActiveRecord::Base
self.abstract_class = true
establish_connection "other_#{Rails.env}"
end
class Student < OtherTable
end
class Course < OtherTable
end
If you'd like more detail, see the blog post I wrote titled Establishing a Connection to a Non-Default Database in Rails 3.2.

Ruby on rails with multiple production settings

How can we run a ruby on rails application with different database configuration?
in detail: I want to run multiple instance of a rails app with different database config for each on production. How is it possible?
I think you can duplicate the config in database.yml into different environments, like prod1, prod2 ... and then set RAILS_ENV environment variable to match before starting up each respective server...
You can duplicate your database.yml file as DGM mentioned. However, the right way to do this would be to use a configuration management solution like Chef.
If you look at the guide for setting up Rails stack, it includes a 2 front-end Web server + 1 back-end DB server. Which would include your case of duplicating database.yml file.
If you are able to control and configure each Rails instance, and you can afford wasting resources because of them being on standby, save yourself some trouble and just change the database.yml to modify the database connection used on every instance. If you are concerned about performance this approach won't cut it.
For models bound to a single unique table on only one database you can call establish_connection inside the model:
establish_connection "database_name_#{RAILS_ENV}"
As described here: http://apidock.com/rails/ActiveRecord/Base/establish_connection/class
You will have some models using tables from one database and other different models using tables from other databases.
If you have identical tables, common on different databases, and shared by a single model, ActiveRecord won't help you. Back in 2009 I required this on a project I was working on, using Rails 2.3.8. I had a database for each customer, and I named the databases with their IDs. So I created a method to change the connection inside ApplicationController:
def change_database database_id = params[:company_id]
return if database_id.blank?
configuration = ActiveRecord::Base.connection.instance_eval { #config }.clone
configuration[:database] = "database_name_#{database_id}_#{RAILS_ENV}"
MultipleDatabaseModel.establish_connection configuration
end
And added that method as a *before_filter* to all controllers:
before_filter :change_database
So for each action of each controller, when params[:company_id] is defined and set, it will change the database to the correct one.
To handle migrations I extended ActiveRecord::Migration, with a method that looks for all the customers and iterates a block with each ID:
class ActiveRecord::Migration
def self.using_databases *args
configuration = ActiveRecord::Base.connection.instance_eval { #config }
former_database = configuration[:database]
companies = args.blank? ? Company.all : Company.find(args)
companies.each do |company|
configuration[:database] = "database_name_#{company[:id]}_#{RAILS_ENV}"
ActiveRecord::Base.establish_connection configuration
yield self
end
configuration[:database] = former_database
ActiveRecord::Base.establish_connection configuration
end
end
Note that by doing this, it would be impossible for you to make queries within the same action from two different databases. You can call *change_database* again but it will get nasty when you try using methods that execute queries, from the objects no longer linked to the correct database. Also, it is obvious you won't be able to join tables that belong to different databases.
To handle this properly, ActiveRecord should be considerably extended. There should be a plugin by now to help you with this issue. A quick research gave me this one:
DB-Charmer: http://kovyrin.github.com/db-charmer/
I'm willing to try it. Let me know what works for you.
Well. We have to create multiple environments in you application
create config/environmenmts/production1.rb which will be same as of config/environmenmts/production.rb
then edit database.yml for production1 settings and you are done.
start server using rails s -e production1

Rails migrations with database-specific data types

I'm currently running a Rails migration where I am adding a datatype specific to Postgres, the tsvector. It holds search information in the form that Postgres expects for its built-in text searching capabilities.
This is the line from my migration:
t.column "search_vectors", :tsvector
Everything seems to be working fine, and the search works with it. However, when I opened up schema.rb, this is what I got:
Could not dump table "users" because of following StandardError
Unknown type 'tsvector' for column 'search_vectors'
This is preventing me from running unit tests on the user table, and also strikes me as really dangerous looking given that the schema.rb is supposed to be the authoritative definition of my database.
I notice there are a number of Rails plugins that seem to use the same approach of storing the tsvector like I would expect, such as tsearchable. Am I really just stuck without testing and without an authoritative definition of my database?
FYI for anyone who happens across this page, I fixed this by adding this (actually uncommenting it) to my Rails config:
config.active_record.schema_format = :sql
Have you tried specifying the type as a string instead of a symbol?
t.column "search_vectors", "tsvector"
If that doesn't work then you might need to drop down to database-specific SQL:
def self.up
execute "--Put your PostgreSQL specific SQL statements here"
end

Resources