Is there a way of setting the database name dynamically (coming originally from database.yml), ideally using part of the application pathname?
Background of the question is, I have a single source code that shall run on one and the same server multiple times but each instance of the application should have a different database.
Example, I have an auction site which works with the currency USD. Now I want to run the same auction site again (one the same server) for a second currency. For valid reasons I don't want to make the application multi-currency capable, I'ld like to keep the source code as is.
Setting up the application on the same server using sub-URL I will follow this approach:
http://www.modrails.com/documentation/Users%20guide%20Apache.html#deploying_rack_to_sub_uri
The question left is, how does each instance of the application get its own DB name, e.g. the one instance uses the database name production_USD and the otherone uses production_CAD
Edit: The solution works like a charm, thanks to the feedback received:
My folder structure on the server is
/var/www/auction/USD-US Dollar
/var/www/auction/CAD-Canadian Dollar
/var/www/auction/source
/var/www/logs
With the source folder containing the original source code and the USD and CAD being links to the source (no actual need for copying any code anywhere other than placing it into source.
Next to set the DB dynamically. The currency is determined automatically by looking
at the folder name. I put it into the application.rb as I need it to
in an early stage because I also want different log files for the different currencies.
I am storing the log files outside of the source folder to make sure I don't loose them
when the source folder gets refreshed from the QA system
Here the code changes:
application.rb:
fname = File.basename(File.expand_path('../../', __FILE__))
curr = fname.split("-")
if curr[1].nil?
CURR_SHORT = "XXX"
CURR_LONG = "XXX"
else
CURR_SHORT = curr[0]
CURR_LONG = curr[1]
end
dbname = "myapp_#{CURR_SHORT}_#{Rails.env[0..2]}"
ActiveRecord::Base.establish_connection(
:adapter => "sqlite3",
:host => "localhost",
:username => "myuser",
:password => "mypass",
:database => dbname
)
module Virex
class Application < Rails::Application
config.logger = ActiveSupport::BufferedLogger.new("../logs/#{Rails.env}.#{CURR_SHORT}.log")
....
Of course, have a look at ActiveRecord::Base.establish_connection :
ActiveRecord::Base.establish_connection(
:adapter => "mysql",
:host => "localhost",
:username => "myuser",
:password => "mypass",
:database => "somedatabase"
)
You can put this piece of code in an initializer, with the database name you want, depending on your pathname.
Complete doc here
Related
The Problem:
I have a rails app that requires a user to upload some type of spreadsheet (csv, xslx, xsl etc) for processing which can be a costly operation so we've decided to send it off to a background service as a solution to this problem. The issue we're concerned about is that because our production system is on Heroku we need to store the file on AS3 first then retrieve later for processing.
Because uploading the file to AS3 is in itself a costly operation, this should probably also be done as a background job. The problem is the concern that using Resque to do this could eat up a lot of RAM due to Resque needing to put the file data into Redis or later retrieval. As you know, Redis only stores its data in RAM and also prefers simple key value pairs so we would like to try and avoid this.
Heres some pseudocode as an example of what we'd like try and do:
workers/AS3Uploader.rb
require 'fog'
class AS3Uploader
#queue = :as3_uploader
def self.perform(some, file, data)
# create a connection
connection = Fog::Storage.new({
:provider => 'AWS',
:aws_access_key_id => APP_CONFIG['s3_key'],
:aws_secret_access_key => APP_CONFIG['s3_secret']
})
# First, a place to contain the glorious details
directory = connection.directories.create(
:key => "catalog-#{Time.now.to_i}", # globally unique name
:public => true
)
# list directories
p connection.directories
# upload that catalog
file = directory.files.create(
:key => 'catalog.xml',
:body => File.open(blah), # not sure how to get file data here with out putting it into RAM first using Resque/Redis
:public => true
end
# make a call to Enqueue the processing of the catalog
Resque.enqueue(CatalogProcessor, some, parameters, here)
end
controllers/catalog_upload_controller.rb
def create
# process params
# call Enqueue to start the file processing
# What do I do here? I could send all of the file data here right now
# but like I said previously that means storing potentially 100s of MB into RAM
Resque.enqueue(AS3Uploader, some, parameters, here)
end
The way I would suggest you to do would be
store your file in tmp dir you create and get the file-path
tell Resque to upload the file by using the file-path
make Resque to store the file-path in the redis not the whole file-content ( It would be very expensive )
Now worker will upload the file to AWS- S3
Note: If you have multiple instances like One instance for background processing, One for database, One as utility instance then your tmp dir may not be available to other instances.. so store the file in the temp dir inside the instance holding the resque
I'm trying to figure out how to pull data from a database without the need to place a connection string at the top of each ruby file.
I'm learning the basics of ruby via a little Sinatra app I'm putting together which pulls data from a MSSQL database.
So far I've managed to create various simple erb pages that display data from the MSSQL database by using the following code structure at the top of each file:-
<% client = TinyTds::Client.new(:username => 'name', :password => 'password', :dataserver => 'hostname', :database => 'database') %>
<% data = client.execute("SELECT * from tablename") %>
From the books, guides and online tutorials I've found based on lots of configs to do with PostgreSQL or MySQL databases it seems to me I need to be creating a central file to store my connection data (such as a database.yml file) and then referencing that somewhere/somehow in my app.
Would that be correct, and should I be doing that in my main.rb file so that each of my .erb files do not require the connection string or do I have to still refer to the database in each .erb file also?
I've noted references to creating database config variables such as:-
db_config = YAML.load(File.Open("/path_to_file/database.yml")) [ENV['RAILS_ENV']]
but that clearly seems suited to Rails apps.
Could I do something similar for my sinatra driven 'app'?
Thanks.
This should work:
require "sinatra"
require "sinatra/config_file"
config_file 'path/to/config.yml'
DB = TinyTds::Client.new(
:username => settings.name,
:password => settings.password,
:dataserver => settings.hostname,
:database => settings.database
)
get '/' do
#result = DB.do_stuff
haml :index
end
What I would suggest though, is that you look for an ORM that supports TinyTDS and use that to set up the database connection and run queries. I use Sequel a lot and I know it supports TinyTDS, but I'm sure others do too.
I'd also suggest not putting things like database settings in a file that gets checked in to source control, as it's sensitive information. I prefer to put this kind of thing into environment variables for production, and use a config file to load the environment variables in development (for convenience). Using the above example:
DB = TinyTds::Client.new(
:username => ENV["name"],
:password => ENV["password"],
:dataserver => ENV["hostname"],
:database => ENV["database"]
)
Those env variables are loaded into the production server's memory, which makes them a little bit more secure. For development, I load YAML files before starting up Sinatra, adding each value to an ENV var. I'm not suggesting this is a standard way, but it's how I do it.
Is it possible to obtain details about a schema and get the table objects using a stand alone active record connection. I am trying to do something like this
require'rubygems'
gem 'activerecord'
require 'activerecord'
ActiveRecord::Base.establish_connection(
:adapter => "mysql",
:host => "localhost",
:username => "root",
:database => "test_database"
)
Is it possible to access the tables of the db using this connection object.
Yes, it is perfectly possible to use ActiveRecord without Rails.
You can also use standalone_migrations gem to manage ActiveRecord environment outside of Rails: https://github.com/thuss/standalone-migrations.
Have you try to load all Active Support?
In order to have a near-zero default footprint, Active Support does not load anything by default. It is broken in small pieces so that you can load just what you need
require 'active_support/all'
Active Support Core Extensions
I'm starting a new Rails 3 app from scratch.
And as I was going through basic setup ( configuring gems, sessions, etc) I ran into something that has been nagging me for a while.
Our current system ( a mixture of Ruby scripts & Rails 2 app) send various email / fax notifications to clients. There are certain things that are common in 80% of cases - cc - certain email accounts on our end and email signature.
Previously I just defined GLOBALS in the environment.rb such as
SYSTEM_EMAIL_SIGNATURE
or
SYSTEM_EMAIL_NOTIFY
and used them later in mailers or if it was a stand-alone script I had a setup.rb file - that had a bunch of common settings - including a has with custom email settings like this.
Since I'm rebuilding this app from scratch and consolidating all scripts into one ruby app - I was trying to think of a better way to do this.
Right now I'm setting up an email.rb Initializer that has action_mailer settings, that I extended by adding a few more items:
########## Setup Global Email Defaults ##############
Site::Application.configure do
config.action_mailer.raise_delivery_errors = true
config.action_mailer.delivery_method = :smtp
config.action_mailer.smtp_settings = {
:address => 'mail.example.com',
:port => 25,
:domain => 'example.com',
# These are custom to OUR setup - used later in the code
:default_from => 'it.systems#example.com',
:default_notify => ["it.manager#example.com"],
:default_signature => "
---------------------------
This is an automatic email.
If you have any questions please contact customer service
at 1 (800) 888-0000 or go to http://www.example.com.
Thank you for your business!"
}
end
So is this a good approach? Or is there a better way then these two approaches?
I think you're on the right track for default_from and default_notify.
I wouldn't use SMTP settings for that; those aren't SMTP settings, they're just general mailer settings.
I'd go with something like this in an initializer:
MAILER_SETTINGS = YAML::load(open(File.join(Rails.root, "config", "mailer.yml")).read)[Rails.env]
With a yaml file that looks like this:
development: &development
default_from: foo#bar.com
default_notify: ["foo#bar.com"]
production:
<<: *development
default_from: production#bar.com
That lets you set defaults, then cascade them down and override per-environment as desired.
However, for the signature, I'd just move that into a partial, which you then include in your mail templates. They're views like any other and can have layouts, partials, and all of that.
I have several api's that I am integrating with and need to call in various parts of my application.
What is the way to store the keys, the user/password, or token information, say, a configuration file and then how do I call them for use in other parts of the application?
Thanks.
Just to keep this question up-to-date, there is a new way to do this in Rails 4.1:
From the Rails guides:
Rails 4.1 generates a new secrets.yml file in the config folder. By default, this file contains the application's secret_key_base, but it could also be used to store other secrets such as access keys for external APIs.
You can store usernames/passwords and similar configuration information in mechanisms that rails already uses; you can either stuff the configuration data right into your environment configuration files (where production, testing, and development are configured), or you could use your own mechanism and:
require "yaml"
config_hash = YAML::load_file("/path/to/your/config.yaml")
Easiest is to store the info as constants in your various environment files. That way you can use different accounts for development, production, etc.
# Eg
# development/environment.rb
....
API_1_USER = "user101"
API_1_PW = "secret!"
Alternative is to create a yaml file, then read it when your app signs in to an api. This is the style used by rails itself with the config/databse.yml file
ADDED
You can also store as a constant using a hash or nested hash.
# Eg
# development/environment.rb
....
API_1 = {"user" => "user101", "pw" => "secret!"}
API_2 = {"user" => "user102", "pw" => "double_secret"}
# or nested hashes
API_KEYS = {
"api_1" => {"user" => "user101", "pw" => "secret!"},
"api_2" => {"user" => "user102", "pw" => "double_secret"}}
# using them in another file:
foo.signin(API_1['user'], API_1['pw'])
# or
foo.signin(API_KEYS["api_1"]['user'], API_KEYS["api_1"]['pw'])
# note, I use string constants instead of symbols to save vm (since the hash is
# not referenced more than once or twice). You could also use
# symbols as the keys, especially if the hash will be referenced often:
API_1 = {:user => "user101", :pw => "secret!"}
Check out Configatron, it's pretty awesome and can be used exactly for this purpose.