I wanted to know how ActiveRecord::Base.connection.execute method is defined.
So I've checked source code but I couldn't understand what is going on.
# Executes the SQL statement in the context of this connection.
def execute(sql, name = nil)
end
undef_method :execute
https://github.com/rails/rails/blob/c13284131511fb7871a85659dd0b5e821d9ad29b/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb#L55
Perhaps the method is defined another place dynamically.
How can I find place where the method is described?
The method you show is defined in the module DatabaseStatements which is included into the class AbstractAdapter (connection_adapters/abstract_adapter.rb).
AbstractAdapter simply serves as a base class for the various specialised database adapters for the different database servers Rails interoperates with; it's not intended to be instantiated on its own. For instance, the definition of execute for PostgreSQL databases is in postgresql/database_statements.rb, as part of class PostgreSQLAdapter < AbstractAdapter.
They are defined in respective adapters.
The adapters are in the following directory names as *_adapter.rb:
activerecord-x.x.x/lib/active_record/connection_adapters/
You can see the the definition of the execute method inside those files. like: mysql_adapter.rb, postgresql_adapter.rb etc.
To know how ActiveRecord::Base.connection.execute method is defined you should look in the connection adapter class you're using.
For instance, in case you're using mysql db (via mysql2 gem) you'll find the execute method definition you're using here:
activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb#206
Related
I'd like my Rails app to run a raw sql command after it establishes the connection to the DB. In which file does that belong? One of the config/initializers?
I use monkeypatching to force strict mode for MySQL, the same approach should also work in your case. This code belongs in an initializer.
class ActiveRecord::ConnectionAdapters::Mysql2Adapter
private
alias_method :configure_connection_without_autocommit, :configure_connection
def configure_connection
configure_connection_without_autocommit
execute "COMMAND_TO_ENABLE_AUTOCOMMIT"
end
end
For reference, here's the source code for Mysql2Adapter.
I think You can write a rake filter, through which you can fire a query before each inbound call. You can read more about this here.
When working with ruby on rails, it is common to use terminal commands like rake db:migrate or rails g devise:install. But what exactly does the : in these commands mean? In rake db:migrate is migrate a parameter or something else?
You can think of the colon as a namespace. Somewhere within Rails there is a rake task file that looks similar to this:
namespace db
task :migrate do...
....
end
end
It's a way to group related tasks together and prevent them from colliding with other tasks. This way you could potentially have devise:migrate, db:migrate, foobar:migrate, etc.
Like Philip explained in his answer when using rake the colon defines the seperator between namespaces/tasks
When using rails g(enerate) it's basically the same. The difference is that Rails generators aren't defined with rake's DSL, instead they're classes.
But to answer your initial Questions: The Colon works as seperator, in both cases, that's it.
In the code the only thing what it's important for is splitting up the string:
https://github.com/rails/rails/blob/4-0-stable/railties/lib/rails/generators.rb#L124
You can find some more infos about generators and how to create your one ones (which definetley will help you understanding the mechanics behind it) in the official Ruby on Rails Guides
//EDIT
Ok, let's take a closer look at the generator lookup process:
First of all there is Rails::Generators.invoke
It receives the namespaces passed on the CLI and split's it up (using the colon)
names = namespace.to_s.split(':')
then it get's the according class by passing the last part of the passed namespace (the actual generator name) and the remaining part joined with a colon again (the namespace path, in our case it's devise) to Rails::Generators::Base.find_by_namespace
if klass = find_by_namespace(names.pop, names.any? && names.join(':'))
This method again will join the base (namespace path) and name (generator name) and push it to an array:
lookups = []
lookups << "#{base}:#{name}" if base
after that it calls Rails::Generators.lookup which will lookup the classes to invoke for the called generator:
lookup(lookups)
which will again will call Rails::Generators.namepaces_to_paths
There's no big magic in that method, it'll simply return an array of two possible source paths for the invoked generator in our case these two are "devise/install/install" and "devise/install".
Whereby those aren't the actual paths rails will check, they are only the part's of it that are depend on the namespace:generator construct.
The lookup method will now take those two, let's call them subpaths, and check for files to require at the following places:
rails/generators/devise/install/install_generator
generators/devise/install/install_generator
rails/generators/devise/install_generator
generators/devise/install_generator
in our case the second path is the desired file, rails require's it and through that the inherited (more about that callback callback on Rails::Generators::Base will get called since Devise::Generators::InstallGenerator inherits from it.
This will add the Class to the subclasses array of Rails::Generators which is mapped to an Hash which will have the format { namespace => klass } and so rails is finally able to get the desired Generator Class
klass = namespaces[namespace]
and start it
klass.start(args, config)
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.
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
I need to run an oracle script after connect to oracle database using ActiveRecord.
I know that exists the initializers, but these run only in the application's start. I need a point to write a code that runs after every new database connection be established.
This is needed to initialize some oracle environments variables shared with others applications that uses the same legacy database.
Any ideas?
Thanks in advance.
I found the solution:
Create the file /config/initializers/oracle.rb and put into it this code:
ActiveRecord::ConnectionAdapters::ConnectionPool.class_eval do
def new_connection_with_initialization
result = new_connection_without_initialization
result.execute('begin Base_Pck.ConfigSession; end;')
result
end
alias_method_chain :new_connection, :initialization
end
The alias_method_chain allows you to change a method (new_connection) without override it, but extending it.
Then we need only to change the script into the result.execute call.