aboutsummaryrefslogtreecommitdiffstats
path: root/activerecord/lib/active_record/core.rb
Commit message (Collapse)AuthorAgeFilesLines
* Make connection handler per thread instead of per fiberEileen Uchitelle2018-11-201-2/+2
| | | | | | | | | | | | | | | The connection handler was using the RuntimeRegistry which kind of implies it's a per thread registry. But it's actually per fiber. If you have an application that uses fibers and you're using multiple databases, when you switch the connection handler to swap connections new fibers running on the same thread used to get a different connection id. This PR changes the code to actually use a thread so that we get the same connection. Fixes https://github.com/rails/rails/issues/30047 [Eileen M. Uchitelle, Aaron Patterson, & Arthur Neeves]
* Fix inspect with non-primary key id attributeEugene Kenny2018-11-061-2/+2
| | | | | | | | | | | The `read_attribute` method always returns the primary key when asked to read the `id` attribute, even if the primary key isn't named `id`, and even if another attribute named `id` exists. For the `inspect`, `attribute_for_inspect` and `pretty_print` methods, this behaviour is undesirable, as they're used to examine the internal state of the record. By using `_read_attribute` instead, we'll get the real value of the `id` attribute.
* Merge pull request #34208 from yskkin/inspect_with_parameter_filterRyuta Kamizono2018-10-261-19/+22
|\ | | | | Implement AR#inspect using ParameterFilter
| * Implement AR#inspect using ParamterFilter.Yoshiyuki Kinjo2018-10-191-19/+22
| | | | | | | | | | | | | | | | | | AR instance support `filter_parameters` since #33756. Though Regex or Proc is valid as `filter_parameters`, they are not supported as AR#inspect. I also add :mask option and #filter_params to `ActiveSupport::ParameterFilter#new` to implement this.
* | Consolidate duplicated code that initializing an empty model objectRyuta Kamizono2018-10-171-19/+7
|/ | | | | | | | | | | | | `init_with` and `init_from_db` are almost the same code except decode `coder`. And also, named `init_from_db` is a little misreading, a raw values hash from the database is already converted to an attributes object by `attributes_builder.build_from_database`, so passed `attributes` in that method is just an attributes object. I renamed that method to `init_with_attributes` since the method is shared with `init_with` to initialize an empty model object.
* Basic API for connection switchingEileen Uchitelle2018-10-101-0/+3
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | This PR adds the ability to 1) connect to multiple databases in a model, and 2) switch between those connections using a block. To connect a model to a set of databases for writing and reading use the following API. This API supercedes `establish_connection`. The `writing` and `reading` keys represent handler / role names and `animals` and `animals_replica` represents the database key to look up the configuration hash from. ``` class AnimalsBase < ApplicationRecord connects_to database: { writing: :animals, reading: :animals_replica } end ``` Inside the application - outside the model declaration - we can switch connections with a block call to `connected_to`. If we want to connect to a db that isn't default (ie readonly_slow) we can connect like this: Outside the model we may want to connect to a new database (one that is not in the default writing/reading set) - for example a slow replica for making slow queries. To do this we have the `connected_to` method that takes a `database` hash that matches the signature of `connects_to`. The `connected_to` method also takes a block. ``` AcitveRecord::Base.connected_to(database: { slow_readonly: :primary_replica_slow }) do ModelInPrimary.do_something_thats_slow end ``` For models that are already loaded and connections that are already connected, `connected_to` doesn't need to pass in a `database` because you may want to run queries against multiple databases using a specific role/handler. In this case `connected_to` can take a `role` and use that to swap on the connection passed. This simplies queries - and matches how we do it in GitHub. Once you're connected to the database you don't need to re-connect, we assume the connection is in the pool and simply pass the handler we'd like to swap on. ``` ActiveRecord::Base.connected_to(role: :reading) do Dog.read_something_from_dog ModelInPrimary.do_something_from_model_in_primary end ```
* Add mention about `ActiveRecord::Base::filter_attributes` to the changelog entrybogdanvlviv2018-09-121-6/+6
| | | | | Also remove `# :nodoc:` for `ActiveRecord::Core::ClassMethods` in order to show non-nodoc methods in that module on the api docs http://edgeapi.rubyonrails.org
* Build string set when `filter_attributes` is assignedbogdanvlviv2018-09-121-6/+17
| | | | | | | | | It would allow `filter_attributes` to be reused across multiple calls to `#inspect` or `#pretty_print`. - Add `require "set"` - Remove `filter_attributes` instance reader. I think there is no need to keep it.
* DRY `activerecord/lib/active_record/core.rb` and fix testsbogdanvlviv2018-09-121-6/+9
| | | | | | | | | | | | | | | | | | | - Move ``` filter_attributes = self.filter_attributes.map(&:to_s).to_set filter_attributes.include?(attribute_name) && !read_attribute(attribute_name).nil? ``` to private method. - Fix tests in `activerecord/test/cases/filter_attributes_test.rb` - Ensure that `teardown` sets `ActiveRecord::Base.filter_attributes` to previous state. - Ensure that `Admin::Account.filter_attributes` is set to previous state in the "filter_attributes could be overwritten by models" test. Follow up #33756
* Clarify docs of `config.filter_parameters` and `#filter_attributes`bogdanvlviv2018-09-121-1/+1
| | | | | Add mention that `config.filter_parameters` also filters out sensitive values of database columns when call `#inspect` since #33756.
* Configuration item `config.filter_parameters` could also filter out ↵Zhang Kang2018-09-071-2/+18
| | | | | | | | | | | | | | | | | | | | | | | | sensitive value of database column when call `#inspect` * Why Some sensitive data will be exposed in log accidentally by calling `#inspect`, e.g. ```ruby @account = Account.find params[:id] payload = { account: @account } logger.info "payload will be #{ payload }" ``` All the information of `@account` will be exposed in log. * Solution Add a class attribute filter_attributes to specify which values of columns shouldn't be exposed. This attribute equals to `Rails.application.config.filter_parameters` by default. ```ruby Rails.application.config.filter_parameters += [:credit_card_number] Account.last.insepct # => #<Account id: 123, credit_card_number: [FILTERED] ...> ```
* Refactors Active Record connection managementEileen Uchitelle2018-08-301-13/+9
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | While the three-tier config makes it easier to define databases for multiple database applications, it quickly became clear to offer full support for multiple databases we need to change the way the connections hash was handled. A three-tier config means that when Rails needed to choose a default configuration (in the case a user doesn't ask for a specific configuration) it wasn't clear to Rails which the default was. I [bandaid fixed this so the rake tasks could work](#32271) but that fix wasn't correct because it actually doubled up the configuration hashes. Instead of attemping to manipulate the hashes @tenderlove and I decided that it made more sense if we converted the hashes to objects so we can easily ask those object questions. In a three tier config like this: ``` development: primary: database: "my_primary_db" animals: database; "my_animals_db" ``` We end up with an object like this: ``` @configurations=[ #<ActiveRecord::DatabaseConfigurations::HashConfig:0x00007fd1acbded10 @env_name="development",@spec_name="primary", @config={"adapter"=>"sqlite3", "database"=>"db/development.sqlite3"}>, #<ActiveRecord::DatabaseConfigurations::HashConfig:0x00007fd1acbdea90 @env_name="development",@spec_name="animals", @config={"adapter"=>"sqlite3", "database"=>"db/development.sqlite3"}> ]> ``` The configurations setter takes the database configuration set by your application and turns them into an `ActiveRecord::DatabaseConfigurations` object that has one getter - `@configurations` which is an array of all the database objects. The configurations getter returns this object by default since it acts like a hash in most of the cases we need. For example if you need to access the default `development` database we can simply request it as we did before: ``` ActiveRecord::Base.configurations["development"] ``` This will return primary development database configuration hash: ``` { "database" => "my_primary_db" } ``` Internally all of Active Record has been converted to use the new objects. I've built this to be backwards compatible but allow for accessing the hash if needed for a deprecation period. To get the original hash instead of the object you can either add `to_h` on the configurations call or pass `legacy: true` to `configurations. ``` ActiveRecord::Base.configurations.to_h => { "development => { "database" => "my_primary_db" } } ActiveRecord::Base.configurations(legacy: true) => { "development => { "database" => "my_primary_db" } } ``` The new configurations object allows us to iterate over the Active Record configurations without losing the known environment or specification name for that configuration. You can also select all the configs for an env or env and spec. With this we can always ask any object what environment it belongs to: ``` db_configs = ActiveRecord::Base.configurations.configurations_for("development") => #<ActiveRecord::DatabaseConfigurations:0x00007fd1acbdf800 @configurations=[ #<ActiveRecord::DatabaseConfigurations::HashConfig:0x00007fd1acbded10 @env_name="development",@spec_name="primary", @config={"adapter"=>"sqlite3", "database"=>"db/development.sqlite3"}>, #<ActiveRecord::DatabaseConfigurations::HashConfig:0x00007fd1acbdea90 @env_name="development",@spec_name="animals", @config={"adapter"=>"sqlite3", "database"=>"db/development.sqlite3"}> ]> db_config.env_name => "development" db_config.spec_name => "primary" db_config.config => { "adapter"=>"sqlite3", "database"=>"db/development.sqlite3" } ``` The configurations object is more flexible than the configurations hash and will allow us to build on top of the connection management in order to add support for primary/replica connections, sharding, and constructing queries for associations that live in multiple databases.
* [ci skip] Change references from Rake task to Rails commandAlberto Almagro2018-08-011-1/+1
| | | | | This commit follows the path we started at commit #ea4f0e2 and continued at PR #33229.
* define attribute methods in `init_from_db`Aaron Patterson2018-06-261-0/+2
| | | | | Now that `allocate` is removed, we need to define attribute methods in all "init" methods.
* Merge branch 'master' into homogeneous-allocationAaron Patterson2018-06-261-5/+0
|\ | | | | | | | | | | | | | | * master: Call initialize after allocate Remove `ActiveSupport::Concern` from `ActiveRecord::Aggregations` Add example for no_touching? in active_record/no_touching for api docs [ci skip] Generate a new key for each service test
| * Call initialize after allocateAaron Patterson2018-06-261-5/+0
| | | | | | | | | | | | | | | | If someone calls allocate on the object, they'd better also call an initialization routine too (you can't expect allocate to do any initialization work). Before this commit, AR objects that are instantiated from the database would call `define_attribute_methods` twice.
* | Speed up homogeneous AR lists / reduce allocationsAaron Patterson2018-06-251-0/+20
|/ | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | This commit speeds up allocating homogeneous lists of AR objects. We can know if the result set contains an STI column before initializing every AR object, so this change pulls the "does this result set contain an STI column?" test up, then uses a specialized instantiation function. This way we only have to check for an STI column once rather than N times. This change also introduces a new initialization function that is meant for use when allocating AR objects that come from the database. Doing this allows us to eliminate one hash allocation per AR instance. Here is a benchmark: ```ruby require 'active_record' require 'benchmark/ips' ActiveRecord::Base.establish_connection adapter: "sqlite3", database: ":memory:" ActiveRecord::Migration.verbose = false ActiveRecord::Schema.define do create_table :users, force: true do |t| t.string :name t.timestamps null: false end end class User < ActiveRecord::Base; end 2000.times do User.create!(name: "Gorby") end Benchmark.ips do |x| x.report("find") do User.limit(2000).to_a end end ``` Results: Before: ``` [aaron@TC activerecord (master)]$ be ruby -I lib:~/git/allocation_tracer/lib speed.rb Warming up -------------------------------------- find 5.000 i/100ms Calculating ------------------------------------- find 56.192 (± 3.6%) i/s - 285.000 in 5.080940s ``` After: ``` [aaron@TC activerecord (homogeneous-allocation)]$ be ruby -I lib:~/git/allocation_tracer/lib speed.rb Warming up -------------------------------------- find 7.000 i/100ms Calculating ------------------------------------- find 72.204 (± 2.8%) i/s - 364.000 in 5.044592s ```
* Clear the transaction state when AR object is dupedYuriy Ustushenko2018-01-251-2/+4
|
* Avoid passing unnecessary arguments to relationDaniel Colson2018-01-241-1/+1
| | | | | | | | | | | | Most of the time the table and predicate_builder passed to Relation.new are exactly the arel_table and predicate builder of the given klass. This uses klass.arel_table and klass.predicate_builder as the defaults, so we don't have to pass them in most cases. This does change the signaure of both Relation and AssocationRelation. Are we ok with that?
* Log call site for all queriesOlivier Lacan2017-12-131-0/+7
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | This new ActiveRecord configuration option allows you to easily pinpoint what line of application code is triggering SQL queries in the development log by appending below each SQL statement log the line of Ruby code that triggered it. It’s useful with N+1 issues, and to locate stray queries. By default this new option ignores Rails and Ruby code in order to surface only callers from your application Ruby code or your gems. It is enabled on newly generated Rails 5.2 applications and can be enabled on existing Rails applications: ```ruby Rails.application.configure do # ... config.active_record.verbose_query_logs = true end ``` The `rails app:upgrade` task will also add it to `config/development.rb`. This feature purposely avoids coupling with ActiveSupport::BacktraceCleaner since ActiveRecord can be used without ActiveRecord. This decision can be reverted in the future to allow more configurable backtraces (the exclusion of gem callers for example).
* Prevent extra `spawn` to make `klass.all` faster (#29009)Ryuta Kamizono2017-11-201-1/+2
| | | | | | | | | | | | | | | | | | | | These extra `spawn` are called via `klass.all` and `klass.all` is called everywhere in the internal. Avoiding the extra `spawn` makes` klass.all` 30% faster for STI classes. https://gist.github.com/kamipo/684d03817a8115848cec8e8b079560b7 ``` Warming up -------------------------------------- fast relation 4.410k i/100ms slow relation 3.334k i/100ms Calculating ------------------------------------- fast relation 47.373k (± 5.2%) i/s - 238.140k in 5.041836s slow relation 35.757k (±15.9%) i/s - 176.702k in 5.104625s Comparison: fast relation: 47373.2 i/s slow relation: 35756.7 i/s - 1.32x slower ```
* remove :enabled optionBen Toews2017-11-091-3/+2
|
* add config to check arguments to unsafe AR methodsBen Toews2017-11-091-0/+9
|
* Remove deprecated configuration `.error_on_ignored_order_or_limit`Rafael Mendonça França2017-10-231-20/+0
|
* Update links to use https instead of http [ci skip]Yoshiyuki Hirano2017-08-221-1/+1
|
* Fix outdated comment for `Core::ClassMethods#===` [ci skip] (#30146)Ryuta Kamizono2017-08-121-2/+2
| | | | | | | | | | | | | This comment was added at 97849de, but `AssociationProxy` and `test_triple_equality` was removed at 1644663. Currently the `===` is used for `test_decorated_polymorphic_where` that added at #11945. So I updated "association proxies" to "decorated models". And also, currently `Core::ClassMethods` appears in the doc. http://api.rubyonrails.org/classes/ActiveRecord/Core/ClassMethods.html But it looks like that the methods in the module is not public API. So I also added `# :nodoc:` to the module.
* Use `Concurrent::Map` than `Mutex` and `Mutex_m` for statement cachesRyuta Kamizono2017-08-041-4/+3
| | | | | Statement caches are used as a concurrent map. It will more clarify to using `Concurrent::Map`.
* Passing `klass` to `StatementCache.new`Ryuta Kamizono2017-08-041-2/+2
| | | | | | Actually `StatementCache#execute` is always passed the same klass that the owner klass of the connection when the statement cache is created. So passing `klass` to `StatementCache.new` will make more DRY.
* Merge pull request #29842 from kamipo/fix_find_by_with_rangeMatthew Draper2017-08-021-3/+2
|\ | | | | Fix `find_by` with range conditions
| * Fix `find_by` with range conditionsRyuta Kamizono2017-07-201-3/+2
| | | | | | | | | | `StatementCache` doesn't support range conditions. So we need to through the args to `FinderMethods#find_by` if range value is passed.
* | Use frozen-string-literal in ActiveRecordKir Shatrov2017-07-191-0/+2
|/
* Remove useless `arel_engine`Ryuta Kamizono2017-07-171-10/+0
| | | | | | | | | | | `arel_engine` is only used in `raise_record_not_found_exception!` to use `engine.connection` (and `connection.visitor`) in `arel.where_sql`. https://github.com/rails/arel/blob/v8.0.0/lib/arel/select_manager.rb#L183 But `klass.connection` will work as expected even if not using `arel_engine` (described by `test_connection`). So `arel_engine` is no longer needed.
* Remove unused requiresRyuta Kamizono2017-07-161-2/+0
|
* Revert "Merge pull request #29540 from kirs/rubocop-frozen-string"Matthew Draper2017-07-021-1/+0
| | | | | This reverts commit 3420a14590c0e6915d8b6c242887f74adb4120f9, reversing changes made to afb66a5a598ce4ac74ad84b125a5abf046dcf5aa.
* Enforce frozen string in RubocopKir Shatrov2017-07-011-0/+1
|
* Use mattr_accessor default: option throughout the projectGenadi Samokovarov2017-06-031-13/+6
|
* Remove unused `@txn` variableEugene Kenny2017-03-151-1/+0
| | | | | | This was added in c24c885209ac2334dc6f798c394a821ee270bec6, removed in b89ffe7f0047eb614e42232a21201b317b880755, and then (unintentionally?) reintroduced in 2d7ae1b08ee2a10b12cbfeef3a6cc6da55b57df6.
* `type_condition` should be overwritten by `create_with_value` in ↵Ryuta Kamizono2017-01-151-1/+1
| | | | | | | | | | `scope_for_create` `type_condition` should be overwritten by `create_with_value`. So `type` in `create_with_value` should be a string because `where_values_hash` keys are converted to string. Fixes #27600.
* `self.` is not needed when calling its own instance methodAkira Matsuda2017-01-051-2/+2
| | | | Actually, private methods cannot be called with `self.`, so it's not just redundant, it's a bad habit in Ruby
* Fix `find_by` and `where` consistencyRyuta Kamizono2017-01-041-3/+3
| | | | | | | | | | The alternative of #26213. Currently `find_by` and `where` with AR object return inconsistent result. This is caused by statement cache does not support AR object. Passing to finder method to fix the issue. Fixes #26210.
* Raise ArgumentError when a instance of ActiveRecord::Base is passed toRafael Mendonça França2017-01-031-9/+5
| | | | find and exists?
* Mark :GeneratedAssociationMethods also as private_constantPrathamesh Sonpatki2016-12-311-0/+2
| | | | | | | | | | | | - After https://github.com/rails/rails/commit/64e5b897ac944a05a33275e3828a3d4047a6b457, only :GeneratedAssociationMethods was remaining to be marked as private constant, so marked it as well. - Before: >> User.constants(false) => [:GeneratedAssociationMethods] - After: >> User.constants(false) => []
* No need to nodoc private methodsAkira Matsuda2016-12-241-3/+3
|
* Translate numeric value out of range to the specific exceptionRyuta Kamizono2016-12-061-2/+2
| | | | Raise `ActiveRecord::RangeError` when values that executed are out of range.
* Don't assign default attributes until after loading schemaSean Griffin2016-11-031-1/+1
| | | | | | | | If the call to `.define_attribute_methods` actually ends up loading the schema (*very* hard to do, as it requires the object being created without `allocate` having been called, but it can be done by manually calling `initialize` from inside `marshal_load` if you're crazy), the value of `_default_attributes` will change from that call.
* allow ActiveRecord::Core#slice to use array argCohen Carlisle2016-10-311-1/+1
|
* Add more rubocop rules about whitespacesRafael Mendonça França2016-10-291-1/+1
|
* Use xor to avoid allocations in `AR::Core#hash`Sean Griffin2016-09-261-1/+1
| | | | | | | | This is not as good a solution as actually hashing both values, but Ruby doesn't expose that capability other than allocating the array. Unless we were to do something silly like have a thread local array that is re-used, I don't see any other way to do this without allocation. This solution may not be perfect, but it should reasonably avoid collisions to the extent that we need.
* fixes remaining RuboCop issues [Vipul A M, Xavier Noria]Xavier Noria2016-09-011-1/+1
|
* Include user defined attributes in inspectSean Griffin2016-08-311-1/+1
| | | | The fact that this only includes column names is an oversight.