Module: Hijacker
- Defined in:
- lib/hijacker.rb,
lib/hijacker/alias.rb,
lib/hijacker/middleware.rb
Defined Under Namespace
Modules: ControllerMethods Classes: Alias, Database, InvalidDatabase, Middleware, UnparseableURL
Class Attribute Summary collapse
-
.config ⇒ Object
Returns the value of attribute config.
-
.master ⇒ Object
Returns the value of attribute master.
-
.sister ⇒ Object
Returns the value of attribute sister.
- .valid_routes ⇒ Object
Class Method Summary collapse
-
.check_connection ⇒ Object
just calling establish_connection doesn’t actually check to see if we’ve established a VALID connection.
-
.connect(target_name, sister_name = nil, options = {}) ⇒ Object
Manually establishes a new connection to the database.
-
.connect_sister_site_models(db) ⇒ Object
very small chance this will raise, but if it does, we will still handle it the same as
Hijacker.connect
so we don’t lock up the app. - .connect_to_master(db_name) ⇒ Object
- .current_client ⇒ Object
- .do_hijacking? ⇒ Boolean
-
.establish_root_connection ⇒ Object
this should establish a connection to a database containing the bare minimum for loading the app, usually a sessions table if using sql-based sessions.
- .processing_sister_site? ⇒ Boolean
- .root_config ⇒ Object
-
.root_connection ⇒ Object
maintains and returns a connection to the “dummy” database.
-
.temporary_sister_connect(db, &block) ⇒ Object
connects the sister_site_models to
db
while calling the block ifdb
and self.master differ. - .test? ⇒ Boolean
Class Attribute Details
.config ⇒ Object
Returns the value of attribute config.
10 11 12 |
# File 'lib/hijacker.rb', line 10 def config @config end |
.master ⇒ Object
Returns the value of attribute master.
10 11 12 |
# File 'lib/hijacker.rb', line 10 def master @master end |
.sister ⇒ Object
Returns the value of attribute sister.
10 11 12 |
# File 'lib/hijacker.rb', line 10 def sister @sister end |
.valid_routes ⇒ Object
14 15 16 |
# File 'lib/hijacker.rb', line 14 def self.valid_routes @valid_routes ||= {} end |
Class Method Details
.check_connection ⇒ Object
just calling establish_connection doesn’t actually check to see if we’ve established a VALID connection. a call to connection will check this, and throw an error if the connection’s invalid. It is important to catch the error and reconnect to a known valid database or rails will get stuck. This is because once we establish a connection to an invalid database, the next request will do a courteousy touch to the invalid database before reaching establish_connection and throw an error, preventing us from retrying to establish a valid connection and effectively locking us out of the app.
164 165 166 |
# File 'lib/hijacker.rb', line 164 def self.check_connection ::ActiveRecord::Base.connection end |
.connect(target_name, sister_name = nil, options = {}) ⇒ Object
Manually establishes a new connection to the database.
Background: every time rails gets information from the database, it uses the last established connection. So, although we’ve already established a connection to a “dummy” db (“crystal”, in this case), if we establish a new connection, all subsequent database calls will use these settings instead (well, until it’s called again when it gets another request).
Note that you can manually call this from script/console (or wherever) to connect to the database you want, ex Hijacker.connect(“database”)
33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 |
# File 'lib/hijacker.rb', line 33 def self.connect(target_name, sister_name = nil, = {}) raise InvalidDatabase, 'master cannot be nil' if target_name.nil? target_name = target_name.downcase sister_name = sister_name.downcase unless sister_name.nil? return if already_connected?(target_name, sister_name) || test? verify = .fetch(:verify, Hijacker.do_hijacking?) db_name = determine_database_name(target_name, sister_name, verify) establish_connection_to_database(db_name) check_connection self.master = db_name self.sister = sister_name # don't cache sister site cache_database_route(target_name, db_name) unless sister_name connect_sister_site_models(target_name) reenable_query_caching self.config[:after_hijack].call if self.config[:after_hijack] rescue self.establish_root_connection raise end |
.connect_sister_site_models(db) ⇒ Object
very small chance this will raise, but if it does, we will still handle it the same as Hijacker.connect
so we don’t lock up the app.
Also note that sister site models share a connection via minor management of AR’s connection_pool stuff, and will use ActiveRecord::Base.connection_pool if we’re not in a sister-site situation
71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 |
# File 'lib/hijacker.rb', line 71 def self.connect_sister_site_models(db) return if db.nil? sister_db_connection_pool = self.processing_sister_site? ? nil : ActiveRecord::Base.connection_pool self.config[:sister_site_models].each do |model_name| ar_model = model_name.constantize if !sister_db_connection_pool ar_model.establish_connection(self.root_connection.config.merge(:database => db)) begin ar_model.connection rescue ar_model.establish_connection(self.root_connection.config) raise Hijacker::InvalidDatabase, db end sister_db_connection_pool = ar_model.connection_pool else ActiveRecord::Base.connection_handler.connection_pools[model_name] = sister_db_connection_pool end end end |
.connect_to_master(db_name) ⇒ Object
18 19 20 |
# File 'lib/hijacker.rb', line 18 def self.connect_to_master(db_name) connect(*Hijacker::Database.find_master_and_sister_for(db_name)) end |
.current_client ⇒ Object
146 147 148 |
# File 'lib/hijacker.rb', line 146 def self.current_client sister || master end |
.do_hijacking? ⇒ Boolean
150 151 152 153 |
# File 'lib/hijacker.rb', line 150 def self.do_hijacking? (Hijacker.config[:hosted_environments] || %w[staging production]). include?(ENV['RAILS_ENV']) end |
.establish_root_connection ⇒ Object
this should establish a connection to a database containing the bare minimum for loading the app, usually a sessions table if using sql-based sessions.
134 135 136 |
# File 'lib/hijacker.rb', line 134 def self.establish_root_connection ActiveRecord::Base.establish_connection('root') end |
.processing_sister_site? ⇒ Boolean
138 139 140 |
# File 'lib/hijacker.rb', line 138 def self.processing_sister_site? !sister.nil? end |
.root_config ⇒ Object
128 129 130 |
# File 'lib/hijacker.rb', line 128 def self.root_config ActiveRecord::Base.configurations['root'] end |
.root_connection ⇒ Object
maintains and returns a connection to the “dummy” database.
The advantage of using this over just calling ActiveRecord::Base.establish_connection (without arguments) to reconnect to the dummy database is that reusing the same connection greatly reduces context switching overhead etc involved with establishing a connection to the database. It may seem trivial, but it actually seems to speed things up by ~ 1/3 for already fast requests (probably less noticeable on slower pages).
Note: does not hijack, just returns the root connection (i.e. AR::Base will maintain its connection)
117 118 119 120 121 122 123 124 125 126 |
# File 'lib/hijacker.rb', line 117 def self.root_connection unless $hijacker_root_connection current_config = ActiveRecord::Base.connection.config ActiveRecord::Base.establish_connection('root') # establish with defaults $hijacker_root_connection = ActiveRecord::Base.connection ActiveRecord::Base.establish_connection(current_config) # reconnect, we don't intend to hijack end return $hijacker_root_connection end |
.temporary_sister_connect(db, &block) ⇒ Object
connects the sister_site_models to db
while calling the block if db
and self.master differ
95 96 97 98 99 100 101 102 103 |
# File 'lib/hijacker.rb', line 95 def self.temporary_sister_connect(db, &block) processing_sister_site = (db != self.master && db != self.sister) self.sister = db if processing_sister_site self.connect_sister_site_models(db) if processing_sister_site result = block.call self.connect_sister_site_models(self.master) if processing_sister_site self.sister = nil if processing_sister_site return result end |
.test? ⇒ Boolean
168 169 170 |
# File 'lib/hijacker.rb', line 168 def self.test? ['test', 'cucumber'].include?(RAILS_ENV) end |