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.
Related
In an app I'm working on, the production database is Oracle and the development db is sqlite.
Most of the app code is high level ActiveRecord, but there is some custom sql for reporting. This sql varies depending on the backend db.
Rather than extending the ORM and adapters, or writing if statements throughout the application, is it possible to duck type the connection such that something like the below code is possible:
if Archive.connection.supports_function?("EXTRACT")
Archive.select("extract(year from created_at)")...
else
Archive.select("strftime('%Y', created_at)")...
end
I might be completely misunderstanding your requirement but you can check the adapter and change the code used for a method easily enough.
If you want to add a new extract method to activerecord that behaves in two ways for example:
# config/initializers/active_record_extract.rb
class ActiveRecord::Base
def self.extract_agnostic(oracle_column, default_column)
if ActiveRecord::Base.connection.instance_values["config"][:adapter].include?('oracle')
return self.select("extract(#{column1} from created_at)")...
end
self.select("strftime(#{default_column}, created_at)")...
end
end
# Usage:
Archive.extract_agnostic("year", "%Y")
Obviously this isn't perfect but should get you started?
I don't think rails can tell you if your adapter understands a command, but you could always try wrapping the command you want in a begin/rescue:
begin
self.select("extract(year from created_at)")...
rescue # the above failed, try something else
self.select("strftime('%Y', created_at)")...
end
Why can't you run an Oracle database for your development environment..? Scratch that - I don't want to know.
Use create_function to plug an extract() method into your SQLite:
http://rdoc.info/github/luislavena/sqlite3-ruby/SQLite3/Database#create_function-instance_method
(And good luck doing THAT in Oracle!;)
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
So I know how that this works like this
ActiveRecord::Base.connection_pool.with_connection do |conn|
conn.execute(sql)
end
but I'm trying to use the connection with actual Activerecord models, so something like
conn.Url.first
is there a way to do something like that?
Found out this isn't possible, but within the with_connection block any ActiveRecord calls should use the connection that is checked out from the Rails connection pool
so in this example
ActiveRecord::Base.connection_pool.with_connection do |conn|
Url.first
end
It should check out a connection from the pool set aside for Rails in your database.yml :pool setting, let your active record call use it and then check it back in
However, this only works in rails 3+ ... you can see the code change that makes this possible here
Rails 2.3 (old way) http://apidock.com/rails/v2.3.8/ActiveRecord/ConnectionAdapters/ConnectionPool/with_connection
Rails 3 http://apidock.com/rails/v3.0.0/ActiveRecord/ConnectionAdapters/ConnectionPool/with_connection
This guy explains the patch in this blog post
http://coderrr.wordpress.com/2009/05/05/activerecords-with_connection-is-now-useful/
I have a somewhat special use case, where I'd like to create a method that accepts a block, such that anything that happens inside that block is not written to the DB.
The obvious answer is to use transactions like so:
def no_db
ActiveRecord::Base.transaction do
yield
raise ActiveRecord::Rollback
end
end
But the trouble is that if my no_db method is used inside of another transaction block, then I'll ned up in the case of nested transactions. The drawback here is that nested transactions are only supported by MySQL, and I need support for PG, but more importantly SQLite (for tests). (I understand that PG is supported via savepoints, how reliable is that? performance hit?).
The other problem with this type of approach is that it seems really inefficient, writing things to a DB, and then rolling them back. It would be better if I could do something like this:
def no_db_2
# ActiveRecord::Base.turn_off_database
yield
# ActiveRecord::Base.turn_on_database
end
Is there such a method? Or a similar approach to what I'm looking for? I think it needs to be fairly low level..
(Rails version is 3.0.5, but I would be happy if there were an elegant solution for Rails 3.1)
This might be one way to do it:
class Book < ActiveRecord::Base
# the usual stuff
end
# Seems like a hack but you'll get the
# transaction behavior this way...
class ReadOnly < ActiveRecord::Base
establish_connection "#{Rails.env}_readonly"
end
I would think that this...
ReadOnly.transaction do
Book.delete_all
end
...should fail.
Finally, add another connection to config/database.yml
development:
username: fullaccess
development_readonly:
username: readonly
One downside is the lack of support for a read-only mode in the sqlite3-ruby driver. You'll notice that the mode parameter doesn't do anything yet according to the documentation. http://sqlite-ruby.rubyforge.org/classes/SQLite/Database.html#M000071
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.