I'm developing an aplication with mysql and sqlserver. sqlserver is used to connect to a legacy table.
here is my definition
development:
adapter: mysql2
encoding: utf8
reconnect: false
database: spvalores_development
username: secret
password: secret
pool: 5
host: 192.168.100.35
socket: mysql
port: 3306
sql_server_db:
adapter: sqlserver
database: SPPokerManager
dsn: DesaSqlServer
mode: odbc
username: sa
password: master
encoding: utf8
the gems i use:
gem 'activerecord-sqlserver-adapter'
gem 'ruby-odbc'
this is my model
class Client < ActiveRecord::Base
self.table_name = "dbo.LOB_CLIENTE"
self.primary_keys = :CASINO_ID, :CLIENTE_ID
establish_connection :sql_server_db
attr_accessible :CASINO_ID, :CLIENTE_ID, :CDNI, :CAPELLIDO, :CNOMBRES,:TIPODOCUMENTO_ID, :CNICKNAME, :CDIRECCION, :CTELEFONO, :CCELULAR, :CEMAIL, :COBSERVACIONES, :CLIENTEPERFIL_ID
attr_accessible :DFECHAINGRESO, :BIDENTIFICADO, :BACEPTAENVIOSMS, :IFOTO, :COLATIPOPREFERIDA_ID
attr_accessible :BACTIVO, :CNROJUGADOR, :CSEXO, :DFECHANACIMIENTO, :NACIONALIDAD_ID, :CEMAIL2, :CPATROCINADOR, :CPAISRESIDENCIA, :CPROVINCIARESIDENCIA, :CCIUDADRESIDENCIA
attr_accessible :DFECHAHORA_CESIONIMAGEN, :BFIRMA, :BJUGADORFRECUENTE, :DFECHAACTUALIZACION
def as_json(options={})
nick = self.CNICKNAME.force_encoding("ISO-8859-1").encode("UTF-8")
name = self.CNOMBRES.force_encoding("ISO-8859-1").encode("UTF-8") unless self.CNOMBRES.nil?
surname = self.CAPELLIDO.force_encoding("ISO-8859-1").encode("UTF-8") unless self.CAPELLIDO.nil?
{:CLIENTE_ID => self.CLIENTE_ID ,:CNICKNAME => nick ,:CAPELLIDO => surname ,:CNOMBRES => name, :CDNI => self.CDNI, :TIPODOCUMENTO_ID => self.TIPODOCUMENTO_ID }
end
end
i always get errors like this:
incompatible character encodings: ASCII-8BIT and UTF-8
the only way i solved is doing something like this
modelinstance.field.force_encoding("ISO-8859-1").encode("UTF-8")
There are a lot of field on that table. Beside, sure i will need to query other tables like this one.
Looking in the database properties the collation is Modern_Spanish_CI_AS
How i can configure rails to show and save property in the collation Modern_Spanish_CI_AS
Thanks in advance, hope to be clear
Well I finally solve the problem.
I need to use tiny_tds:
here is the explanation:
https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/wiki/Using-TinyTds
Related
I have to move my app data from the old app database to new app database. The table structures are different. I have written the following script.
require 'mysql2'
require 'active_record'
old_database = {
adapter: "mysql2",
host: "localhost",
username: "foo",
password: "bar",
database: "old_db",
socket: "/var/run/mysqld/mysqld.sock"
}
new_database = {
adapter: "mysql2",
encoding: "utf8mb4",
collation: "utf8mb4_bin",
host: "localhost",
username: "foo",
password: "bar",
database: "new_db",
socket: "/var/run/mysqld/mysqld.sock"
}
class Doctor < ActiveRecord::Base
end
Code for reading a single record from old database
ActiveRecord::Base.establish_connection(old_database)
doctor_attributes = Doctor.order(:id).limit(1).offset(offset).first.attributes
ActiveRecord::Base.remove_connection
This is followed by code for conforming doctor_params with new table structure. The code for creating an entry in new database is as under.
ActiveRecord::Base.establish_connection(new_database)
Doctor.create(doctor_params)
The issue is the Doctor object in the last line has attributes of the old database. Am I not handling database connections properly or is there another issue?
I tried the following
ActiveRecord::Base.establish_connection(old_db)
ActiveRecord::Base.establish_connection(new_db)
doctor = Doctor.new #Instance of doctor as per new database
But if I do
ActiveRecord::Base.establish_connection(old_db)
doctor = Doctor.new # instance of doctor as per old database
ActiveRecord::Base.establish_connection(new_db)
doctor = Doctor.new # Still instance of doctor as per new database
Somehow the Doctor model gets stuck with old database.
I solved the problem as under
require 'mysql2'
require 'active_record'
class ApplicationRecord < ActiveRecord::Base
self.abstract_class = true
end
class Doctor < ApplicationRecord
old_database = {
adapter: "mysql2",
host: "localhost",
username: "foo",
password: "bar",
database: "old_db"
}
establish_connection(old_database)
end
class NewDoctor < ApplicationRecord
new_database = {
adapter: "mysql2",
encoding: "utf8mb4",
collation: "utf8mb4_bin",
host: "localhost",
username: "foo",
password: "bar",
database: "new_db",
socket: "/var/run/mysqld/mysqld.sock"
}
self.table_name = 'doctors'
establish_connection(new_database)
end
It feels "hackey" and I am sure it is not efficient when dealing with large databases but it is a solution to my crisis situation. My database has around 8000 entries so I am not worried by efficiency consideration.
Try,
Doctor.establish_connection :new_database
Doctor.create doctor_params
with,
# config/database.yml
default: &default
adapter: mysql2
host: localhost
username: foo
password: bar
socket: /var/run/mysqld/mysqld.sock
old_database:
<<: *default
database: old_db
new_database:
<<: *default
database: new_db
encoding: utf8mb4
collation: utf8mb4_bin
There are many questions and answers regarding the creation of multiple connections to multiple databases in rails:
https://stackoverflow.com/a/7480330/2120023
https://stackoverflow.com/a/6305540/2120023
Example from outside stackoverflow: http://ilikestuffblog.com/2012/09/21/establishing-a-connection-to-a-non-default-database-in-rails-3-2-2/
But I have yet to find a solution that works when using a model that appears in both databases.
If my default db has a table titles and my Other db has a table titles how do I access the other database's Title model?
title.rb:
class Title < ActiveRecord::Base
end
othertitle.rb:
class Other < ActiveRecord::Base
self.abstract_class = true
establish_connection "other_#{Rails.env}"
end
class OtherTitle < Other
end
I can't use the above because I get this error (EDIT: for clarity there is no other_titles table in either db only a titles table -> EDIT 2: If I do create an other_titles table in the Other database, everything works perfectly but that does not help me access the titles table.):
ActiveRecord::StatementInvalid: Mysql2::Error: Table 'other.other_titles' doesn't exist: SHOW FULL FIELDS FROM `other_titles`
I also can't use class Title < Other because I get a TypeError: superclass mismatch for class Title error.
database.yml
development:
adapter: mysql2
encoding: utf8
database: db_dev
pool: 5
username: xxxx
password: xxxx
socket: /var/lib/mysql/mysql.sock
production:
adapter: mysql2
encoding: utf8
database: db
pool: 5
username: xxxx
password: xxxx
socket: /var/lib/mysql/mysql.sock
other_development:
adapter: mysql2
encoding: utf8
database: other_dev
pool: 5
username: xxxx
password: xxxx
socket: /var/lib/mysql/mysql.sock
other_production:
adapter: mysql2
encoding: utf8
database: other
pool: 5
username: xxxx
password: xxxx
socket: /var/lib/mysql/mysql.sock
I found the answer and it is quite simple:
class OtherTitle < Other
self.table_name='titles'
end
Referenced here:
Efficient way to pull data from second database?
and here:
Cannot connect to two postgres databases in rails 3.2.
I have a ruby on rails application working fine and connected to a database. Now i want to connect to a different database from the same application. The data model can be exactly the same. In fact if i connect to the different database the application works fine. However I want to connect to two different databases. Is it possible in ruby on rails?
For multiple database connection, you need to add the following codes to the database.yml file. Here, I am giving the example of connecting two databases from a rails application
config/database.yml
development:
adapter: mysql2
database: db1_dev
username: root
password: xyz
host: localhost
development_sec:
adapter: mysql2
database: db2_dev
username: root
password: xyz
host: localhost
production:
adapter: mysql2
database: db1_prod
username: root
password: xyz
host: your-production-ip
production_sec:
adapter: mysql2
database: db2_prod
username: root
password: xyz
host: your-production-ip
Here I have used two databases for the development and production environment.
Now we need to connect the model to databases. When you are running your application in development and production mode, all the models will be mapped through the development and production db parameters those been mentioned in your database.yml. So for some model we need to connect to other database.
Lets assume that, we have two models User and Category. The users table is in db1_dev and db1_prod, the categories table in db2_dev and db2_prod.
Category model
class Category < ActiveRecord::Base
establish_connection "#{Rails.env}_sec".to_sym
end
Similarly, when you adding the new migration for the second database, need to add following code to it.
class CreateRewards < ActiveRecord::Migration
def connection
ActiveRecord::Base.establish_connection("#{Rails.env}_sec".to_sym).connection
end
def change
# your code goes here.
end
end
Hope it will work for you :) .
Use establish_connection to switch to a different database:
ActiveRecord::Base.establish_connection(
:adapter => "mysql",
:host => "localhost",
:username => "myuser",
:password => "mypass",
:database => "somedatabase"
)
You can also pass a preconfigured environment from database.yml like so:
ActiveRecord::Base.establish_connection(ActiveRecord::Base.configurations['other_env'])
You can also set it for a specific model:
MyClass.establish_connection(...)
You might like to note that as of Rails 6 (2019), Rails has support for multiple primary databases!
https://guides.rubyonrails.org/active_record_multiple_databases.html
The database.yml file will now look something like this:
development:
primary:
database: primary_db
user: root
primary_replica:
database: primary_db
user: ro_user
replica: true
animals:
database: my_animals_db
user: root
migrations_path: db/animals_migrate
animals_replica:
database: my_animals_db
user: ro_user
replica: true
And then it's as simple as specifying in your model files:
class AnimalsModel < ApplicationRecord
self.abstract_class = true
connects_to database: { writing: :animals_primary, reading: :animals_replica }
end
class Dog < AnimalsModel
# connected to both the animals_primary db for writing and the animals_replica for reading
end
(These examples were taken from this helpful tutorial.)
My rails app has its own MySql database (and requires the mysql2 gem) but also needs to connect with an external MongoDB database for one particular model (and so I've included mongoid and bson_ext in the Gemfile). Now when I try to generate a migration for a new model, it tells me that
$ rails g migration CreateLocations
error mongoid [not found]
When I generated the Location model it included Mongoid::Document, so Rails obviously thinks it is using the external database as my primary datastore.
databse.yml:
development:
adapter: mysql2
encoding: utf8
reconnect: false
database: associalize_development
pool: 5
username: root
password:
socket: /tmp/mysql.sock
mongoid.yml:
development:
host: pearl.mongohq.com
port: 27019
username: asfasdf
password: sadfasdf
database: app4574678
test:
host: pearl.mongohq.com
port: 27019
username: asdfadhasdfa
password: hadsadfas
database: app4574678
production:
host: pearl.mongohq.com
port: 27019
username: asdfdfsasda
password: afdasdfdasdf
database: app4574678
UPDATE
Model that uses Mongo
class ExternalMongoModel
include Mongoid::Document
field :title
field :long_title
field :deal_type
field :merchandise_type
field :market_id
field :market_name
field :market_location, type: Array
field :featureType
field :country_code
field :subtitle
field :offer_ends_at
field :price
field :value
field :merchant_type
field :content
field :merchant
index(
[[:division_latlon, Mongo::GEO2D]], background: true
)
end
Add this to the Application block in config/application.rb:
config.generators do |g|
g.orm :active_record
end
(found here)
If you don't want to change the config/application.rb you could use this while generating the model:
rails generate active_record:migration
If you change the application.rb file, to invoke a mongoid generator, say for a model 'contacts', one would use:
rails g mongoid:model contacts
(solution link)
First check the below block is present in config/application.rb file in your rails application
config.generators do |g|
g.orm :active_record
end
If not add then, or else you can run
rails g active_record:migration
I have a Model (MessageImporter) that connects to a different Database than the other models using self.establish_connection. Everything works fine when I pass the connection info hardcoded. Now I need the connection to depend on the current environment. So I added the info to my application_config.yml (it's a simple nifty_config). I got stuck at how to pass the connection info to self.establish_connection.
Here's my current code:
class MessageImporter < ActiveRecord::Base
self.establish_connection lambda {{
:adapter => APP_CONFIG[:external_messages][:adapter],
:host => APP_CONFIG[:external_messages][:host],
:database => APP_CONFIG[:external_messages][:database],
:username => APP_CONFIG[:external_messages][:username],
:password => APP_CONFIG[:external_messages][:password]
}}
# […]
I get an undefined method 'symbolize_keys' for #<Proc:0x2564224>-. Error I also tried it without the lambda, but that does not work either and I get an even weirder error:
Please install the adapter: `gem install activerecord--adapter` (no such file to load -- active_record/connection_adapters/_adapter)
Or is there a better/Rails-ish way to set a different db-connection for individual models?
Little different approach and it works:
Adding the connection info to the regular database.yml:
development:
adapter: mysql
encoding: utf8
reconnect: false
database: […]
pool: 5
username: root
password:
socket: /tmp/mysql.sock
message_import:
adapter: mysql
encoding: utf8
username: […]
password: […]
database: […]
host: […]
Note the nesting! message_import ist nested beneath development.
Within the message_importer.rb:
class MessageImporter < ActiveRecord::Base
establish_connection configurations[RAILS_ENV]['message_import']
Still wondering why my first approach didn't work but this does just as expected.
According to the documentation, the establish_connection method accepts a hash as input. Did you try this?—
class MessageImporter < ActiveRecord::Base
establish_connection {
:adapter => APP_CONFIG[:external_messages][:adapter],
:host => APP_CONFIG[:external_messages][:host],
:database => APP_CONFIG[:external_messages][:database],
:username => APP_CONFIG[:external_messages][:username],
:password => APP_CONFIG[:external_messages][:password]
}