Commit Graph

1998 Commits

Author SHA1 Message Date
Markus Doits 9bd186a0e8
clear secure password cache if password is set to `nil`
```rb
# before:
user.password = 'something'
user.password = nil

user.password # => 'something'

# now:
user.password = 'something'
user.password = nil

user.password # => nil
```
2021-10-10 11:54:35 +02:00
Muhammad Muhammad Ibrahim d1d4a54c23 Prevent error when authenticating user with a blank password digest
Co-authored-by: Petrik de Heus <petrik@deheus.net>
2021-09-24 09:28:10 +02:00
Jesse van der Pluijm 4862c2faf6 Fix typo: integer numbers (not integral) 2021-09-18 10:21:42 +02:00
Rafael Mendonça França d177551c30
Preparing for 7.0.0.alpha2 release 2021-09-15 18:22:51 -04:00
Rafael Mendonça França 9b7be48212
Preparing for 7.0.0.alpha1 release 2021-09-15 17:55:08 -04:00
Petrik c477d95604 Introduce ActiveModel::API
Currently `ActiveModel::Model` is defined as the minimum API to talk
with Action Pack and Action View.
Its name suggests it can be included to create Active Record type
models, but for creating models it's probably too minimal. For example
it's very common to include ActiveModel::Attributes as well.

By moving `ActiveModel::Model`'s implementation to a new
`ActiveModel::API` we keep a definition of the minimum API to talk with
Action Pack and Action View.

For `ActiveModel::Model` we only need to include `ActiveModel::API`.
This will allow adding more funcationality to `ActiveModel::Model` while
keeping backwards compatibility.

Co-authored-by: Nathaniel Watts <1141717+thewatts@users.noreply.github.com>
2021-09-15 18:24:47 +02:00
Guillermo Iguaran 75ea828409 Don't add attribute_names to ActiveModel::Serialization public API 2021-08-28 11:56:21 -07:00
Cody Cutrer 1fbb3ddcd3 avoid calling attributes.keys in ActiveModel#serializable_hash
for ActiveRecord objects, it will force the entire attributes hash to
be constructed, which may include expensive deserialization.
ActiveModel already has a simple attribute_names method defined which
returns attributes.keys, exactly like the code we're replacing.
ActiveRecord overrides that method, and returns the names of the
attributes _without_ having to deserialize any values.

this change can save a lot of CPU if you have a serialized column
on a model that you often load from the DB because it's not worth
the effort to customize the SELECT on every relation, but
also rarely expose in any JSON serializations (i.e. have a default
except option for it).
2021-08-17 18:59:37 -06:00
Rafael Mendonça França 18707ab17f
Standardize nodoc comments 2021-07-29 21:18:07 +00:00
Ryuta Kamizono 0f001f00eb Fix `to_json` after `changes_applied` for `ActiveModel::Dirty` object
Follow up to #41677.

Mutation tracking variables are not only `@mutations_from_database` but
also `@mutations_before_last_save`.
2021-07-24 08:22:18 +09:00
Jonathan Hefner baa070c3b4
Merge pull request #42839 from jonathanhefner/doc-each_validator
Remove nodoc from EachValidator [ci-skip]
2021-07-23 13:27:35 -05:00
Jean Boussier 8512118f43
Merge pull request #42832 from lulalala/slim-errors-inspect
Slimmer ActiveModel::Errors#inspect message
2021-07-23 09:05:08 +02:00
lulalala 1523838567 Slimmer ActiveModel::Errors#inspect
Only show @errors array and hide @base
2021-07-23 12:29:46 +08:00
Jonathan Hefner 79bb7d0a2b Remove nodoc from EachValidator [ci-skip]
The Active Record Validations guide recommends using `EachValidator`,
and has done so for many years.
2021-07-22 10:35:48 -05:00
Marcelo Lauxen d1df4c100f
Fix dirty check for Float::NaN and BigDecimal::NaN
Float::NaN and BigDecimal::NaN in Ruby are [special values](https://bugs.ruby-lang.org/issues/1720) and can't be compared with `==`.
2021-07-22 09:49:16 -03:00
OKURA Masafumi 67adc94e00 Add `:nodoc` to `ActiveModel::Errors`
Three classes in `active_model/errors` look internal only.
2021-07-09 00:01:10 +09:00
OKURA Masafumi f96929ae5f Add missing require to `active_model/naming`
Using `delegate` at L151 causes `NoMethodError`.
Adding `require` resolves this.
2021-07-08 23:02:09 +09:00
Rafael França 637d386fbb
Merge pull request #41677 from anilmaurya/fix-41521
Fixes #41521, ActiveModel::Dirty fails on to_json
2021-06-24 14:10:29 -04:00
Anil Kumar Maurya ab1a58281c Fixes #41521, ActiveModel::Dirty fails on to_json 2021-06-24 10:31:48 +00:00
Eddie Lebow ec207a415a
Formatting markup in comment 2021-06-23 22:41:13 -04:00
Aditya Bhutani 32af6add67 [ci skip] Fixing all <x> based occurances to <x>-based 2021-06-16 19:15:12 +05:30
Chris Salzberg caced27393 Add ActiveModel::AttributeSet#values_for_database 2021-06-08 16:39:23 +09:00
Benoit Daloze 191ee5eec9 Prefer (...) over ruby2_keywords for ActiveModel::Type.lookup
* (...) is already used in several places in Rails and looks nicer.
2021-05-25 16:06:15 +02:00
Benoit Daloze 5d86e32ae2 Fix delegation in ActiveModel::Type.lookup
* Without the change the new test fails like this:
  Failure:
  ActiveModel::TypeTest#test_registering_a_new_type [test/cases/type_test.rb:21]:
  Expected: #<struct args={}>
    Actual: #<struct args=nil>
* (*args, **kwargs)-delegation is not correct on Ruby 2.7 unless the
  target always accepts keyword arguments (not the case for `Struct.new(:args).new`).
  See https://eregon.me/blog/2021/02/13/correct-delegation-in-ruby-2-27-3.html
2021-05-25 16:01:17 +02:00
Benoit Daloze 8ccc3bfc2d Fix delegation in ActiveModel::Type::Registry
* Without the change the new test fails like this:
  Failure:
  ActiveModel::Type::RegistryTest#test_a_class_can_be_registered_for_a_symbol [test/cases/type/registry_test.rb:16]:
  Expected: [{}, {}]
    Actual: [nil, nil]
* (*args, **kwargs)-delegation is not correct on Ruby 2.7 unless the
  target always accepts keyword arguments (not the case for `Array.new`).
  See https://eregon.me/blog/2021/02/13/correct-delegation-in-ruby-2-27-3.html
2021-05-21 13:50:33 +02:00
Jean Boussier ca5542fed3 Cache and reuse generated attribute methods 2021-05-03 09:27:59 +02:00
Ryuta Kamizono 95b45c826d Change `send` back to `public_send`
It was accidentally changed in #40095.
2021-04-26 03:23:51 +09:00
Abhay Nikam 0b0b22a46a Fixes a typo and wordsmithing in the exception message. Typo: nor -> or 2021-04-24 21:10:24 +05:30
Ashik Salman b0241f300c Added more test coverage for comparison validator. 2021-04-24 19:36:35 +05:30
Ryuta Kamizono aa7a8db604 Fix numericality validator `:in` with invalid args to raise ArgumentError 2021-04-24 14:35:35 +09:00
Ryuta Kamizono f83dbe358e Fix error message on comparison validator 2021-04-24 14:26:08 +09:00
Ryuta Kamizono a1afc7726b Convert \r\n to \n 2021-04-24 14:10:18 +09:00
Ryuta Kamizono 8a23c85f6e Fix "uninitialized constant ActiveModel::Validations::NumericalityValidator::Comparability (NameError)"
Somehow it isn't caused on CI, but it consistently causes on locally.

```
% bin/test -w
/Users/kamipo/src/github.com/rails/rails/activemodel/lib/active_model/validations.rb:85: warning: method redefined; discarding old validates_each
/Users/kamipo/src/github.com/rails/rails/activemodel/lib/active_model/validations.rb:85: warning: previous definition of validates_each was here
/Users/kamipo/src/github.com/rails/rails/activemodel/lib/active_model/validations.rb:89: warning: already initialized constant ActiveModel::Validations::ClassMethods::VALID_OPTIONS_FOR_VALIDATE
/Users/kamipo/src/github.com/rails/rails/activemodel/lib/active_model/validations.rb:89: warning: previous definition of VALID_OPTIONS_FOR_VALIDATE was here
/Users/kamipo/src/github.com/rails/rails/activemodel/lib/active_model/validations.rb:152: warning: method redefined; discarding old validate
/Users/kamipo/src/github.com/rails/rails/activemodel/lib/active_model/validations.rb:152: warning: previous definition of validate was here
/Users/kamipo/src/github.com/rails/rails/activemodel/lib/active_model/validations.rb:192: warning: method redefined; discarding old validators
/Users/kamipo/src/github.com/rails/rails/activemodel/lib/active_model/validations.rb:192: warning: previous definition of validators was here
/Users/kamipo/src/github.com/rails/rails/activemodel/lib/active_model/validations.rb:234: warning: method redefined; discarding old clear_validators!
/Users/kamipo/src/github.com/rails/rails/activemodel/lib/active_model/validations.rb:234: warning: previous definition of clear_validators! was here
/Users/kamipo/src/github.com/rails/rails/activemodel/lib/active_model/validations.rb:254: warning: method redefined; discarding old validators_on
/Users/kamipo/src/github.com/rails/rails/activemodel/lib/active_model/validations.rb:254: warning: previous definition of validators_on was here
/Users/kamipo/src/github.com/rails/rails/activemodel/lib/active_model/validations.rb:270: warning: method redefined; discarding old attribute_method?
/Users/kamipo/src/github.com/rails/rails/activemodel/lib/active_model/validations.rb:270: warning: previous definition of attribute_method? was here
/Users/kamipo/src/github.com/rails/rails/activemodel/lib/active_model/validations.rb:275: warning: method redefined; discarding old inherited
/Users/kamipo/src/github.com/rails/rails/activemodel/lib/active_model/validations.rb:275: warning: previous definition of inherited was here
/Users/kamipo/src/github.com/rails/rails/activemodel/lib/active_model/validations.rb:283: warning: method redefined; discarding old initialize_dup
/Users/kamipo/src/github.com/rails/rails/activemodel/lib/active_model/validations.rb:283: warning: previous definition of initialize_dup was here
/Users/kamipo/src/github.com/rails/rails/activemodel/lib/active_model/validations.rb:301: warning: method redefined; discarding old errors
/Users/kamipo/src/github.com/rails/rails/activemodel/lib/active_model/validations.rb:301: warning: previous definition of errors was here
/Users/kamipo/src/github.com/rails/rails/activemodel/lib/active_model/validations.rb:373: warning: method redefined; discarding old invalid?
/Users/kamipo/src/github.com/rails/rails/activemodel/lib/active_model/validations.rb:373: warning: previous definition of invalid? was here
/Users/kamipo/src/github.com/rails/rails/activemodel/lib/active_model/validations.rb:382: warning: method redefined; discarding old validate!
/Users/kamipo/src/github.com/rails/rails/activemodel/lib/active_model/validations.rb:382: warning: previous definition of validate! was here
/Users/kamipo/src/github.com/rails/rails/activemodel/lib/active_model/validations.rb:405: warning: method redefined; discarding old run_validations!
/Users/kamipo/src/github.com/rails/rails/activemodel/lib/active_model/validations.rb:405: warning: previous definition of run_validations! was here
/Users/kamipo/src/github.com/rails/rails/activemodel/lib/active_model/validations.rb:410: warning: method redefined; discarding old raise_validation_error
/Users/kamipo/src/github.com/rails/rails/activemodel/lib/active_model/validations.rb:410: warning: previous definition of raise_validation_error was here
/Users/kamipo/src/github.com/rails/rails/activemodel/lib/active_model/validations.rb:426: warning: method redefined; discarding old model
/Users/kamipo/src/github.com/rails/rails/activemodel/lib/active_model/validations.rb:428: warning: method redefined; discarding old initialize
/Users/kamipo/src/github.com/rails/rails/activemodel/lib/active_model/validations.rb:428: warning: previous definition of initialize was here
Traceback (most recent call last):
	23: from bin/test:5:in `<main>'
	22: from bin/test:5:in `require_relative'
	21: from /Users/kamipo/src/github.com/rails/rails/tools/test.rb:18:in `<top (required)>'
	20: from /Users/kamipo/src/github.com/rails/rails/railties/lib/rails/test_unit/runner.rb:40:in `run'
	19: from /Users/kamipo/src/github.com/rails/rails/railties/lib/rails/test_unit/runner.rb:52:in `load_tests'
	18: from /Users/kamipo/src/github.com/rails/rails/railties/lib/rails/test_unit/runner.rb:52:in `each'
	17: from /Users/kamipo/src/github.com/rails/rails/railties/lib/rails/test_unit/runner.rb:52:in `block in load_tests'
	16: from /Users/kamipo/src/github.com/rails/rails/railties/lib/rails/test_unit/runner.rb:52:in `require'
	15: from /Users/kamipo/src/github.com/rails/rails/activemodel/test/cases/attributes_dirty_test.rb:5:in `<top (required)>'
	14: from /Users/kamipo/src/github.com/rails/rails/activemodel/test/cases/attributes_dirty_test.rb:6:in `<class:AttributesDirtyTest>'
	13: from /Users/kamipo/src/github.com/rails/rails/activemodel/test/cases/attributes_dirty_test.rb:7:in `<class:DirtyModel>'
	12: from /Users/kamipo/src/github.com/rails/rails/activemodel/test/cases/attributes_dirty_test.rb:7:in `require'
	11: from /Users/kamipo/src/github.com/rails/rails/activemodel/lib/active_model/model.rb:3:in `<top (required)>'
	10: from /Users/kamipo/src/github.com/rails/rails/activemodel/lib/active_model/model.rb:59:in `<module:ActiveModel>'
	 9: from /Users/kamipo/src/github.com/rails/rails/activemodel/lib/active_model/model.rb:62:in `<module:Model>'
	 8: from /Users/kamipo/src/github.com/rails/rails/activemodel/lib/active_model/model.rb:62:in `require'
	 7: from /Users/kamipo/src/github.com/rails/rails/activemodel/lib/active_model/validations.rb:436:in `<top (required)>'
	 6: from /Users/kamipo/src/github.com/rails/rails/activemodel/lib/active_model/validations.rb:436:in `each'
	 5: from /Users/kamipo/src/github.com/rails/rails/activemodel/lib/active_model/validations.rb:436:in `block in <top (required)>'
	 4: from /Users/kamipo/src/github.com/rails/rails/activemodel/lib/active_model/validations.rb:436:in `require'
	 3: from /Users/kamipo/src/github.com/rails/rails/activemodel/lib/active_model/validations/numericality.rb:5:in `<top (required)>'
	 2: from /Users/kamipo/src/github.com/rails/rails/activemodel/lib/active_model/validations/numericality.rb:6:in `<module:ActiveModel>'
	 1: from /Users/kamipo/src/github.com/rails/rails/activemodel/lib/active_model/validations/numericality.rb:7:in `<module:Validations>'
/Users/kamipo/src/github.com/rails/rails/activemodel/lib/active_model/validations/numericality.rb:8:in `<class:NumericalityValidator>': uninitialized constant ActiveModel::Validations::NumericalityValidator::Comparability (NameError)
```
2021-04-24 13:46:45 +09:00
Matthew Draper 536a2c0011
Merge pull request #40095 from ChaelCodes/cc-comparablity-validator
Add ComparisonValidator to validate comparison of any objects
2021-04-24 13:20:57 +09:30
Ryuta Kamizono bbbc861f71 Enable `Performance/MapCompact` cop
Follow up to #42053.
2021-04-23 16:33:02 +09:00
Jean Boussier 6a5fb7dbd4
Merge pull request #41911 from Shopify/simplify-proxy-call
Allow to pass the method signature when defining attribute methods
2021-04-12 22:36:32 +02:00
Rafael Mendonça França 4354e3ae49
Don't define methods using the method modifier in the same line as the method
Our style guide use block method modifiers, not inline method modifiers.
2021-04-12 18:49:54 +00:00
Jean Boussier eece095765 Allow to pass the method signature when defining attribute methods
This saves some array allocations from avoiding `*args`, as well
as makes the Method object `arity` and `parameters` correct.

e.g. before this patch, ArgumentError would be confusing:

```ruby
>> model.name_was(1)
ArgumentError: wrong number of arguments (given 2, expected 1)
```
2021-04-11 17:03:25 +02:00
Jean Boussier c8ea5b8615 Use alias_method rather than define_method to handle non compilable names 2021-04-11 16:10:45 +02:00
Jean Boussier 3f59640016 Stop checking if ruby2_keywords is defined 2021-04-11 13:42:02 +02:00
Étienne Barrié 81d0653f84 Simplify ActiveModel & ActiveRecord Type::Registry
ActiveRecord::Type::Registry doesn't need to inherit from
ActiveModel::Type::Registry, and it makes both classes more simple.

Co-authored-by: Adrianna Chang <adrianna.chang@shopify.com>
2021-04-07 09:59:55 -04:00
Jean Boussier 39341de433 Remove useless `include_private` parameter in `define_proxy_call`
Since Ruby 2.7 `self.some_private_method` works fine.
So now that Ruby 2.7 is the minimal supported version,
`define_proxy_call` can always prepend `self.`
2021-03-20 14:27:53 -04:00
Ryuta Kamizono c435af140e Don't use `type.cast(value)` to emulate unchecked serialized value in `unboundable?`
I used `type.cast(value)` to emulate unchecked serialized value in
`unboundable?`, since `RangeError` was raised only for the integer type,
so the emulation works enough for the integer type.

But since #41516, Enum types are also not always serializable, so
`type.cast(value)` may also be called for the enum types.

I've delegated `type.cast(value)` to the subtype if an unknown label is
passed to work the emulation even on Enum types in 3b6461b. But it is
strange to delegate to the subtype for the emulation only if an unknown
label is passed.

Instead of using `type.cast(value)` for the emulation, extend
`serializable?` to get unchecked serialized value if the value is not
serializable.
2021-03-15 12:23:40 +09:00
Ryuta Kamizono 4607f13c88 Use `serializable?` instead of `rescue ::RangeError` 2021-03-10 21:21:22 +09:00
Ryuta Kamizono 6ee96a8f42 Avoid extra query attribute allocation in `_insert_record`/`_update_record`
Since a `BindParam` object always has an attribute object as the value
in the Active Record usage, so `_insert_record`/`_update_record` could
be passed attribute set instead of wrapping casted value by a query
attribute.
2021-03-01 16:24:31 +09:00
Artem Yegorov 89db42b5e1
Add `uncountable?` method to ActiveModel::Name 2021-02-18 09:55:29 +03:00
Jonathan Hefner 167f5c8065 Fix inline code markup [ci-skip]
RDoc Markup does not support backticks the way Markdown does to mark up
inline code.  Additionally, `<tt>` must be used to mark up inline code
that includes spaces or certain punctuation characters (e.g. quotes).
2021-02-14 11:20:35 -06:00
Ryuta Kamizono 56ea638290 A value acts like time object should respond to `getutc` and `getlocal` 2021-02-11 15:05:25 +09:00
Ricardo Díaz 93cbc30f34 Use Enumerator#all? and Enumerator#any? with classes instead of iterations
These methods have changed in Ruby 2.5 to be more akin to grep:

https://bugs.ruby-lang.org/issues/11286

Using classes seems to be faster (and a bit more expressive) than iterating over
the collection items:

```
Warming up --------------------------------------
    #all? with class   504.000  i/100ms
     #all? with proc   189.000  i/100ms
Calculating -------------------------------------
    #all? with class      4.960k (± 1.6%) i/s -     25.200k in   5.082049s
     #all? with proc      1.874k (± 2.8%) i/s -      9.450k in   5.047866s

Comparison:
    #all? with class:     4959.9 i/s
     #all? with proc:     1873.8 i/s - 2.65x  (± 0.00) slower
```

Benchmark script:

```ruby
require "minitest/autorun"
require "benchmark/ips"

class BugTest < Minitest::Test
  def test_enumerators_with_classes
    arr = (1..10000).to_a << nil

    assert_equal arr.all?(Integer), arr.all? { |v| v.is_a?(Integer) }

    Benchmark.ips do |x|
      x.report("#all? with class") do
        arr.all?(Integer)
      end

      x.report("#all? with proc") do
        arr.all? { |v| v.is_a?(Integer) }
      end

      x.compare!
    end
  end
end
```
2021-02-07 01:29:50 -05:00
Rafael Mendonça França 1b455e2e9d
Rails 6.2 is now Rails 7.0
We have big plans for the next version of Rails and that
require big versions.
2021-02-04 16:47:16 +00:00
Rafael França da418dc250
Merge pull request #41217 from Vin0uz/active-model-errors-add-doc
[ci-skip] Adding options example in ActiveModel::Errors doc
2021-02-03 16:18:26 -05:00
Kevin Vinhas da0e869bd8 Adding options example in ActiveModel::Errors doc
Place errors with variable example under the `type is a symbol` block
Closes #41124
2021-02-03 21:55:10 +01:00
Rafael Mendonça França 9ea15f1927
Improve performance of time type cast for ISO dates
Before this patch we were appeding a new date in front of
an already existing date what was making the fast path of the
type cast to not trigger.

The following benchmark was used to drive this implementation:

https://gist.github.com/rafaelfranca/0f71c00613f924fcbcdb14b95e6f7661

Closes #41316.
2021-02-03 00:10:15 +00:00
Rachael Wright-Munn 9a08a2f09c Add ComparisonValidator to Rails to support validations between two comparable values.
We allow for compare validations in NumericalityValidator, but these
only work on numbers. There are various comparisons people may want
to validate, from dates to strings, to custom comparisons.

```
validates_comparison_of :end_date, greater_than: :start_date
```

Refactor NumericalityValidator to share module Comparison with ComparabilityValidator
* Move creating the option_value into a reusable module
* Separate COMPARE_CHECKS which support compare functions and accept values
* Move odd/even checks to NUMBER_CHECKS as they can only be run on numbers
2021-01-23 21:24:25 -05:00
Ryuta Kamizono e889cc55b0 Make ActiveModel's attribute behavior follow ActiveRecord's 2021-01-18 07:54:36 +09:00
Ryuta Kamizono 63835772bb
Merge pull request #41019 from intrip/40902-fix-numericality-validator
Use round(scale) in  ActiveModel NumericalityValidator
2021-01-14 17:14:31 +09:00
Jacopo 6657e3428b Change Numericaly validator to use round
f72f743 introduces truncate(scale) in the Numericality validator.
This behaviour conflicts with AR decimal type conversion,
which uses round(scale) instead.

Changes the Numericality validator in order to use
round(scale) for consistency.
2021-01-13 22:37:01 +01:00
Ryuta Kamizono 4db95d8432 Restore the ability that update/destroy optimistic locking object without default
The ability has lost due to reverted #39321 in #41049.

We should allow updating with dirty locking value to work the documented
usage, but if casted value has no difference (i.e. regarded as no dirty),
identify the object by the original (uninitialized default) value.
2021-01-12 09:27:11 +09:00
Ryuta Kamizono d24dc88dad
Revert "Fix update with dirty locking column to not match latest object accidentally" 2021-01-08 18:06:05 +09:00
Michal Papis 2486e887de
Add validate numericality in range 2021-01-05 22:56:58 +01:00
Ryuta Kamizono 2b0b5a75c0 Bump license years to 2021 [ci skip] 2021-01-01 12:21:20 +09:00
Rafael França 67a1cb6c19
Merge pull request #40961 from luk4s/add_activemodel_naming_locale_arg
change ActiveModel::Name initialize arguments to hash and add locale
2020-12-29 14:20:00 -05:00
Lukáš Pokorný d20caa6df1
add locale argument to ActiveModel::Name initialize 2020-12-29 10:39:35 +01:00
Ryuta Kamizono 6c4306be71 Move `set_options_for_callback` into `Callbacks::ClassMethods`
https://buildkite.com/rails/rails/builds/73736#864bc31e-384d-4e38-8165-0d3256ac3f3d/968-979
2020-12-29 16:20:13 +09:00
Rafael Mendonça França b4cab6a854
Make sure the :if options of callbacks is not mutated
In some cases, the framework was mutating the :if option of callbacks.
Since #38323, those options are frozen, so the framework could raise
exception when trying to mutate those options if they were being resued
with method like `with_options`.
2020-12-29 03:56:54 +00:00
alpaca-tc 8034a439c7 Reuse the same ActiveModel::Type::Value 2020-12-23 18:09:50 +09:00
Rafael Mendonça França b24ed15baa
Rename the method to match what it is doing 2020-12-09 17:10:22 +00:00
Ryuta Kamizono 720a60e68c Split the options checks from `read_attribute_for_validation` 2020-12-09 16:43:26 +09:00
Ryuta Kamizono 1dee4990cd `allow_nil` should work for casted value in `NumericalityValidator`
It is a regression for 4cc438a1df.

`NumericalityValidator` basically takes the value before typecasting,
but `allow_nil` should work for the typecasted value for the
compatibility.

Fixes #40750.
2020-12-08 23:25:56 +09:00
Rafael Mendonça França 59f7f5889e
Start Rails 6.2 development 🎉 2020-12-03 01:35:29 +00:00
alpaca-tc 3d1cb9a1f3 Handle frozen conditions in validate
Co-authored-by: Rafael França <rafael@franca.dev>
2020-11-06 12:06:03 +09:00
alpaca-tc e4e62fbdc6 ActiveModel::Model can be frozen again 2020-11-05 20:52:27 +09:00
Rafael Mendonça França 8389f9902c
Preparing for 6.1.0.rc1 release 2020-11-02 21:12:47 +00:00
Rafael França af91d9a1c5
Merge pull request #40434 from filipe-sabella/pass-in-base-in-validation-messages
Pass in base to Error.human_attribute_names
2020-11-02 13:15:53 -05:00
Rafael Mendonça França e14e78bf44
Revert "Add test to make sure this method will not be removed again"
This reverts commit d93a5d385e.

Revert "Revert "Remove unused internal methods in ActiveModel::Attributes""

This reverts commit 2d7967204e.

Reason: read_attribute was added in 6.1 as a performance optimization
and it is not needed anymore and write_attribute only existed to make
possible to call something that is not `attribute=` with send. We don't
need those methods internally and since they were never part of the
public API we can remove them.
2020-10-30 01:54:16 +00:00
Rafael Mendonça França d93a5d385e
Add test to make sure this method will not be removed again 2020-10-28 21:26:39 +00:00
Rafael Mendonça França 2d7967204e
Revert "Remove unused internal methods in ActiveModel::Attributes"
This reverts commit 13bd289b44.
2020-10-28 21:26:38 +00:00
Ryuta Kamizono e47068c3f3 Use `attribute_before_type_cast` in the internal
`read_attribute_before_type_cast` has become bit slower since #40395.
2020-10-27 16:38:32 +09:00
Ryuta Kamizono 13bd289b44 Remove unused internal methods in ActiveModel::Attributes 2020-10-27 16:11:24 +09:00
Akira Matsuda 98fda672a6 *_digest is defined as a public method 2020-10-27 12:13:32 +09:00
Ryuta Kamizono 92ff708476 Re-enable `Layout/SpaceAroundOperators` cop
We prefer space around operators, but `Layout/SpaceAroundOperators` cop
was temporarily disabled in #36943 since that cop changed to check
alignment strictly somehow.

In RuboCop 1.0.0, that is fixed by https://github.com/rubocop-hq/rubocop/pull/8906.

Related https://github.com/rails/rails/pull/38034#discussion_r359845661,
https://github.com/rails/rails/pull/39770#discussion_r448829561.
2020-10-23 16:12:15 +09:00
Filipe Sabella bc7b730891 Pass in base to Error.human_attribute_names
There are validation cases in which the human_attribute_name depends on
other fields of the base class.

For instance, an Address model that depends on the selected country to
localize the attribute name to be shown in error messages. E.g. the
:address1 and :address2 attributes can be displayed as very different
strings depending on whether the address is in the US or in Japan.
2020-10-22 16:50:00 -03:00
Chris Griego 5fe517563e
Add missing ActiveSupport require in ActiveModel::Serialization
serializable_attributes is using index_with from active_support/core_ext/enumerable
2020-10-13 14:30:24 -05:00
Akira Matsuda ce25559c3e Comparison operator methods on Integer are public methods 2020-10-02 13:41:42 +09:00
Akira Matsuda 02ad67841c Integer#odd? and even? are public methods 2020-10-02 13:39:00 +09:00
Akira Matsuda c7e68d1729 ==, >=, and <= are public methods 2020-10-02 13:18:09 +09:00
Akira Matsuda 6d45be5ba0 *_confirmation is defined as a public method 2020-10-02 13:14:15 +09:00
Akira Matsuda 8d014e1058 Enumerable#include? and cover? are both public methods 2020-10-02 13:12:55 +09:00
Akira Matsuda f2a182bf7d Time.utc and Time.local are both public methods 2020-10-02 13:06:59 +09:00
Akira Matsuda 9caf8ddb93 *_ditest and *_digest= are defined as public methods 2020-10-02 13:06:55 +09:00
Trevor John 6fba3c3be0
Allow ActiveModel::Name fields to be overriden 2020-09-23 00:17:54 -04:00
Akira Matsuda badcaf6763 AR::Base#read_attribute_for_validation is a public_method 2020-09-16 12:15:23 +09:00
lulalala 1fee2cbc50 Rename Error#detail method as details
Plural is more expected.
2020-09-11 17:03:59 +08:00
Eugene Kenny 7af59e16a2 Use transform_values in a few more places
It's faster on Ruby 2.7+ since it avoids rehashing the keys.
2020-09-08 01:34:41 +01:00
Abhay Nikam 714f8c8068 Documents other_than option also accepts the proc or a symbol for numericality validation [skip ci] 2020-08-24 21:27:45 +05:30
Eugene Kenny 0d0eb93b16 Add missing require for Enumerable#index_with
Followup to 0adcec4954.
2020-08-23 09:17:53 +01:00
Matthew Draper 843898c57a
Merge pull request #22610 from KevinSjoberg/feature/array-member-inclusion
Validate inclusion of each object in an array
2020-08-03 00:09:35 +09:30
Vipul A M 1d6daaaa56
Merge pull request #39735 from lulalala/doc-errors-update
Document ActiveModel errors methods
2020-07-31 08:54:08 +05:30
Ryuta Kamizono 4cc438a1df Extract `read_attribute_for_validation` for per-validator customization
The model global `read_attribute_for_validation` is not fit for some
validators (specifically for numericality validator).

To allow per-validator customization for attribute value, it extracts
`read_attribute_for_validation` in `EachValidator`.
2020-07-29 18:11:49 +09:00
lulalala f9518dc972 Document model error methods
[ci skip]
2020-06-29 17:50:08 +08:00
Ryuta Kamizono f870537c47 Allow ISO 8601 formatted string for `fast_string_to_time`
Currently `ISO_DATETIME` regexp parser doesn't allow ISO 8601 formatted
string, it fallbacks to slower `Date._parse` in `fallback_string_to_time`.

This makes `ISO_DATETIME` allows ISO 8601 formatted string for
`fast_string_to_time`, it makes ISO 8601 formatted string parsing about
3.5x faster.

```ruby
type = ActiveRecord::Type.lookup(:datetime)
local = Time.now.iso8601
utc = Time.now.utc.iso8601

Benchmark.ips do |x|
  x.report("type.cast(local)") { type.cast(local); type.cast(local) }
  x.report("type.cast(utc)")   { type.cast(utc);   type.cast(utc)   }
end
```

Before:

```
Warming up --------------------------------------
    type.cast(local)     2.198k i/100ms
      type.cast(utc)     2.443k i/100ms
Calculating -------------------------------------
    type.cast(local)     22.371k (± 5.9%) i/s -    112.098k in   5.028419s
      type.cast(utc)     23.359k (± 5.5%) i/s -    117.264k in   5.034913s
```

After:

```
Warming up --------------------------------------
    type.cast(local)     6.918k i/100ms
      type.cast(utc)     9.414k i/100ms
Calculating -------------------------------------
    type.cast(local)     71.468k (± 6.2%) i/s -    359.736k in   5.053612s
      type.cast(utc)     86.258k (± 4.5%) i/s -    433.044k in   5.029979s
```
2020-06-20 10:50:08 +09:00
Ryuta Kamizono 575f4e16a7 Do not use slower `public_send` in type casting
Before:

```
Warming up --------------------------------------
type.cast(usec=0len)     9.439k i/100ms
type.cast(usec=6len)     9.282k i/100ms
type.cast(usec=3len)     9.111k i/100ms
type.cast(usec=7len)     9.059k i/100ms
Calculating -------------------------------------
type.cast(usec=0len)     90.341k (± 4.2%) i/s -    453.072k in   5.023724s
type.cast(usec=6len)     84.970k (± 3.7%) i/s -    426.972k in   5.031444s
type.cast(usec=3len)     84.043k (± 4.3%) i/s -    428.217k in   5.104155s
type.cast(usec=7len)     83.443k (± 5.3%) i/s -    416.714k in   5.008011s
```

After:

```
Warming up --------------------------------------
type.cast(usec=0len)     9.829k i/100ms
type.cast(usec=6len)     9.405k i/100ms
type.cast(usec=3len)     9.315k i/100ms
type.cast(usec=7len)     9.464k i/100ms
Calculating -------------------------------------
type.cast(usec=0len)     92.918k (± 5.3%) i/s -    471.792k in   5.091504s
type.cast(usec=6len)     86.207k (± 4.4%) i/s -    432.630k in   5.027844s
type.cast(usec=3len)     86.060k (± 4.6%) i/s -    437.805k in   5.097409s
type.cast(usec=7len)     87.036k (± 4.3%) i/s -    435.344k in   5.010501s
```
2020-06-20 08:22:45 +09:00
Ryuta Kamizono e152d3403f Make usec parsing faster
This intends to avoid extra Rational creation for usec parsing
especially in the no usec case.

This makes all usec variations faster.

```ruby
type = ActiveRecord::Type.lookup(:datetime)
time1 = "2020-06-19 19:18:43"
time2 = "2020-06-19 19:18:43.123456"
time3 = "2020-06-19 19:18:43.123"
time4 = "2020-06-19 19:18:43.1234567"

Benchmark.ips do |x|
  x.report("type.cast(usec=0len)") { type.cast(time1); type.cast(time1) }
  x.report("type.cast(usec=6len)") { type.cast(time2); type.cast(time2) }
  x.report("type.cast(usec=3len)") { type.cast(time3); type.cast(time3) }
  x.report("type.cast(usec=7len)") { type.cast(time4); type.cast(time4) }
end
```

Before:

```
Warming up --------------------------------------
type.cast(usec=0len)     7.343k i/100ms
type.cast(usec=6len)     8.993k i/100ms
type.cast(usec=3len)     8.301k i/100ms
type.cast(usec=7len)     8.209k i/100ms
Calculating -------------------------------------
type.cast(usec=0len)     85.825k (± 5.4%) i/s -    433.237k in   5.062319s
type.cast(usec=6len)     82.045k (± 4.3%) i/s -    413.678k in   5.051260s
type.cast(usec=3len)     78.659k (± 4.4%) i/s -    398.448k in   5.074891s
type.cast(usec=7len)     77.477k (± 4.4%) i/s -    394.032k in   5.095355s
```

After:

```
Warming up --------------------------------------
type.cast(usec=0len)     9.439k i/100ms
type.cast(usec=6len)     9.282k i/100ms
type.cast(usec=3len)     9.111k i/100ms
type.cast(usec=7len)     9.059k i/100ms
Calculating -------------------------------------
type.cast(usec=0len)     90.341k (± 4.2%) i/s -    453.072k in   5.023724s
type.cast(usec=6len)     84.970k (± 3.7%) i/s -    426.972k in   5.031444s
type.cast(usec=3len)     84.043k (± 4.3%) i/s -    428.217k in   5.104155s
type.cast(usec=7len)     83.443k (± 5.3%) i/s -    416.714k in   5.008011s
```
2020-06-20 08:08:31 +09:00
Ryuta Kamizono d2cdf0be67
Merge pull request #39612 from kamipo/faster_attributes
PERF: 45% faster attributes for readonly usage
2020-06-17 20:29:47 +09:00
Ryuta Kamizono 3944fb743a Avoid to use slower `define_method` for `AcceptsMultiparameterTime`
This makes `datetime.serialize` about 10% faster.

```ruby
type = ActiveRecord::Type.lookup(:datetime)
time = Time.now.utc

Benchmark.ips do |x|
  x.report("type.serialize(time)") do
    type.serialize(time)
    type.serialize(time)
    type.serialize(time)
    type.serialize(time)
  end
end
```

Before:

```
Warming up --------------------------------------
type.serialize(time)    12.899k i/100ms
Calculating -------------------------------------
type.serialize(time)    131.293k (± 1.6%) i/s -    657.849k in   5.011870s
```

After:

```
Warming up --------------------------------------
type.serialize(time)    14.603k i/100ms
Calculating -------------------------------------
type.serialize(time)    145.941k (± 1.1%) i/s -    730.150k in   5.003639s
```
2020-06-17 19:45:00 +09:00
Ryuta Kamizono 0adcec4954 PERF: Avoid extra delegation to `LazyAttributeHash`
The extra delegation to `LazyAttributeHash` has non-negligible overhead.

Avoiding that delegation makes attributes access about 45% faster for
readonly (non-mutation) usage.

https://gist.github.com/kamipo/4002c96a02859d8fe6503e26d7be4ad8

Before:

```
IPS
Warming up --------------------------------------
    attribute access     1.000  i/100ms
Calculating -------------------------------------
    attribute access      3.444  (± 0.0%) i/s -     18.000  in   5.259030s
MEMORY
Calculating -------------------------------------
    attribute access    38.902M memsize (     0.000  retained)
                       350.044k objects (     0.000  retained)
                        15.000  strings (     0.000  retained)
```

After (with `immutable_strings_by_default = true`):

```
IPS
Warming up --------------------------------------
    attribute access     1.000  i/100ms
Calculating -------------------------------------
    attribute access      5.066  (±19.7%) i/s -     25.000  in   5.024650s
MEMORY
Calculating -------------------------------------
    attribute access    27.382M memsize (     0.000  retained)
                       160.044k objects (     0.000  retained)
                        15.000  strings (     0.000  retained)
```
2020-06-15 09:26:24 +09:00
Ryuta Kamizono 5090a64aa3 Lazy allocate `@forced_changes`
It is almost no longer used in Active Record.
2020-06-14 13:50:07 +09:00
Ryuta Kamizono 528b62e386 Address to false negative for Performance/DeletePrefix,DeleteSuffix
Follow up to c07dff7227.

Actually it is not the cop's fault, but we mistakenly use `^`, `$`, and
`\Z` in much places, the cop doesn't correct those conservatively.

I've checked all those usage and replaced all safe ones.
2020-06-14 13:04:47 +09:00
Ryuta Kamizono ab8b12eaf6 PERF: 35% faster attributes for readonly usage
Instantiating attributes hash from raw database values is one of the
slower part of attributes.

Why that is necessary is to detect mutations. In other words, that isn't
necessary until mutations are happened.

`LazyAttributeHash` which was introduced at 0f29c21 is to instantiate
attribute lazily until first accessing the attribute (i.e.
`Model.find(1)` isn't slow yet, but `Model.find(1).attr_name` is still
slow).

This introduces `LazyAttributeSet` to instantiate attribute more lazily,
it doesn't instantiate attribute until first assigning/dirty checking
the attribute (i.e. `Model.find(1).attr_name` is no longer slow).

It makes attributes access about 35% faster for readonly (non-mutation)
usage.

https://gist.github.com/kamipo/4002c96a02859d8fe6503e26d7be4ad8

Before:

```
IPS
Warming up --------------------------------------
    attribute access     1.000  i/100ms
Calculating -------------------------------------
    attribute access      3.444  (± 0.0%) i/s -     18.000  in   5.259030s
MEMORY
Calculating -------------------------------------
    attribute access    38.902M memsize (     0.000  retained)
                       350.044k objects (     0.000  retained)
                        15.000  strings (     0.000  retained)
```

After (with `immutable_strings_by_default = true`):

```
IPS
Warming up --------------------------------------
    attribute access     1.000  i/100ms
Calculating -------------------------------------
    attribute access      4.652  (±21.5%) i/s -     23.000  in   5.034853s
MEMORY
Calculating -------------------------------------
    attribute access    27.782M memsize (     0.000  retained)
                       170.044k objects (     0.000  retained)
                        15.000  strings (     0.000  retained)
```
2020-06-13 16:01:08 +09:00
Ryuta Kamizono 19839ff46c Fix string type cast with boolean serialization for MySQL
And benchmark with this branch for immutable string type:

```ruby
ActiveRecord::Schema.define do
  create_table :users, force: true do |t|
    t.string :name
    t.string :fast_name
  end
end

class User < ActiveRecord::Base
  attribute :fast_name, :immutable_string
end

user = User.new

Benchmark.ips do |x|
  x.report("user.name") do
    user.name = "foo"
    user.name_changed?
  end
  x.report("user.fast_name") do
    user.fast_name = "foo"
    user.fast_name_changed?
  end
end
```

```
Warming up --------------------------------------
           user.name    34.811k i/100ms
      user.fast_name    39.505k i/100ms
Calculating -------------------------------------
           user.name    343.864k (± 3.6%) i/s -      1.741M in   5.068576s
      user.fast_name    384.033k (± 2.7%) i/s -      1.936M in   5.044425s
```
2020-06-13 07:50:12 +09:00
Sean Griffin 332c3364b6 Add a setting to specify that all string columns should be immutable
In Rails 4.2 we introduced mutation detection, to remove the need to
call `attribute_will_change!` after modifying a field. One side effect
of that change was that we needed to enforce that the
`_before_type_cast` form of a value is a different object than the post
type cast value, if the value is mutable. That contract is really only
relevant for strings, but it meant we needed to dup them.

In Rails 5 we added the `ImmutableString` type, to allow people to opt
out of this duping in places where the memory usage was causing
problems, and they don't need to mutate that field.

This takes that a step further, and adds a class-level setting to
specify whether strings should be frozen by default or not. The default
value of this setting is `false` (strings are mutable), and I do not
plan on changing that.

While I think that immutable strings by default would be a reasonable
default for new applications, I do not think that we would be able to
document the value of this setting in a place that people will be
looking when they can't figure out why some string is frozen.
Realistically, the number of applications where this setting is relevant
is fairly small, so I don't think it would make sense to ever enable it
by default.
2020-06-11 15:07:06 +09:00
Ryuta Kamizono 27a1ca2bfe PERF: 15% faster attribute access
Delegating to just one line method is to not be worth it.
Avoiding the delegation makes `read_attribute` about 15% faster.

```ruby
ActiveRecord::Schema.define do
  create_table :users, force: true do |t|
    t.string :name
  end
end

class User < ActiveRecord::Base
  def fast_read_attribute(attr_name, &block)
    name = attr_name.to_s
    name = self.class.attribute_aliases[name] || name

    name = @primary_key if name == "id" && @primary_key
    @attributes.fetch_value(name, &block)
  end
end

user = User.create!(name: "user name")

Benchmark.ips do |x|
  x.report("read_attribute('id')") { user.read_attribute('id') }
  x.report("read_attribute('name')") { user.read_attribute('name') }
  x.report("fast_read_attribute('id')") { user.fast_read_attribute('id') }
  x.report("fast_read_attribute('name')") { user.fast_read_attribute('name') }
end
```

```
Warming up --------------------------------------
read_attribute('id')   165.744k i/100ms
read_attribute('name')
                       162.229k i/100ms
fast_read_attribute('id')
                       192.543k i/100ms
fast_read_attribute('name')
                       191.209k i/100ms
Calculating -------------------------------------
read_attribute('id')      1.648M (± 1.7%) i/s -      8.287M in   5.030170s
read_attribute('name')
                          1.636M (± 3.9%) i/s -      8.274M in   5.065356s
fast_read_attribute('id')
                          1.918M (± 1.8%) i/s -      9.627M in   5.021271s
fast_read_attribute('name')
                          1.928M (± 0.9%) i/s -      9.752M in   5.058820s
```
2020-06-05 09:12:21 +09:00
Ryuta Kamizono 7834363bbf Avoid redundant `to_s` in internal attribute API
Redundant `to_s` has a few overhead. Especially private methods are not
intend to be passed user input directly so it should be passed always
string.

Removing redundant `to_s` makes attribute methods about 10% faster.

```ruby
ActiveRecord::Schema.define do
  create_table :users, force: true do |t|
  end
end

class User < ActiveRecord::Base
  def fast_read_attribute(attr_name, &block)
    @attributes.fetch_value(attr_name, &block)
  end
end

user = User.create!

Benchmark.ips do |x|
  x.report("user._read_attribute('id')") { user._read_attribute("id") }
  x.report("user.fast_read_attribute('id')") { user.fast_read_attribute("id") }
end
```

```
Warming up --------------------------------------
user._read_attribute('id')
                       272.151k i/100ms
user.fast_read_attribute('id')
                       283.518k i/100ms
Calculating -------------------------------------
user._read_attribute('id')
                          2.699M (± 1.3%) i/s -     13.608M in   5.042846s
user.fast_read_attribute('id')
                          2.988M (± 1.2%) i/s -     15.026M in   5.029056s
```
2020-06-04 09:02:53 +09:00
Ryuta Kamizono 6f1bf2a3dd Promote `clear_attribute_change` as attribute methods
For now, `increment` with aliased attribute does work, but `increment!`
with aliased attribute does not work, due to `clear_attribute_change` is
not aware of attribute aliases.

We sometimes partially updates specific attributes in dirties, at that
time it relies on `clear_attribute_change` to clear partially updated
attribute dirties. If `clear_attribute_change` is not attribute method
unlike others, we need to resolve attribute aliases manually only for
`clear_attribute_change`, it is a little inconvinient for me.

From another point of view, we have `restore_attributes`,
`restore_attribute!`, `clear_attribute_changes`, and
`clear_attribute_change`. Despite almost similar features
`restore_attribute!` is an attribute method but `clear_attribute_change`
is not.

Given the above, I'd like to promote `clear_attribute_change` as
attribute methods to fix issues caused by the inconsisteny.
2020-06-04 04:17:17 +09:00
Aaron Patterson 35fe9bc0aa
Merge pull request #39477 from p8/improve-inspect
Make custom inspect methods more consistent
2020-06-03 10:43:35 -07:00
Ryuta Kamizono 4dbbba4a97 Don't call `ruby2_keywords` for user supplied block 2020-06-04 02:19:30 +09:00
Petrik 74cb9a6f38 Make inspect look more like regular Object#inspect
Move the # outside the < > just like regular Object#inspect
2020-05-29 21:53:35 +02:00
Ryuta Kamizono c65864cdca Prefer no allocation `start/end_with?` over `String#[] ==` 2020-05-29 10:20:13 +09:00
Eugene Kenny 7e14c16cc0 Optimise serializable_hash when options are empty
This reverts 8538dfdc08, which broke the
activemodel-serializers-xml gem.

We can still get most of the benefit by applying the optimisation from
7b39197742 to empty hashes as well as nil.
This has the additional benefit of retaining the optimisation when the
user passes an empty options hash.
2020-05-22 00:04:31 +01:00
Eugene Kenny 8538dfdc08 Reduce allocations in to_json's include option
Since 7b39197742, `serializable_hash`
allocates fewer objects when options is nil rather than empty.
2020-05-19 22:00:00 +01:00
Ryuta Kamizono fba016c7a3 Fix update with dirty locking column to not match latest object accidentally
Related #32163.

We should not identify an object by dirty value. If do so, accidentally
matches latest object even though it is a stale object.
2020-05-18 09:46:09 +09:00
fatkodima 7b39197742 Avoid allocating extra hash and arrays when as_json is called without options
Co-authored-by: Eugene Kenny <elkenny@gmail.com>
2020-05-17 22:54:55 +03:00
eileencodes 6833bf4d10
Remove implementation of unchecked_serialize
Since we're checking `serializable?` in the new `HomogeneousIn`
`serialize` will no longer raise an exception. We implemented
`unchecked_serialize` to avoid raising in these cases, but with some of
our refactoring we no longer need it.

I discovered this while trying to fix a query in our application that
was not properly serializing binary columns. I discovered that in at
least 2 of our active model types we were not calling the correct
serialization. Since `serialize` wasn't aliased to `unchecked_serialize`
in `ActiveModel::Type::Binary` and `ActiveModel::Type::Boolean` (I
didn't check others but pretty sure all the AM Types are broken) the SQL
was being treated as a `String` and not the correct type.

This caused Rails to incorrectly query by string values. This is
problematic for columns storing binary data like our emoji columns at
GitHub. The test added here is an example of how the Binary type was
broken previously. The SQL should be using the hex values, not the
string value of "🥦" or other emoji.

We still have the problem `unchecked_serialize` was supposed to fix -
that `serialize` shouldn't validate data, just convert it. We'll be
fixing that in a followup PR so for now we should use `serialize` so we
know all the values are going through the right serialization for their
SQL.
2020-05-12 13:37:22 -04:00
Akira Matsuda 1edf103b52 undef_method can take varargs 2020-05-08 23:58:01 +09:00
Ryuta Kamizono 12c2f44316 Remove redundant `squish` for single line message 2020-05-06 15:08:06 +09:00
eileencodes 70ddb8a704
Merge branch 'fix-array-builder-wheres' 2020-05-05 12:57:14 -04:00
Ryuta Kamizono 199e4e96d6 Attributes can be dup-ed 2020-05-06 00:40:48 +09:00
Ryuta Kamizono 776f2abc5a `Type::Value#initialize` doesn't take positional arguments
Follow up to 257d8f9792.
2020-05-05 20:40:37 +09:00
Ryuta Kamizono f93b04afab Deprecate marshalling load from legacy attributes format
Since #31827, marshalling attributes hash format is changed to improve
performance because materializing lazy attribute hash is too expensive.

In that time, we had kept an ability to load from legacy attributes
format, since that performance improvement is backported to 5-1-stable
and 5-0-stable.

Now all supported versions will dump attributes as new format, the
backward compatibity should no longer be needed.
2020-05-02 15:49:09 +09:00
eileencodes 272f2f081a
Use `range.member?` over `range.cover?`
Rails has a monkey patch on `range.cover?` that is slower than Ruby's
`range.cover?`. We don't need Range support in this case because the SQL
creates a `BETWEEN` not an `IN` statement.
2020-05-01 15:12:05 -04:00
eileencodes 72fd0bae59
Perf: Improve performance of where when using an array of values
A coworker at GitHub found a few months back that if we used
`santitize_sql` over `where` when we knew the values going into `where`
it was a lot faster than `where`.

This PR adds a new Arel node type called `HomogenousIn` that will be
used when Rails knows the values are all homogenous and can therefore
pick a faster codepath. This new codepath skips some of the required
processing by `where` to make `wheres` with homogenous arrays faster
without requiring the application author to know when to use which query
type.

Using our benchmark code:

```ruby
ids = (1..1000).each.map do |n|
  Post.create!.id
end

Benchmark.ips do |x|
  x.report("where with ids") do
    Post.where(id: ids).to_a
  end

  x.report("where with sanitize") do
    Post.where(ActiveRecord::Base.sanitize_sql(["id IN (?)", ids])).to_a
  end

  x.compare!
end
```

Before this PR comparing where with a list of IDs to santitize sql:

```
Warming up --------------------------------------
      where with ids    11.000  i/100ms
 where with sanitize    17.000  i/100ms

Calculating -------------------------------------
      where with ids    115.733  (± 4.3%) i/s -    583.000  in   5.045828s
 where with sanitize    174.231  (± 4.0%) i/s -    884.000  in   5.081495s

Comparison:
 where with sanitize:      174.2 i/s
      where with ids:      115.7 i/s - 1.51x  slower
```

After this PR comparing where with a list of IDs to santitize sql:

```
Warming up --------------------------------------
      where with ids    16.000  i/100ms
 where with sanitize    19.000  i/100ms

Calculating -------------------------------------
      where with ids    158.293  (± 6.3%) i/s -    800.000  in   5.072208s
 where with sanitize    169.141  (± 3.5%) i/s -    855.000  in   5.060878s

Comparison:
 where with sanitize:      169.1 i/s
      where with ids:      158.3 i/s - same-ish: difference falls within error
```

Co-authored-by: Aaron Patterson <aaron.patterson@gmail.com>
2020-05-01 15:12:05 -04:00
Jean Boussier d12418a776 Also batch attribute readers and writers 2020-05-01 12:21:16 +02:00
Jean Boussier 9e8bbf6fc9 Batch attribute methods definition in a single module_eval 2020-04-30 18:09:48 +02:00
Adam Hess 096f2d1f83 Reference updated errors attribute names method in deprecation warning 2020-04-22 09:08:42 -07:00
nimish b3c308dd20 Reject signed hexadecimal numbers while validating numericality 2020-04-22 12:15:57 +00:00
Rafael Mendonça França a4deb63798
No need to deprecate Errors#first
This deprecation is useless since the result is still an Error object
and there is no way to fix the code to remove the deprecation.

Let's just accept as a breaking change.
2020-04-13 19:07:59 -04:00
Rafael França 6f6f4e40ab
Merge pull request #36125 from lulalala/doc-for-model-errors
Document update for ActiveModel#errors
2020-04-13 14:11:55 -04:00
Rafael França 46cb94f6ed
Merge pull request #38903 from HParker/add-access-to-attributes-on-errors
Add attribute_names method on errors
2020-04-08 19:18:11 -04:00
Adam Hess 89eb554025 Add attribute_names method on errors
This method replaces the `keys` method on `errors` as a way to get the error attribute names from the errors object without treating `errors` like a hash.
2020-04-08 16:02:24 -07:00
Adam Hess 19ec6233cc Update the Active Model deprecation warning
This message more clearly communicates how to access the attribute and message keys that you would expect to get when using the previous API.

before you might iterate over errors like,

errors.each do |attribute, message|
  # My error code here
end

This message helps the user find the methods on error that match the previous API.
2020-04-08 15:43:38 -07:00
Ryuta Kamizono de8a404751
Merge pull request #38784 from JuanitoFatas/doc/am-absence-validator
Fix a typo in AbsenceValidator

[ci skip]
2020-03-21 22:49:56 +09:00
Juanito Fatas 1c9a427ca9 Fix a typo in AbsenceValidator 2020-03-21 21:24:38 +09:00
Tim Dorr 55fdf173cc
Tiny doc fix in .validates
This should be a string array literal. Simple as that :)
2020-03-17 11:08:50 -04:00
Ryuta Kamizono 1ef8c60dfc Avoid extra string allocation in the methods generated by eval 2020-03-10 17:43:35 +09:00
Rafael França df186bd16f
Merge pull request #38401 from vinistock/stop_stringifying_during_attribute_assignment
Do not stringify attributes in assign_attributes
2020-02-13 16:54:35 -05:00
aminamos 7bb0706f2c update from PR #36222 2020-02-12 13:31:43 -05:00
Vinicius Stock 2e9e940e22
Change safe guard to check for each_pair instead of stringify_keys 2020-02-07 11:36:35 -05:00
Vinicius Stock 112c3ec0f5
Only dup attributes in activerecord attribute_assignment 2020-02-06 17:02:56 -05:00
Vinicius Stock 8b59960cd4
Do not stringify attributes in assign_attributes 2020-02-06 16:27:24 -05:00
Jean Boussier 1e209d71b0 Save a string allocation for each attribute method call 2020-01-30 20:40:31 +01:00
Ryuta Kamizono dd77e787a0 Remove unnecessary `include ActiveModel::Model` in the doc [ci skip] 2020-01-29 11:40:41 +09:00
Ryuta Kamizono 1f08fec27e Generalize FrozenError on write attribute 2020-01-29 11:23:41 +09:00
George Claghorn a6841c720a Allow checking whether an attribute previously changed from/to a particular value 2020-01-27 16:38:24 -05:00
Ryuta Kamizono 501cb3eb68 Fix warnings for attribute methods with kwargs 2020-01-21 00:34:06 +09:00
Ryuta Kamizono 289d3db332 Defined attribute should not expand positional hash argument 2020-01-21 00:16:02 +09:00
lulalala fcd1e41e82 Document on ActiveModel::Errors changes
Mark private constants

Display alternative for deprecation removal warning

Annotate Error's attributes

More emphasis on adding an error instead of message

Rewrite scaffold template using new errors API

Set first and last with behavior change deprecation

Update more doc and example

Add inspect for easier debugging
2020-01-14 23:55:09 +08:00
Gannon McGibbon f72f743dc3 Add scale support to ActiveRecord::Validations::NumericalityValidator 2020-01-13 11:00:22 -05:00
Gannon McGibbon b5c9974fa7 Add ActiveRecord::Validations::NumericalityValidator
Add Active Record numericality validator with support for casting
floats using a database columns' precision value.
2020-01-06 19:01:29 -05:00
Abhay Nikam d8beb77252 Bump license years from 2019 to 2020 [ci skip] 2020-01-01 15:10:31 +05:30
Ryuta Kamizono 57ace94c42 Merge pull request #38038 from Shopify/activerecord-ruby-2.7-warnings-6-0-stable-batch-2
Activerecord ruby 2.7 warnings 6 0 stable batch 2
2019-12-20 19:43:49 +09:00
Richard e58f41af2d Api-docs validation defaults missing absence [ci skip] 2019-12-18 13:10:04 +00:00
Rafael França 886f397e98
Merge pull request #37088 from enriikke/fix-activemodel-error-frozen
Fix FrozenError on ActiveModel::Error clear and delete
2019-12-17 19:39:28 -03:00
Ryuta Kamizono 56f63552f1 Add missing period 2019-11-24 10:28:48 +09:00
Ryuta Kamizono 98754de141 Fix multi-threaded issue for `AcceptanceValidator` 2019-11-03 12:55:30 +09:00
Ryuta Kamizono 8d8011f0bb Simplify `LazilyDefineAttributes` 2019-10-21 22:30:34 +09:00
Chris Salzberg 4b67bd51c2
Rewrite LazilyDefineAttributes so that it removes itself
LazilyDefineAttributes only needs to stay in the model's ancestors long
enough to define accessors for acceptance attributes, after that it is
not needed anymore. To optimize this, we eagerly define attributes as
soon as either +method_missing+ or +respond_to_missing?+ is called, then
immediately remove those methods from the module so that future calls
will incur no performance penalty.

I've also removed the call to +define_attribute_methods+ here, which
is no longer be necessary to avoid an infinite loop.
2019-10-21 19:53:31 +09:00
Jonathan Hefner cd619e9781 Fix i18n of attributes with multi-digit indexes
Follow-up to #33615 and #37447.
2019-10-17 10:23:00 -04:00
Rafael França c2a002b98d
Merge pull request #37447 from jonathankwok/i18n-error-lookup-for-indexed-attribute
Support ActiveModel::Error translation lookup on indexed attributes.
2019-10-15 17:54:35 -04:00
jonathankwok 236e20e6fb Don't add new lookup; replace existing one instead 2019-10-15 15:18:07 -04:00
willnet 68b11a8dbb [ci skip]fix typo 2019-10-14 11:29:40 +09:00
jonathankwok 5c9b008f36 Support ActiveModel::Error translation lookup on indexed attributes.
Instances of ActiveModel::Error where `attribute` is a nested attribute
can use translation keys that don't include the index in their lookup key.
2019-10-11 17:15:02 -04:00
Kasper Timm Hansen 4c5da6093d
Merge pull request #37217 from joshmn/frozen_attributes
Raise FrozenError for frozen objects when trying to write to a non-database-backed attribute
2019-10-07 03:00:26 +02:00
Takayuki Nakata 6497096b85 Remove unused require
`except` and `slice` were removed at d2b78b3594
2019-10-03 09:51:16 +09:00
Matthew Draper ade48853d9
Merge pull request #36907 from wjessop/string_attribute_should_compare_with_typecast_symbol_after_update
Serialize symbols to strings in ImmutableString serialize method
2019-09-28 18:20:08 +09:30
Ryuta Kamizono 63299ce7a3 Revert register proc takes keyword arguments
Because Ruby 2.6 cannot ignore empty kwargs.

https://buildkite.com/rails/rails/builds/63958#9932c536-b1df-4d2c-bda0-c59ed0e254c1/987-995
2019-09-28 15:07:38 +09:00
Ryuta Kamizono 2cf74f6b87 Fix remaining keyword arguments warnings for Active Record
Except required `ruby2_keywords` things.
2019-09-28 14:42:25 +09:00
Josh Brody 54b1574421 Raise FrozenError for frozen objects when trying to write to a
non-database-backed attribute.

Writing to database-backed attributes after freezing an object would
raise FrozenError, but wouldn't raise FrozenError for user-defined
attributes.

Fixes #37208
2019-09-16 16:59:43 -05:00
Akira Matsuda 91712c5080 Fix Class#new + keyword arguments warnings 2019-09-09 01:02:39 +09:00
Akira Matsuda 13f9803215 rubocop 2019-09-08 09:47:54 +09:00
Akira Matsuda af99f45b58 Revert "Class#new also separates keyword arguments and optional hash"
This reverts commit 72c1aa21c1.

This causes CI fails on Ruby < 2.7
2019-09-08 09:44:47 +09:00
Akira Matsuda de3d9680ac Handle kwargs only in Ruby >= '2.7'
To avoid "ArgumentError: wrong number of arguments" in old rubies
2019-09-08 09:06:42 +09:00
Akira Matsuda 72c1aa21c1 Class#new also separates keyword arguments and optional hash 2019-09-08 08:58:01 +09:00
Akira Matsuda 1a40a48113 Registration#matches? takes keywords, and Registry#lookup is already called with keywords 2019-09-07 10:11:23 +09:00
Ryuta Kamizono d0ba1aa986 Revert "Include kwargs definition in the generated method signatures and method calls"
This reverts commit 0188b1c289.

CI was broken by that.

https://buildkite.com/rails/rails/builds/63488
2019-09-06 21:36:49 +09:00
Akira Matsuda 0188b1c289 Include kwargs definition in the generated method signatures and method calls 2019-09-06 18:52:00 +09:00
Akira Matsuda 1915255846 Revert "Include kwargs definition in the generated method signatures and method calls"
This reverts commit 9895d67d6d.

Reason: This causes CI failures in activerecord tests
2019-09-04 13:47:02 +09:00
Akira Matsuda 9895d67d6d Include kwargs definition in the generated method signatures and method calls 2019-09-04 12:45:27 +09:00
Akira Matsuda 257d8f9792 The super_method at Type::Value takes kwargs 2019-09-04 12:45:27 +09:00
Akira Matsuda 4645f2d34f Passing in a Hash instance as kwargs parameters requires the "double splat" prefix 2019-09-04 12:45:27 +09:00
Enrique Gonzalez 65f2180f19 Fix FrozenError on ActiveModel::Error clear and delete
This PR fixes a `FrozenError` when attempting to clear or delete
`ActiveModel::Errors` through the deprecated array methods. In
particular the error happens in the following situations:

    # calling `clear` on the deprecated array
    errors[:some_attribute].clear

    # calling `delete` on the deprecated messages hash
    errors.messages.delete(:some_attribute)

Following the recent introduction of `ActiveModel::Error`, this PR adds
deprecation warnings for those two messages.
2019-08-29 22:41:39 -04:00
Eugene Kenny d2e2ca0d0f Always load validator class to verify it exists
When updating our app for 9def05385f, I
found several incorrectly configured validations that looked like this:

    validates :name, uniqueness: true, case_sensitive: false

The intent is clearly for `case_sensitive: false` to be passed as an
option to the uniqueness validator, but instead it's being passed as
its own separate validation. Because the value `false` disables the
validation, the validator class isn't loaded and the failure is silent.

The validator should always be loaded, even if it's disabled, to ensure
it exists and avoid configuration errors like the one described above.
2019-08-26 11:52:34 +01:00
Will Jessop d110b7b877
Serialize symbols to strings in ImmutableString serialize method
Symbols serialize to strings when persisted:

    model.some_string = :foo
    model.save! # "foo" is persisted

This PR updates the immutable string class to serialize symbols to strings to mirror this behavior as ActiveModel::Attribute calls this serialize method to determine the return value for changed_in_place? Prior to this change this code would report that "something" had changed:

    comment = Comment.create! # (has a string "something" field)
    comment.update_column :something, :anything # persists "anything" to the "something" field of the comments table
    comment.something  # or comment.attributes
    comment.something_change # will be ["anything", "anything"], note these are `to` and `from` values, but are identical

After this PR the comment.something_change will return nil for this situation.

Fixes #36463
2019-08-10 23:37:37 +01:00
David Heinemeier Hansson a0bb19fbfa
Add *_previously_was attribute methods when dirty tracking (#36836) 2019-08-01 15:38:03 -07:00
Akira Matsuda 530f7805ed It may be better to explicitly require 'object/try' where we call `try`
In most cases it works now without explicit require because it's accidentally required through
active_support/core_ext/date_and_time/calculations.rb where we still call `try`,
but that would stop working if we changed the Calculations implementation and remove the require call there.
2019-08-01 18:51:51 +09:00
Akira Matsuda af2129b4c7 Use `try` only when we're unsure if the receiver would respond_to the method 2019-08-01 17:58:00 +09:00
Akira Matsuda 6dbfc67734 Accessing ivar with Symbols might be just a very little bit better than with fstrings 2019-07-31 12:18:44 +09:00
Akira Matsuda 0196551e60 Use match? where we don't need MatchData 2019-07-29 14:23:10 +09:00
Akira Matsuda 8f90ac7827 Add AS::TimeZone#match? 2019-07-29 14:17:36 +09:00
Akira Matsuda d1ffe59ab5 Use match? where we don't need MatchData
We're already running Performance/RegexpMatch cop, but it seems like the cop is not always =~ justice
2019-07-27 13:06:49 +09:00
Rafael França e5dc101cc5
Merge pull request #36005 from shioyama/plain_matcher_first
Make plain matcher match first, not last
2019-07-25 23:51:19 -04:00
Abhay Nikam 9a47db70c9 Fixed the typo in the deprecation error messages. Followup #36738 2019-07-23 23:33:32 +05:30
Edouard CHIN ff0204bc7f Modify behaviour of `AM::Errors#to_h`:
- `AM::Error#to_h` was kind of broken before and would return in the
  hash values a single error message.

  ```ruby
    person = Person.new
    person.errors.add(:name, "cannot be blank")
    person.errors.add(:name, "too long")

    puts person.errors.to_h # {name: 'too long'}
  ```

  Since an attribute can have different errors, the previous behavior
  didn't make much sense.

  Now, `ActiveModel::Errors#to_hash` correctly returns an array of
  error messages containing all the errors for an attribute.
  However, one can easily be surprised by this change, so let's
  deprecated it first.
2019-07-23 17:58:59 +02:00
Edouard CHIN 35ac22d6ef Deprecated `AM::Errors#to_h`:
- In ef4d3215b1 I made a change to
  pass `AM::Error` object in case the arity of the block passed to
  `each` accepted less than 2 arguments.

  This is causing one issue for `to_h` as it expects the argument
  passed to the block to be an Array (and were are passing it an
  instance of `AM::Error`).

  There is no real reason to use `to_h` anymore since `to_hash` exists

  Deprecating `to_h` inf favor of `to_hash`

Co-Authored-By: Rafael França <rafael@franca.dev>
2019-07-23 14:11:36 +02:00
Edouard CHIN ab21db050d Fix deprecation on `AM::Errors` when each is called indirectly:
- `AM::Errors#each` is implemented for the `Enumerator` module and
  get called indirectly by a bunch of method in the ruby land
  (map, first, select ...)

  These methods have a `-1` arity as they are written in C and they
  wrongly trigger a deprecation warning.

  This commit fixes that and correctectly return a `AM::Error` object
  when `each` is called with a negative arity.
2019-07-20 21:26:43 +02:00
Edouard CHIN d204a09df2 Switch to use `class_attribute`:
- Since `ActiveModel::Error` can now be inherited by
  `ActiveModel::NestedError`, when the latter generates a
  `full_message`, the `i18n_customize_full_message` accessor set in
  the parent class is not set.

  This commit fixes that by using a `class_attribute` instead.
2019-07-16 14:28:38 +02:00
Edouard CHIN b677adede0 Move the `ActiveModel:Errors#full_message` method to the `Error` class:
- One regression introduced by the "AM errors as object" features is
  about the `full_messages` method.

  It's currently impossible to call that method if the `base` object
  passed in the constructor of `AM::Errors` doesn't respond to the
  `errors` method.
  That's because `full_messages` now makes a weird back and forth trip

  `AM::Errors#full_messages` -> `AM::Error#full_message` -> `AM::Errors#full_message`

  Since `full_message` (singular) isn't needed by AM::Errors, I moved
  it to the `AM::Error` (singular) class. This way we don't need to
  grab the `AM::Errors` object from the base.
2019-07-16 14:28:38 +02:00
Rafael França 43c27e479a
Merge pull request #36654 from Edouard-chin/ec-errors-delete
Returns `nil` when `AM::Errors#delete` doesn't delete anything:
2019-07-15 20:41:16 +01:00
Rafael França bec7be8800
Merge pull request #36649 from Edouard-chin/ec-errors-strit-match-collection
Fix `AM::Errors.added?` trying to generate a message:
2019-07-15 20:36:40 +01:00
Rafael França 69cb9eb7ad
Merge pull request #36640 from Edouard-chin/ec-uniq-validation-fix
Fix errors getting duplicated when passed validations options:
2019-07-15 20:35:05 +01:00
Akira Matsuda 356857a122 active_support/deprecation has to be already required via active_support/rails.rb 2019-07-12 18:34:07 +09:00
Edouard CHIN 4a8cf10148 Returns `nil` when `AM::Errors#delete` doesn't delete anything:
- `AM::Errors#delete` currently returns an empty array when trying
  to delete an error that doesn't exist.

  This behaviour is surprising and I think it would be better
  to no return a truthy value but instead return nil like
  `Hash#delete` does.
2019-07-11 01:41:14 +02:00
Edouard CHIN 06756290d5 Fix `AM::Errors.added?` trying to generate a message:
- When a ActiveRecord record get saved and validated as part of a
  collection association, the errors attribute are changed to reflect
  the children names. You end up with an error attribute that will
  look like this:

  `author.errors # {:'books.title' => [:blank]}`

  2fe20cb55c/activerecord/lib/active_record/autosave_association.rb (L331-L340)

  We then can't check if the `books.title` errors was added using
  `ActiveModel::Errors#added?` because it tries to generate a message
  to make the match and end up calling the "books.title" method
  on the Author.

  ```
  author.errors.added?(:'books.title', :blank) => NoMethodError: undefined method `books.title'
  ```

  This patch modify the behaviour of `strict_match?` to not generate
  a message to make the comparison but instead make a strict
  comparison with the `options` from the error.
2019-07-10 23:33:32 +02:00
Edouard CHIN 07ff343857 Fix errors getting duplicated when passed validations options:
- In 86620cc3aa, a change was made
  on how we remove error duplication on a record for autosave
  association

  This fix has one caveat where validation having a `if` / `unless`
  options passed as a proc would be considered different.
  Example:

  ```ruby
  class Book < ApplicationRecord
    has_one :author

    validates :title, presence: true, if -> { true }
    validates :title, presence: true, if -> { true }
  end

  Book.new.valid? # false
  Book.errors.full_messages # ["title can't be blank", "title can't be blank"]
  ```

  While this example might sound strange, I think it's better to
  ignore `AM::Validations` options (if, unless ...) when making the
  comparison.
2019-07-10 18:40:12 +02:00
John Gesimondo 4093238d0a
Update docs on dirty.rb
`previously_changed` seems to actually be `previous_changes`
2019-07-05 10:24:01 -07:00
Ryuta Kamizono d29d459897 Avoid redundant `time.getutc` call if it is already utc time object
Currently `type.serialize` and `connection.{quote|type_cast}` for a time
object always does `time.getutc` call regardless of whether it is
already utc time object or not, that duplicated proccess
(`connection.type_cast(type.serialize(time))`) allocates extra/useless
time objects for each type casting.

This avoids that redundant `time.getutc` call if it is already utc time
object. In the case of a model has timestamps (`created_at` and
`updated_at`), it avoids 6,000 time objects allocation for 1,000 times
`model.save`.

```ruby
ObjectSpace::AllocationTracer.setup(%i{path line type})

pp ObjectSpace::AllocationTracer.trace {
  1_000.times { User.create }
}.select { |k, _| k[0].end_with?("quoting.rb", "time_value.rb") }
```

Before (c104bfe424):

```
{["~/rails/activerecord/lib/active_record/connection_adapters/abstract/quoting.rb",
  203,
  :T_ARRAY]=>[1004, 0, 778, 0, 1, 0],
 ["~/rails/activerecord/lib/active_record/connection_adapters/abstract/quoting.rb",
  220,
  :T_STRING]=>[2, 0, 2, 1, 1, 0],
 ["~/rails/activerecord/lib/active_record/connection_adapters/abstract/quoting.rb",
  209,
  :T_ARRAY]=>[8, 0, 8, 1, 1, 0],
 ["~/rails/activerecord/lib/active_record/connection_adapters/abstract/quoting.rb",
  57,
  :T_ARRAY]=>[4, 0, 4, 1, 1, 0],
 ["~/rails/activemodel/lib/active_model/type/helpers/time_value.rb",
  17,
  :T_DATA]=>[4000, 0, 3096, 0, 1, 0],
 ["~/rails/activerecord/lib/active_record/connection_adapters/abstract/quoting.rb",
  120,
  :T_DATA]=>[2000, 0, 1548, 0, 1, 0],
 ["~/rails/activerecord/lib/active_record/connection_adapters/abstract/quoting.rb",
  126,
  :T_STRING]=>[4000, 0, 3096, 0, 1, 0]}
```

After (this change):

```
{["~/rails/activerecord/lib/active_record/connection_adapters/abstract/quoting.rb",
  203,
  :T_ARRAY]=>[1004, 0, 823, 0, 1, 0],
 ["~/rails/activerecord/lib/active_record/connection_adapters/abstract/quoting.rb",
  220,
  :T_STRING]=>[2, 0, 2, 1, 1, 0],
 ["~/rails/activerecord/lib/active_record/connection_adapters/abstract/quoting.rb",
  209,
  :T_ARRAY]=>[8, 0, 8, 1, 1, 0],
 ["~/rails/activerecord/lib/active_record/connection_adapters/abstract/quoting.rb",
  57,
  :T_ARRAY]=>[4, 0, 4, 1, 1, 0],
 ["~/rails/activerecord/lib/active_record/connection_adapters/abstract/quoting.rb",
  126,
  :T_STRING]=>[2000, 0, 1638, 0, 1, 0]}
```
2019-06-18 01:03:21 +09:00
Ryuta Kamizono c81af6ae72 Enable `Layout/EmptyLinesAroundAccessModifier` cop
We sometimes say "✂️ newline after `private`" in a code review (e.g.
https://github.com/rails/rails/pull/18546#discussion_r23188776,
https://github.com/rails/rails/pull/34832#discussion_r244847195).

Now `Layout/EmptyLinesAroundAccessModifier` cop have new enforced style
`EnforcedStyle: only_before` (https://github.com/rubocop-hq/rubocop/pull/7059).

That cop and enforced style will reduce the our code review cost.
2019-06-13 12:00:45 +09:00
Chris Salzberg 38c0bf7dfa
Remove plain method 2019-05-31 12:55:59 +09:00
Chris Salzberg dd0357aeb8
Make plain matcher match first, not last
This code takes the "plain" matcher with no prefix and suffix and puts
it at the end of the matchers array such that it is de-prioritized among
all matchers. The comment explaining this code, originally from commimt
8b8b7143ef dated in 2011, is in a context where detection from matchers
happened immediately. In that situation, the plain matcher would indeed
always match first and no others would ever be used.

However, the current code does not immediately detect one match but
rather maps matchers to matches for the method_name. Detection only
happens for matches whose attribute name is valid.

In this context, there is no need to bump the plain matcher to the end
of the array, since it will only be selected if the attribute name it
catpures matches a valid attribute name.
2019-05-31 12:55:59 +09:00
Ryuta Kamizono 497e52f8c2 Don't round off subseconds unless necessary
Currently, if `:datetime` type has a precision, type casting always does
round off subseconds regardless of whether necessary or not, it is a bit
slow.

Since #34970, `t.timestamps` with `precision: 6` by default, so
`pluck(:created_at)` in newly created app will always be affected by the
round off.

This avoids the round off if possible, it makes `pluck(:created_at)`
about 25% faster.

https://gist.github.com/kamipo/e029539f2632aee9f5e711fe66fc8842

Before (0a87d7c9dd with postgresql adapter):

```
Warming up --------------------------------------
    users.pluck(:id)      344.000  i/100ms
  users.pluck(:name)      336.000  i/100ms
users.pluck(:created_at)  206.000  i/100ms
Calculating -------------------------------------
    users.pluck(:id)      3.620k (± 8.5%) i/s -     18.232k in   5.077316s
  users.pluck(:name)      3.579k (± 9.4%) i/s -     17.808k in   5.020230s
users.pluck(:created_at)  2.069k (± 8.0%) i/s -     10.300k in   5.019284s
```

Before (0a87d7c9dd with mysql2 adapter):

```
Warming up --------------------------------------
    users.pluck(:id)      245.000  i/100ms
  users.pluck(:name)      240.000  i/100ms
users.pluck(:created_at)  180.000  i/100ms
Calculating -------------------------------------
    users.pluck(:id)      2.548k (± 9.4%) i/s -     12.740k in   5.066574s
  users.pluck(:name)      2.513k (± 8.0%) i/s -     12.480k in   5.011260s
users.pluck(:created_at)  1.771k (±11.2%) i/s -      8.820k in   5.084473s
```

After (this change with postgresql adapter):

```
Warming up --------------------------------------
    users.pluck(:id)      348.000  i/100ms
  users.pluck(:name)      357.000  i/100ms
users.pluck(:created_at)  254.000  i/100ms
Calculating -------------------------------------
    users.pluck(:id)      3.628k (± 8.2%) i/s -     18.096k in   5.024748s
  users.pluck(:name)      3.624k (±12.4%) i/s -     17.850k in   5.020959s
users.pluck(:created_at)  2.567k (± 7.0%) i/s -     12.954k in   5.081153s
```

After (this change with mysql2 adapter):

```
Warming up --------------------------------------
    users.pluck(:id)      268.000  i/100ms
  users.pluck(:name)      265.000  i/100ms
users.pluck(:created_at)  207.000  i/100ms
Calculating -------------------------------------
    users.pluck(:id)      2.586k (±10.9%) i/s -     12.864k in   5.050546s
  users.pluck(:name)      2.543k (±10.2%) i/s -     12.720k in   5.067726s
users.pluck(:created_at)  2.263k (±14.5%) i/s -     10.971k in   5.004039s
```
2019-05-28 22:50:36 +09:00
Gannon McGibbon 93ef75615e
Merge pull request #36092 from imechemi/update-doc
Improve doc for :root option in as_json()
2019-05-13 12:06:49 -04:00
Tenzin Chemi 42a3ec8fee Improve doc for :root option in as_json() [ci skip]
Remove trailing whitespace [ci skip]

Reword

Root value should be string [ci skip]
2019-05-13 15:35:50 +05:30
Guo Xiang Tan 25f1e0e3ea Recover perf for `pluck` by reverting 9c9c950d02.
This reverts commit 9c9c950d02.
2019-05-03 22:36:23 +08:00
Aaron Patterson 2ada222f1e
any? should be delegated to the errors list
Otherwise we get deprecation warnings in the generated scaffold template files
2019-04-30 16:54:40 -05:00
Abhay Nikam 1cd24e5d00 Change the deprecation for Enumerating ActiveModel::Errors to Rails 6.1 instead of 6.0 (#36087)
* Change the deprecation for Enumerating ActiveModel::Errors to Rails 6.1 instead of 6.0

* Changed the deprecation message for ActiveModel::Errors methods: slice, values, keys and to_xml
2019-04-25 13:13:01 +09:00
Rafael França d4d145a679
Merge pull request #32313 from lulalala/model_error_as_object
Model error as object
2019-04-24 16:16:00 -04:00
Rafael Mendonça França 9834be6565
Start Rails 6.1 development 2019-04-24 15:57:14 -04:00
Ryuta Kamizono 5575bd7b22 Avoid redundant `attribute_alias?` before `attribute_alias`
If we want to get alias resolved attribute finally, we can use
`attribute_alias` directly.

For that purpose, avoiding redundant `attribute_alias?` makes alias
attribute access 40% faster.

https://gist.github.com/kamipo/e427f080a27b46f50bc508fae3612a0e

Before (2c0729d8):

```
Warming up --------------------------------------
          user['id']   102.668k i/100ms
      user['new_id']    80.660k i/100ms
        user['name']    99.368k i/100ms
    user['new_name']    81.626k i/100ms
Calculating -------------------------------------
          user['id']      1.431M (± 4.0%) i/s -      7.187M in   5.031985s
      user['new_id']      1.042M (± 4.2%) i/s -      5.243M in   5.039858s
        user['name']      1.406M (± 5.6%) i/s -      7.055M in   5.036743s
    user['new_name']      1.074M (± 3.6%) i/s -      5.387M in   5.024152s
```

After (this change):

```
Warming up --------------------------------------
          user['id']   109.775k i/100ms
      user['new_id']   103.303k i/100ms
        user['name']   105.988k i/100ms
    user['new_name']    99.618k i/100ms
Calculating -------------------------------------
          user['id']      1.520M (± 6.7%) i/s -      7.574M in   5.011496s
      user['new_id']      1.485M (± 6.2%) i/s -      7.438M in   5.036252s
        user['name']      1.538M (± 5.4%) i/s -      7.737M in   5.049765s
    user['new_name']      1.516M (± 4.6%) i/s -      7.571M in   5.007293s
```
2019-04-24 18:46:23 +09:00
Rafael França 6a4eb3e75e
Merge pull request #36061 from shioyama/update_comment
Update comment in attribute_method_matchers_matching
2019-04-23 11:16:53 -04:00
Chris Salzberg 14ff93c4bc
Update comment in attribute_method_matchers_matching
The current comment here is from 2011 and its original context has
changed completely. The plain matcher will not "match every time"
anymore since the code now filters all matchers, and only selects those
for which the captured attribute is valid.

To avoid confusion, I updated the comment. For more discussion, see:

https://github.com/rails/rails/pull/36005
2019-04-23 14:24:40 +09:00
Daniel Colson e7a28c3990
Add attribute_names to ActiveModel::Attributes
This adds `.attribute_names` and `#attribute_names` to
`ActiveModel::Attributes` along the same lines as the corresponding
methods in `ActiveRecord::AttributeMethods` (see
[`.attribute_names`][class_method] and
[`#attribute_names`][instance_method].

While I was here I also added documentation for '#attributes', which I
added in 043ce35b18. The whole class is still `#:nodoc:` so I don't
think this will have any effect for now.

[class_method]: cc834db1d0/activerecord/lib/active_record/attribute_methods.rb (L154-L160)
[instance_method]: cc834db1d0/activerecord/lib/active_record/attribute_methods.rb (L299-L301)
2019-04-22 19:48:17 -04:00
Chris Salzberg c9d75177fe
Improve wording of comments
Most of the time, these methods are called from actual methods defined
from columns in the schema, not from method_missing, so the current
wording is misleading.
2019-04-13 11:12:39 +09:00
Chris Salzberg bdcdb2b35f
Rename method_missing_target to target
The target of matchers is used in two contexts: to define attribute
methods which dispatch to handlers like attribute_was, and to match
method calls in method_missing and dispatch to those same handler
methods.

Only in the latter context does the term "method_missing_target" make
any sense; in the former context it is just confusing. "target" is not
ideal as a term but at least it avoids this confusion.
2019-04-13 10:41:57 +09:00
Chris Salzberg 63b5bdea51
Remove unused method_name from AttributeMethodMatch 2019-04-12 23:35:26 +09:00
Chris Salzberg 0bd4552e02
Rename "method" to "matcher" in map block 2019-04-12 15:19:09 +09:00
Ryuta Kamizono 6b0a9de906 PERF: 2x ~ 30x faster dirty tracking
Currently, although using both dirty tracking (ivar backed and
attributes backed) on one model is not supported (doesn't fully work at
least), both dirty tracking are being performed, that is very slow.

As long as attributes backed dirty tracking is used, ivar backed dirty
tracking should not need to be performed.

I've refactored to extract new `ForcedMutationTracker` which only tracks
`force_change` to be performed for ivar backed dirty tracking, that
makes dirty tracking on Active Record 2x ~ 30x faster.

https://gist.github.com/kamipo/971dfe0891f0fe1ec7db8ab31f016435

Before:

```
Warming up --------------------------------------
            changed?     4.467k i/100ms
             changed     5.134k i/100ms
             changes     3.023k i/100ms
  changed_attributes     4.358k i/100ms
        title_change     3.185k i/100ms
           title_was     3.381k i/100ms
Calculating -------------------------------------
            changed?     42.197k (±28.5%) i/s -    187.614k in   5.050446s
             changed     50.481k (±16.0%) i/s -    246.432k in   5.045759s
             changes     30.799k (± 7.2%) i/s -    154.173k in   5.030765s
  changed_attributes     51.530k (±14.2%) i/s -    252.764k in   5.041106s
        title_change     44.667k (± 9.0%) i/s -    222.950k in   5.040646s
           title_was     44.635k (±16.6%) i/s -    216.384k in   5.051098s
```

After:

```
Warming up --------------------------------------
            changed?    24.130k i/100ms
             changed    13.503k i/100ms
             changes     6.511k i/100ms
  changed_attributes     9.226k i/100ms
        title_change    48.221k i/100ms
           title_was    96.060k i/100ms
Calculating -------------------------------------
            changed?    245.478k (±16.1%) i/s -      1.182M in   5.015837s
             changed    157.641k (± 4.9%) i/s -    796.677k in   5.066734s
             changes     70.633k (± 5.7%) i/s -    358.105k in   5.086553s
  changed_attributes     95.155k (±13.6%) i/s -    470.526k in   5.082841s
        title_change    566.481k (± 3.5%) i/s -      2.845M in   5.028852s
           title_was      1.487M (± 3.9%) i/s -      7.493M in   5.046774s
```
2019-04-11 16:30:40 +09:00
Ryuta Kamizono 50fba828d5 Refactor `has_secure_password` to extract dedicated attribute module
Follow up of #26764 and #35700.

And add test case for #35700.
2019-04-05 01:55:00 +09:00
Ryuta Kamizono dc45130c44
Merge pull request #35700 from Futurelearn/seb-secure-password-fix
Reintroduce support for overriding `has_secure_password` attributes
2019-04-05 01:19:08 +09:00
lulalala aaa0c32797 Set default array to details
maintaining behavior errors.details[:foo].any?
2019-03-31 22:59:13 +08:00
lulalala f7f42a2d0e Fix messages[]= does not override value 2019-03-31 22:59:13 +08:00
lulalala 514c4b4d53 Freeze DeprecationHandling array and hash 2019-03-31 22:59:13 +08:00
lulalala e7834214a6 Fix equality comparison raising error bug 2019-03-31 22:59:13 +08:00
lulalala 90815b12c5 Fix spec 2019-03-31 22:59:12 +08:00
lulalala ba38b40e83 Split messages and to_hash
Fix double wrapping issue
Revert messages_for wrapping. It's a new method so no need to put
deprecation warnings.
2019-03-31 22:59:12 +08:00
lulalala abee034368 Raise deprecation for calling `[:f] = 'b'` or `[:f] << 'b'`
Revert some tests to ensure back compatibility
2019-03-31 22:59:12 +08:00
lulalala 67d262f70f Add deprecation to slice! 2019-03-31 22:59:12 +08:00
lulalala be1585fca0 Nested attribute error's attribute name to use different key:
To keep the same as SHA dcafe995bf
2019-03-31 22:59:12 +08:00
lulalala 582a8e2f94 String override options in #import to convert to symbol 2019-03-31 22:59:12 +08:00
lulalala 86620cc3aa Allow errors to remove duplicates, and ensure cyclic associations w/ autosave duplicate errors can be removed
See SHA 7550f0a016
2019-03-31 22:59:12 +08:00
lulalala 2a06f13099 Add messages_for 2019-03-31 22:59:12 +08:00
lulalala cccbac6df6 Add a transitional method `objects`, for accessing the array directly.
This is because we try to accommodate old hash behavior, so `first` and `last` now does not return Error object.
2019-03-31 22:59:12 +08:00