aboutsummaryrefslogtreecommitdiffstats
path: root/activemodel/lib
Commit message (Collapse)AuthorAgeFilesLines
...
* | | | PERF: Recover marshaling dump/load performance (#31827)Ryuta Kamizono2018-02-021-9/+11
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | * PERF: Recover marshaling dump/load performance This performance regression which is described in #30680 was caused by f0ddf87 due to force materialized `LazyAttributeHash`. Since 95b86e5, default proc has been removed in the class, so it is no longer needed that force materialized. Avoiding force materialized will recover marshaling dump/load performance. Benchmark: https://gist.github.com/blimmer/1360ea51cd3147bae8aeb7c6d09bff17 Before: ``` it took 0.6248569069430232 seconds to unmarshal the objects Total allocated: 38681544 bytes (530060 objects) allocated memory by class ----------------------------------- 12138848 Hash 10542384 String 7920000 ActiveModel::Attribute::Uninitialized 5600000 ActiveModel::Attribute::FromDatabase 1200000 Foo 880000 ActiveModel::LazyAttributeHash 400000 ActiveModel::AttributeSet 80 Integer 72 ActiveRecord::ConnectionAdapters::SQLite3Adapter::SQLite3Integer 40 ActiveModel::Type::String 40 ActiveRecord::Type::DateTime 40 Object 40 Range allocated objects by class ----------------------------------- 250052 String 110000 ActiveModel::Attribute::Uninitialized 70001 Hash 70000 ActiveModel::Attribute::FromDatabase 10000 ActiveModel::AttributeSet 10000 ActiveModel::LazyAttributeHash 10000 Foo 2 Integer 1 ActiveModel::Type::String 1 ActiveRecord::ConnectionAdapters::SQLite3Adapter::SQLite3Integer 1 ActiveRecord::Type::DateTime 1 Object 1 Range ``` After: ``` it took 0.1660824950085953 seconds to unmarshal the objects Total allocated: 13883811 bytes (220090 objects) allocated memory by class ----------------------------------- 5743371 String 4940008 Hash 1200000 Foo 880000 ActiveModel::LazyAttributeHash 720000 Array 400000 ActiveModel::AttributeSet 80 ActiveModel::Attribute::FromDatabase 80 Integer 72 ActiveRecord::ConnectionAdapters::SQLite3Adapter::SQLite3Integer 40 ActiveModel::Type::String 40 ActiveModel::Type::Value 40 ActiveRecord::Type::DateTime 40 Object 40 Range allocated objects by class ----------------------------------- 130077 String 50004 Hash 10000 ActiveModel::AttributeSet 10000 ActiveModel::LazyAttributeHash 10000 Array 10000 Foo 2 Integer 1 ActiveModel::Attribute::FromDatabase 1 ActiveModel::Type::String 1 ActiveModel::Type::Value 1 ActiveRecord::ConnectionAdapters::SQLite3Adapter::SQLite3Integer 1 ActiveRecord::Type::DateTime 1 Object 1 Range ``` Fixes #30680. * Keep the `@delegate_hash` to avoid to lose any mutations that have been made to the record
* | | | Start Rails 6.0 development!!!Rafael Mendonça França2018-01-301-3/+3
| | | | | | | | | | | | | | | | :tada::tada::tada:
* | | | Use respond_to test helpersDaniel Colson2018-01-251-12/+12
| | | |
* | | | Allow attributes with a proc default to be marshalledSean Griffin2018-01-231-0/+22
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | We don't implement much custom marshalling logic for these objects, but the proc default case needs to be handled separately. Unfortunately there's no way to just say "do what you would have done but with this value for one ivar", so we have to manually implement `marshal_load` as well. The test case is a little bit funky, but I'd really like an equality test in there, and there's no easy way to add one now that this is out of AR (since the `attributes` method isn't here) Fixes #31216
* | | | Use singular define_attribute_methodDaniel Colson2018-01-211-1/+1
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | `define_attribute_methods` splats the arguments, then calls out to `define_attribute_method` for each. When defining a singule attribute, using the singular version of the method saves us an array and an extra method call.
* | | | PERF: Recover `changes_applied` performance (#31698)Ryuta Kamizono2018-01-222-70/+43
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | #30985 caused `object.save` performance regression since calling `changes` in `changes_applied` is very slow. We don't need to call the expensive method in `changes_applied` as long as `@attributes` is tracked by mutation tracker. https://gist.github.com/kamipo/1a9f4f3891803b914fc72ede98268aa2 Before: ``` Warming up -------------------------------------- create_string_columns 73.000 i/100ms Calculating ------------------------------------- create_string_columns 722.256 (± 5.8%) i/s - 3.650k in 5.073031s ``` After: ``` Warming up -------------------------------------- create_string_columns 96.000 i/100ms Calculating ------------------------------------- create_string_columns 950.224 (± 7.7%) i/s - 4.800k in 5.084837s ```
* | | | `deep_dup` is used in `AttributeSet#deep_dup`Ryuta Kamizono2018-01-132-1/+1
| | | |
* | | | Merge pull request #29018 from willbryant/missing_attributes_after_saveRyuta Kamizono2018-01-031-0/+4
|\ \ \ \ | | | | | | | | | | | | | | | fix the dirty tracking code's save hook overwriting missing attribute…
* | | | | Refactor to `Array(options[:on])` only once in defining validationsRyuta Kamizono2018-01-012-11/+13
| | | | |
* | | | | Bump license years for 2018Yoshiyuki Hirano2017-12-311-1/+1
| | | | |
* | | | | Fix validation callbacks on multiple contextYoshiyuki Hirano2017-12-201-9/+13
| |_|_|/ |/| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | I found a bug that validation callbacks don't fire on multiple context. So I've fixed it. Example: ```ruby class Dog include ActiveModel::Validations include ActiveModel::Validations::Callbacks attr_accessor :history def initialize @history = [] end before_validation :set_before_validation_on_a, on: :a before_validation :set_before_validation_on_b, on: :b after_validation :set_after_validation_on_a, on: :a after_validation :set_after_validation_on_b, on: :b def set_before_validation_on_a; history << "before_validation on a"; end def set_before_validation_on_b; history << "before_validation on b"; end def set_after_validation_on_a; history << "after_validation on a" ; end def set_after_validation_on_b; history << "after_validation on b" ; end end ``` Before: ``` d = Dog.new d.valid?([:a, :b]) d.history # [] ``` After: ``` d = Dog.new d.valid?([:a, :b]) d.history # ["before_validation on a", "before_validation on b", "after_validation on a", "after_validation on b"] ```
* | | | Fix doc typo [ci skip]Tom Copeland2017-12-121-1/+1
| | | |
* | | | Update validates.rbLonre Wang2017-12-101-1/+1
| | | |
* | | | Preparing for 5.2.0.beta2 releaseRafael Mendonça França2017-11-281-1/+1
| | | |
* | | | Change how `AttributeSet::Builder` receives its defaultsSean Griffin2017-11-272-15/+15
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | There are two concerns which are both being combined into one here, but both have the same goal. There are certain attributes which we want to always consider initialized. Previously, they were handled separately. The primary key (which is assumed to be backed by a database column) needs to be initialized, because there is a ton of code in Active Record that assumes `foo.id` will never raise. Additionally, we want attributes which aren't backed by a database column to always be initialized, since we would never receive a database value for them. Ultimately these two concerns can be combined into one. The old implementation hid a lot of inherent complexity, and is hard to optimize from the outside. We can simplify things significantly by just passing in a hash. This has slightly different semantics from the old behavior, in that `Foo.select(:bar).first.id` will return the default value for the primary key, rather than `nil` unconditionally -- however, the default value is always `nil` in practice.
* | | | Preparing for 5.2.0.beta1 releaseRafael Mendonça França2017-11-271-1/+1
| | | |
* | | | Merge pull request #31117 from renuo/fix_errors_addedRafael França2017-11-131-3/+7
|\ \ \ \ | | | | | | | | | | fix bug on added? method
| * | | | fix bug on added? methodAlessandro Rodi2017-11-131-3/+7
| | | | | | | | | | | | | | | | | | | | fix rubocop issues
* | | | | Add missing autoload `Type` (#31123)Ryuta Kamizono2017-11-113-2/+1
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Attribute modules (`Attribute`, `Attributes`, `AttributeSet`) uses `Type`, but referencing `Type` before the modules still fail. ``` % ./bin/test -w test/cases/attribute_test.rb -n test_with_value_from_user_validates_the_value Run options: -n test_with_value_from_user_validates_the_value --seed 31876 E Error: ActiveModel::AttributeTest#test_with_value_from_user_validates_the_value: NameError: uninitialized constant ActiveModel::AttributeTest::Type /Users/kamipo/src/github.com/rails/rails/activemodel/test/cases/attribute_test.rb:233:in `block in <class:AttributeTest>' bin/test test/cases/attribute_test.rb:232 Finished in 0.002985s, 335.0479 runs/s, 335.0479 assertions/s. 1 runs, 1 assertions, 0 failures, 1 errors, 0 skips ``` Probably we need more autoloading at least `Type`.
* | | | | Add missing require "active_support/core_ext/hash/indifferent_access"Ryuta Kamizono2017-11-101-0/+2
| | | | | | | | | | | | | | | | | | | | https://travis-ci.org/rails/rails/jobs/300163454#L2236
* | | | | Add missing requiresyuuji.yaginuma2017-11-101-0/+1
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Currently, executing the test with only `attribute_test.rb` results in an error. ``` ./bin/test -w test/cases/attribute_test.rb Run options: --seed 41205 # Running: ....E Error: ActiveModel::AttributeTest#test_attributes_do_not_equal_attributes_with_different_types: NameError: uninitialized constant ActiveModel::AttributeTest::Type rails/activemodel/test/cases/attribute_test.rb:159:in `block in <class:AttributeTest>' bin/test test/cases/attribute_test.rb:158 ``` Added a missing require to fix this.
* | | | | Merge pull request #31114 from y-yagi/fix_ruby_warnings_in_active_modelRyuta Kamizono2017-11-102-3/+3
|\ \ \ \ \ | | | | | | | | | | | | Fix ruby warnings in Active Model
| * | | | | Fix "warning: assigned but unused variable - name"yuuji.yaginuma2017-11-101-1/+1
| | | | | |
| * | | | | Fix "warning: instance variable @attributes not initialized"yuuji.yaginuma2017-11-101-2/+2
| |/ / / /
* / / / / Add missing requiresyuuji.yaginuma2017-11-101-0/+2
|/ / / / | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Currently, executing the test with only `attribute_set_test.rb` results in an error. ``` ./bin/test -w test/cases/attribute_set_test.rb Run options: --seed 33470 # Running: E Error: ActiveModel::AttributeSetTest#test_#map_returns_a_new_attribute_set_with_the_changes_applied: NameError: uninitialized constant ActiveModel::AttributeSetTest::AttributeSet Did you mean? ActiveModel::Attributes ActiveModel::Attribute activemodel/test/cases/attribute_set_test.rb:235:in `block in <class:AttributeSetTest>' bin/test test/cases/attribute_set_test.rb:234 ``` Added a missing require to fix this. Also, I suspect that this is the cause of failures in CI. Ref: https://travis-ci.org/rails/rails/jobs/299994708
* | | | Move Attribute and AttributeSet to ActiveModelLisa Ugray2017-11-0910-74/+828
| | | | | | | | | | | | | | | | | | | | Use these to back the attributes API. Stop automatically including ActiveModel::Dirty in ActiveModel::Attributes, and make it optional.
* | | | Execute `ConfirmationValidator` validation when `_confirmation`'s value is ↵bogdanvlviv2017-11-051-1/+1
| | | | | | | | | | | | | | | | `false`
* | | | Allow passing a Proc or Symbol as an argument to length validator valuesMatt Rohrer2017-10-261-2/+8
| | | | | | | | | | | | | | | | | | | | This brings the Length validator in line with the Numericality validator, which currently supports Proc & Symbol arguments
* | | | Merge pull request #30920 from lugray/attributes_to_amSean Griffin2017-10-231-0/+89
|\ \ \ \ | | | | | | | | | | Start bringing attributes API to AM
| * | | | Start bringing attributes API to AMLisa Ugray2017-10-181-0/+89
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | This is the first PR of a WIP to bring the attributes API to ActiveModel. It is not yet ready for public API. The `attributes_dirty_test.rb` file was created based on `dirty_test.rb`, and the simplifications in the diff do much to motivate this change. ``` diff activemodel/test/cases/dirty_test.rb activemodel/test/cases/attributes_dirty_test.rb 3a4 > require "active_model/attributes" 5c6 < class DirtyTest < ActiveModel::TestCase --- > class AttributesDirtyTest < ActiveModel::TestCase 7,41c8,12 < include ActiveModel::Dirty < define_attribute_methods :name, :color, :size < < def initialize < @name = nil < @color = nil < @size = nil < end < < def name < @name < end < < def name=(val) < name_will_change! < @name = val < end < < def color < @color < end < < def color=(val) < color_will_change! unless val == @color < @color = val < end < < def size < @size < end < < def size=(val) < attribute_will_change!(:size) unless val == @size < @size = val < end --- > include ActiveModel::Model > include ActiveModel::Attributes > attribute :name, :string > attribute :color, :string > attribute :size, :integer ```
* | | | | [Active Model] require => require_relativeAkira Matsuda2017-10-217-25/+25
|/ / / / | | | | | | | | | | | | This basically reverts ee5cfc01a5797f854c8441539b0cae326a81b963
* | | | Clarify intentions around method redefinitionsMatthew Draper2017-09-011-2/+2
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Don't use remove_method or remove_possible_method just before a new definition: at best the purpose is unclear, and at worst it creates a race condition. Instead, prefer redefine_method when practical, and silence_redefinition_of_method otherwise.
* | | | Use tt in doc for ActiveRecord [ci skip]Yoshiyuki Hirano2017-08-271-2/+2
| | | |
* | | | Simplify ActiveModel::Errors#generate_messageViktar Basharymau2017-08-181-7/+5
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Besides making the code easier to read, this commit also makes it faster: * We don't eval `@base.class.respond_to?(:i18n_scope)` twice * We only eval `@base.class.i18n_scope` once * We don't call `flatten!` because it's not needed anymore * We don't call `compact` because all elements are Symbols
* | | | [ci skip] Postgres --> PostgreSQLRyuta Kamizono2017-08-081-1/+1
| | | |
* | | | Talk about bytes not charactersRafael Mendonça França2017-07-311-3/+3
| | | | | | | | | | | | | | | | | | | | | | | | [ci skip] Closes #30012
* | | | Merge pull request #29788 from kamipo/remove_unused_mutex_mRafael França2017-07-171-7/+4
|\ \ \ \ | | | | | | | | | | Remove unused `Mutex_m` in Active Model
| * | | | Make `generated_attribute_methods` to privateRyuta Kamizono2017-07-141-4/+4
| | | | | | | | | | | | | | | | | | | | Because `generated_attribute_methods` is an internal API.
| * | | | Remove unused `Mutex_m` in Active ModelRyuta Kamizono2017-07-141-4/+1
| | | | |
* | | | | Allow multiparameter assigned attributes to be used with `text_field`Sean Griffin2017-07-172-0/+8
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Between 4.2 and 5.0 the behavior of how multiparameter attributes interact with `_before_type_cast` changed. In 4.2 it returns the post-type-cast value. After 5.0, it returns the hash that gets sent to the type. This behavior is correct, but will cause an issue if you then tried to render that value in an input like `text_field` or `hidden_field`. In this case, we want those fields to use the post-type-cast form, instead of the `_before_type_cast` (the main reason it uses `_before_type_cast` at all is to avoid losing data when casting a non-numeric string to integer). I've opted to modify `came_from_user?` rather than introduce a new method for this as I want to avoid complicating that contract further, and technically the multiparameter hash didn't come from assignment, it was constructed internally by AR. Close #27888.
* | | | | Use frozen string literal in activemodel/Kir Shatrov2017-07-1652-0/+104
|/ / / /
* | | | Add ActiveModel::Errors#merge!Jahfer Husain2017-07-071-0/+12
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | ActiveModel::Errors#merge! allows ActiveModel::Errors to append errors from a separate ActiveModel::Errors instance onto their own. Example: person = Person.new person.errors.add(:name, :blank) errors = ActiveModel::Errors.new(Person.new) errors.add(:name, :invalid) person.errors.merge!(errors) puts person.errors.messages # => { name: ["can't be blank", "is invalid"] }
* | | | Fix `ActiveModel::Type::DateTime#serialize`Lisa Ugray2017-07-051-0/+4
| | | | | | | | | | | | | | | | | | | | `ActiveModel::Type::DateTime#serialize` should return a `Time` object so that finding by a datetime column works correctly.
* | | | [Active Model] require => require_relativeAkira Matsuda2017-07-017-23/+23
| | | |
* | | | Fix call-seq typo s/==/<=>/ [ci skip]Ryuta Kamizono2017-06-211-1/+1
| | | | | | | | | | | | | | | | Fixes #29512.
* | | | add frozen string literal commentshotat2017-06-151-1/+3
| | | |
* | | | freeze stringshotat2017-06-141-1/+1
| | | |
* | | | enhance active model assignmentshotat2017-06-141-2/+3
| | | |
* | | | Docs: Fix output representation [ci skip]Viktor Fonic2017-05-311-2/+2
| | | | | | | | | | | | The output of two string attributes is displayed differently in the docs. Standardize the output by always showing it as a comment.
* | | | Add option for class_attribute default (#29270)David Heinemeier Hansson2017-05-293-7/+4
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | * Allow a default value to be declared for class_attribute * Convert to using class_attribute default rather than explicit setter * Removed instance_accessor option by mistake * False is a valid default value * Documentation