Rails ActiveRecord mysql2 adapter, use PreparedStatement by default - ruby-on-rails

PreparedStatement support for mysql2 has been already added in version 0.4.0, as per this link
As per following details in version 0.5.2 it still not uses prepared statement in all ORM queries internally:
Shipment.where(order_id: 78987898789)<br>
Shipment.where('order_id = ?', 56789876)
Mysql Log:
2019-03-10T13:20:01.722848Z 1072 Query SELECT `shipments`.* FROM `shipments` WHERE `shipments`.`order_id` = 78987898789<br>
2019-03-10T13:22:27.748687Z 1072 Query SELECT `shipments`.* FROM `shipments` WHERE (order_id = 56789876)
Is there a way to enable/disable it for all ORM queries? (Just like the PostgreSQL adapter ref). Does enabling it impact adversely on overall application performance?
If not, I haven't given a try yet but is it possible to achieve this using Sequel, and how complex is migrating an existing application from MySQL2 to Sequel.

ActiveRecord with Mysql2 < 5, doesn't support configurable parameter to enable prepared_statement
Code snippet from ActiveRecord 4.2.6
connection_adapters/mysql2_adapter.rb
module ConnectionAdapters
class Mysql2Adapter < AbstractMysqlAdapter
ADAPTER_NAME = 'Mysql2'.freeze
def initialize(connection, logger, connection_options, config)
super
#prepared_statements = false # No configurable param, default set to false
configure_connection
end
...
end
ActiveRecord with Mysql2 = 5.2.1 adapter support configurable parameter to enable prepared_statement
Code snippet from ActiveRecord 5.2.1
connection_adapters/mysql2_adapter.rb
module ConnectionAdapters
class Mysql2Adapter < AbstractMysqlAdapter
ADAPTER_NAME = "Mysql2".freeze
include MySQL::DatabaseStatements
def initialize(connection, logger, connection_options, config)
super
#prepared_statements = false unless config.key?(:prepared_statements)
configure_connection
end
...
end
So, in ActiveRecord 5.2.1, one can just add following line in database.yml to enable prepared_statements
prepared_statements: true

Related

Rails 6.1 development environment not printing query trigger code line with verbose active

I have both lines:
# Highlight code that triggered database queries in logs.
config.active_record.verbose_query_logs = true
ActiveRecord::Base.verbose_query_logs = true
in my config/environments/development/rb
But in my development log the sql queries are logged like:
2022-08-10 08:35:18.536410 D [74:puma srv tp 004] (0.006ms) ActiveRecord -- Model Load -- { :sql => "SELECT ....", :binds => { .... }, :allocations => 1, :cached => true }
I have an N+1 queries issue to fix, but the information about which line in the code triggered the query is missing, so this is not helping me much.
I tried also using active-record-query-trace gem, with configuration:
if Rails.env.development?
ActiveRecordQueryTrace.enabled = true
ActiveRecordQueryTrace.level = :full
ActiveRecordQueryTrace.colorize = true # No colorization (default)
ActiveRecordQueryTrace.colorize = :light_purple
# Optional: other gem config options go here
end
but I see no changes at all in how queries are logged.
How can I enable the logging of the line triggering the query?
Thanks
If you want to know the reference point that made a DB query I used to use a gem called Marginalia. I use it in Rails 6 and it does exactaly what you are looking for.
From what I am reading Rails 7 includes this feature as a native feature (which is quite awesome I might add).
I found a link that talks about this:
Rails 7 includes Marginalia
Their example says:
# config/application.rb
module Saeloun
class Application < Rails::Application
config.active_record.query_log_tags_enabled = true
end
end

How to read ActiveRecord configuration from own gem?

I need to call "establish_connection" method from my own gem, but ActiveRecord::Base.configurations is [].
I made work around:
module Bitrix
class Database < ActiveRecord::Base
#config = YAML.load(File.read('config/database.yml'))
self.abstract_class = true
establish_connection #config["bitrix_#{Rails.env}"]
end
end
But why I can't access to AR config without opening file directly? I tried to use establish_connection :"bitrix_#{Rails.env}" and got this error:
/usr/local/var/rbenv/versions/2.1.3/lib/ruby/gems/2.1.0/gems/activerecord-4.1.4/lib/active_record/connection_adapters/connection_specification.rb:257:in `resolve_symbol_connection': 'bitrix_development' database is not configured. Available: [] (ActiveRecord::AdapterNotSpecified)
All config is available in:
Rails.application.config.database_configuration
So you'd have:
db_config = Rails.application.config.database_configuration
db_config['development']
Opening any file is not needed here. ActiveRecord needs however proper configuration to know how to connect to given database, e.g:
{"template"=>"template0", "adapter"=>"postgresql",
"encoding"=>"UTF8", "database"=>"database", "pool"=>50,
"username"=>"rails", "password"=>nil}
Loading database.yml parses yaml into hash with environment names as keys and their configurations as values.
config = YAML.load(File.read('config/database.yml'))
establish_connection config["bitrix_#{Rails.env}"]
returns more or less the same hash with adapter, user and password which are essential to connect to database.

ActiveSupport encode_big_decimal_as_string

I would like to use the ActiveSupport option encode_big_decimal_as_string on one of my models. Should I put it in the model? Do I call this method on a model instance? Do I place this somewhere in config? What is an ActiveSupport option and how could I use it?
Neither of these answers worked for me in Rails 4.0. Here is what works in Rails 4.0:
ActiveSupport::JSON::Encoding.encode_big_decimal_as_string = false
Add that line to your application config, like so:
# config/application.rb
...
module AppName
class Application < Rails::Application
...
ActiveSupport::JSON::Encoding.encode_big_decimal_as_string = false
...
end
end
As #tyler-nguyen said, this is being deprecated in Rails 4.1, and extracted into this gem: ActiveSupport JSON Encoder. Refer to the gem documentation for configuration in 4.1.
In Rails 4.0, you can set it in your application.rb as following:
config.active_support.encode_big_decimal_as_string = false
From Rails 4.1, the ActiveSupport.encode_big_decimal_as_string option is deprecated. The feature has been extracted to the activesupport-json_encoder gem.
I believe that you do it in the environment.rb file.
This is what should work. I don't have a way to test it right now.
Rails::Initializer.run do |config|
config.active_support.json.encode_big_decimal_as_string = true
end

Can't Rails 3 run in MySQL MyISAM mode, without InnoDB?

I have a MySQL server running with InnoDB disabled (for reasons of performance), with this setup I can't seem to be able to use Rails 3 (with the mysql2 adapter).
Here's my test migration:
class CreateTxts < ActiveRecord::Migration
def change
create_table(:txts, :options => 'ENGINE=MyISAM') do |t|
t.timestamps
end
end
end
And here's the error:
>rake db:migrate
rake aborted!
Mysql2::Error: Unknown storage engine 'InnoDB': CREATE TABLE `schema_migrations`
(`version` varchar(255) NOT NULL) ENGINE=InnoDB
Tried the workaround described here, but it doesn't seem to work either (I did modify MysqlAdapter to Mysql2Adapter to match my setup).
Sorry I'm a newb in Rails. Any help will be much appreciated :o
Going to answer my own question. Here's a patch for environment.rb I ended up with that works with the native mysql driver as well as JRuby/JDBC-mysql:
# Load the rails application
require File.expand_path('../application', __FILE__)
# Patch Mysql adapter to default to MyISAM instead of InnoDB
require 'active_record/connection_adapters/mysql_adapter'
module ActiveRecord
module ConnectionAdapters
class MysqlAdapter
def create_table(table_name, options = {}) #:nodoc:
super(table_name, options.reverse_merge(:options => "ENGINE=MyISAM"))
end
end
end
end
# Initialize the rails application
.....
rake db:migrate now succeeds and creates all tables including schema_migrations with TYPE=MyISAM.
Note: For mysql2 adapter, rename mysql_adapter to mysql2_adapter and MysqlAdapter to Mysql2Adapter.
Try creating the table without specifying the type of engine being used like this
class CreateTxts < ActiveRecord::Migration
def change
create_table(:txts) do |t|
t.timestamps
end
end
end
and then in mysql cli, type this
ALTER TABLE txts ENGINE = MYISAM
hope it helps
The error is coming from creating the schema_migrations table (which rails uses to track which migrations have been run) rather than your table. You could create that table yourself (with a single varchar(255) column called version with an index on it).
If you do end up overwriting the create_table method, you need to preserve the method's signature - you're ignoring the block that it yields. I'd try something like
def create_table(name, options={})
super(name, options.merge(...)) {|t| yield t}
end
#rustyx nice one! &here's my slightly tweaked monkey-patch so the engine can be set from within the /config/database.yml configuration:
&Rather than in /config/environment.rb, i put the codes into an initializer, Eg: /config/initializers/mysql2adapter_default_engine.rb.
Either this for brevity:
require 'active_record/connection_adapters/abstract_mysql_adapter'
class ActiveRecord::ConnectionAdapters::Mysql2Adapter < ActiveRecord::ConnectionAdapters::AbstractMysqlAdapter
def create_table(table_name, options = {}) #:nodoc:
super(table_name, #config[:engine].nil? ? options : options.reverse_merge(:options => "ENGINE="+#config[:engine]))
end
end
or this for more clarity:
require 'active_record/connection_adapters/abstract_mysql_adapter'
module ActiveRecord
module ConnectionAdapters
class Mysql2Adapter < AbstractMysqlAdapter
def create_table(table_name, options = {}) #:nodoc:
super(table_name, #config[:engine].nil? ? options : options.reverse_merge(:options => "ENGINE="+#config[:engine]))
end
end
end
end
Then in /config/database.yml we can have something like this:
production:
adapter: mysql2
encoding: utf8
database: ooook
username: ooook
password: ooook
host: ooook.tld
port: 3306
pool: 5
timeout: 5000
engine: MyISAM
If no engine is specified then the mysql2 adapter will use the default (InnoDB or whatever).

Rails - generating .sqlite3-databases

My rails app. uses mysql database and I need to generate .sqlite3.databases. Is it possible to use activerecord and rails models for it?
We are trying now to use models namespaced by Remote:: module but by this way we can't start concurrent generators.
In your remote models, you want to connect to a separate database using #establish_connection:
# config/database.yml
remote_development:
adapter: sqlite3
database: db/development.sqlite3
remote_production:
adapter: sqlite3
database: /usr/local/remote/myapp.sqlite3
# app/models/remote_model.rb
class RemoteModel < ActiveRecord::Base
establish_connection "remote_#{Rails.env}"
self.abstract_class = true
end
# app/models/remote_user.rb
class RemoteUser < RemoteModel
end
Note the abstract_class setter: this means the class in question doesn't have an underlying table: it's used for configuration purposes only.

Resources