aboutsummaryrefslogtreecommitdiffstats
path: root/activemodel/lib
Commit message (Collapse)AuthorAgeFilesLines
* `validates_acceptance_of` shouldn't require a database connectionSean Griffin2015-09-251-4/+51
| | | | | | | | | | | | | The implementation of `attribute_method?` on Active Record requires establishing a database connection and querying the schema. As a general rule, we don't want to require database connections for any class macro, as the class should be able to be loaded without a database (e.g. for things like compiling assets). Instead of eagerly defining these methods, we do it lazily the first time they are accessed via `method_missing`. This should not cause any performance hits, as it will only hit `method_missing` once for the entire class.
* Improve the performance of `save` and friendsSean Griffin2015-09-241-2/+2
| | | | | | | | | | | | | | | | | | | | | | The biggest source of the performance regression in these methods occurred because dirty tracking required eagerly materializing and type casting the assigned values. In the previous commits, I've changed dirty tracking to perform the comparisons lazily. However, all of this is moot when calling `save`, since `changes_applied` will be called, which just ends up eagerly materializing everything, anyway. With the new mutation tracker, it's easy to just compare the previous two hashes in the same lazy fashion. We will not have aliasing issues with this setup, which is proven by the fact that we're able to detect nested mutation. Before: User.create! 2.007k (± 7.1%) i/s - 10.098k After: User.create! 2.557k (± 3.5%) i/s - 12.789k Fixes #19859
* Clean up the implementation of AR::DirtySean Griffin2015-09-242-0/+11
| | | | | | | | | | | | | This moves a bit more of the logic required for dirty checking into the attribute objects. I had hoped to remove the `with_value_from_database` stuff, but unfortunately just calling `dup` on the attribute objects isn't enough, since the values might contain deeply nested data structures. I think this can be cleaned up further. This makes most dirty checking become lazy, and reduces the number of object allocations and amount of CPU time when assigning a value. This opens the door (but doesn't quite finish) to improving the performance of writes to a place comparable to 4.1
* Merge pull request #21218 from repinel/fix-as-callback-terminatorKasper Timm Hansen2015-09-232-0/+2
|\ | | | | WIP: Fix the AS::Callbacks terminator regression from 4.2.3
| * Fix the AS::Callbacks terminator regression from 4.2.3Roque Pinel2015-09-222-0/+2
| | | | | | | | | | | | Rails 4.2.3 AS::Callbacks will not halt chain if `false` is returned. That is the behavior of specific callbacks like AR::Callbacks and AM::Callbacks.
* | Merge pull request #20317Sean Griffin2015-09-232-9/+12
|\ \ | |/ |/| | | | | AR: take precision into count when assigning a value to timestamp attribute
| * Fixed taking precision into count when assigning a value to timestamp attributeBogdan Gusiev2015-09-232-9/+12
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Timestamp column can have less precision than ruby timestamp In result in how big a fraction of a second can be stored in the database. m = Model.create! m.created_at.usec == m.reload.created_at.usec # => false # due to different seconds precision in Time.now and database column If the precision is low enough, (mysql default is 0, so it is always low enough by default) the value changes when model is reloaded from the database. This patch fixes that issue ensuring that any timestamp assigned as an attribute is converted to column precision under the attribute.
* | AMo typosAkira Matsuda2015-09-221-2/+2
|/
* Require dependencies from stdlib in the Decimal typeSean Griffin2015-09-211-0/+2
| | | | | | | In Active Record, it appears these were either autoloaded, which actually was likely due to test ordering since the method `Float#to_d` wouldn't trigger it. This makes it explicit, and unlikely to fail in the future.
* Remove no-op options being passed in AM type registrationsSean Griffin2015-09-211-11/+11
| | | | | | The `override` option is only a thing for Active Record registrations. We should figure out how to make this properly error out without doing anything too weird to the code.
* Move the appropriate type tests to the Active Model suiteSean Griffin2015-09-211-2/+8
| | | | | | | | | Any tests for a type which is not overridden by Active Record, and does not test the specifics of the attributes API interacting in more complex ways have no reason to be in the Active Record suite. Doing this revealed that the implementation of the date and time types in AM was actually completely broken, and incapable of returning any value other than `nil`.
* Simplify the implementation of Active Model's type registrySean Griffin2015-09-211-97/+10
| | | | | | | | | | | | | | | Things like decorations, overrides, and priorities only matter for Active Record, so the Active Model registry can be implemented much more simply. At this point, I wonder if having Active Record's registry inherit from Active Model's is even worth the trouble? The Active Model class was also missing test cases, which have been backfilled. This removes the error when two types are registered with the same name, but given that Active Model is meant to be significantly more generic, I do not think this is an issue for now. If we want, we can raise an error at the point that someone tries to register it.
* Various stylistic nitpicksSean Griffin2015-09-211-4/+3
| | | | | | | We do not need to require each file from AM individually, the type module does that for us. Even if the classes are extremely small right now, I'd rather keep any custom classes needed by AR in their own files, as they can easily have more complex changes in the future.
* `TypeMap` and `HashLookupTypeMap` shouldn't be in Active ModelSean Griffin2015-09-213-89/+0
| | | | | | These are used by the connection adapters to convert SQL type information into the appropriate type object, and makes no sense outside of the context of Active Record
* Move ActiveRecord::Type to ActiveModelKir Shatrov2015-09-2123-0/+987
| | | | The first step of bringing typecasting to ActiveModel
* Replaced `ThreadSafe::Map` with successor `Concurrent::Map`.Jerry D'Antonio2015-09-191-2/+2
| | | | | | | The thread_safe gem is being deprecated and all its code has been merged into the concurrent-ruby gem. The new class, Concurrent::Map, is exactly the same as its predecessor except for fixes to two bugs discovered during the merge.
* File encoding is defaulted to utf-8 in Ruby >= 2.1Akira Matsuda2015-09-181-2/+0
|
* Validate multiple contexts on `valid?` and `invalid?` at once.Dmitry Polushkin2015-09-071-1/+1
| | | | | | | | | | | | | | | | | | Example: ```ruby class Person include ActiveModel::Validations attr_reader :name, :title validates_presence_of :name, on: :create validates_presence_of :title, on: :update end person = Person.new person.valid?([:create, :update]) # => true person.errors.messages # => {:name=>["can't be blank"], :title=>["can't be blank"]} ```
* Revert "Merge pull request #21069 from ↵Rafael Mendonça França2015-09-071-1/+1
| | | | | | | | | dmitry/feature/validate-multiple-contexts-at-once" This reverts commit 51dd2588433457960cca592d5b5dac6e0537feac, reversing changes made to ecb4e4b21b3222b823fa24d4a0598b1f2f63ecfb. This broke Active Record tests
* Merge pull request #21069 from dmitry/feature/validate-multiple-contexts-at-onceRafael Mendonça França2015-09-071-1/+1
|\ | | | | | | Validate multiple contexts on `valid?` and `invalid?` at once
| * Validate multiple contexts on `valid?` and `invalid?` at once.Dmitry Polushkin2015-07-301-1/+1
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Example: ```ruby class Person include ActiveModel::Validations attr_reader :name, :title validates_presence_of :name, on: :create validates_presence_of :title, on: :update end person = Person.new person.valid?([:create, :update]) # => true person.errors.messages # => {:name=>["can't be blank"], :title=>["can't be blank"]} ```
* | Fix failure introduced by #17351 due to the new mocks implementationCarlos Antonio da Silva2015-09-011-1/+1
| | | | | | | | | | | | | | It was not expecting the new `case_insensitive` option to be passed to `generate_message`, instead of fixing the test we can just not pass this option down since it is specific to the confirmation validator and not necessary for the error message.
* | Fix syntax error introduced by #17351.Jashank Jeremy2015-09-011-1/+1
| |
* | Merge pull request #17351 from akshat-sharma/masterRafael Mendonça França2015-09-011-4/+16
|\ \ | | | | | | | | | Add case_sensitive option for confirmation validation
| * | Add case_sensitive option for confirmation validationAkshat Sharma2015-09-011-4/+16
| | | | | | | | | | | | | | | | | | | | | Case :- 1. In case of email confirmation one needs case insensitive comparison 2. In case of password confirmation one needs case sensitive comparison [ci skip] Update Guides for case_sensitive option in confirmation validation
* | | Tiny documentation improvements [ci skip]Robin Dupret2015-08-281-2/+3
| | |
* | | discard xml Serialization documentation that is no longer available [ci skip]Gaurav Sharma2015-08-221-5/+3
| | |
* | | Rename match_attribute_method? to matched_attribute_methodMarcin Olichwirowicz2015-08-121-4/+4
| | | | | | | | | | | | | | | `match_attribute_method?` is a bit confusing because it suggest that a return value is a boolean which is not true.
* | | Remove XML Serialization from core.Zachary Scott2015-08-073-242/+0
| | | | | | | | | | | | | | | | | | | | | This includes the following classes: - ActiveModel::Serializers::Xml - ActiveRecord::Serialization::XmlSerializer
* | | Freeze string literals when not mutated.schneems2015-07-193-3/+3
| |/ |/| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | I wrote a utility that helps find areas where you could optimize your program using a frozen string instead of a string literal, it's called [let_it_go](https://github.com/schneems/let_it_go). After going through the output and adding `.freeze` I was able to eliminate the creation of 1,114 string objects on EVERY request to [codetriage](codetriage.com). How does this impact execution? To look at memory: ```ruby require 'get_process_mem' mem = GetProcessMem.new GC.start GC.disable 1_114.times { " " } before = mem.mb after = mem.mb GC.enable puts "Diff: #{after - before} mb" ``` Creating 1,114 string objects results in `Diff: 0.03125 mb` of RAM allocated on every request. Or 1mb every 32 requests. To look at raw speed: ```ruby require 'benchmark/ips' number_of_objects_reduced = 1_114 Benchmark.ips do |x| x.report("freeze") { number_of_objects_reduced.times { " ".freeze } } x.report("no-freeze") { number_of_objects_reduced.times { " " } } end ``` We get the results ``` Calculating ------------------------------------- freeze 1.428k i/100ms no-freeze 609.000 i/100ms ------------------------------------------------- freeze 14.363k (± 8.5%) i/s - 71.400k no-freeze 6.084k (± 8.1%) i/s - 30.450k ``` Now we can do some maths: ```ruby ips = 6_226k # iterations / 1 second call_time_before = 1.0 / ips # seconds per iteration ips = 15_254 # iterations / 1 second call_time_after = 1.0 / ips # seconds per iteration diff = call_time_before - call_time_after number_of_objects_reduced * diff * 100 # => 0.4530373333993266 miliseconds saved per request ``` So we're shaving off 1 second of execution time for every 220 requests. Is this going to be an insane speed boost to any Rails app: nope. Should we merge it: yep. p.s. If you know of a method call that doesn't modify a string input such as [String#gsub](https://github.com/schneems/let_it_go/blob/b0e2da69f0cca87ab581022baa43291cdf48638c/lib/let_it_go/core_ext/string.rb#L37) please [give me a pull request to the appropriate file](https://github.com/schneems/let_it_go/blob/b0e2da69f0cca87ab581022baa43291cdf48638c/lib/let_it_go/core_ext/string.rb#L37), or open an issue in LetItGo so we can track and freeze more strings. Keep those strings Frozen ![](https://www.dropbox.com/s/z4dj9fdsv213r4v/let-it-go.gif?dl=1)
* | Revert "Revert "Reduce allocations when running AR callbacks.""Guo Xiang Tan2015-07-162-2/+2
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | This reverts commit bdc1d329d4eea823d07cf010064bd19c07099ff3. Before: Calculating ------------------------------------- 22.000 i/100ms ------------------------------------------------- 229.700 (± 0.4%) i/s - 1.166k Total Allocated Object: 9939 After: Calculating ------------------------------------- 24.000 i/100ms ------------------------------------------------- 246.443 (± 0.8%) i/s - 1.248k Total Allocated Object: 7939 ``` begin require 'bundler/inline' rescue LoadError => e $stderr.puts 'Bundler version 1.10 or later is required. Please update your Bundler' raise e end gemfile(true) do source 'https://rubygems.org' # gem 'rails', github: 'rails/rails', ref: 'bdc1d329d4eea823d07cf010064bd19c07099ff3' gem 'rails', github: 'rails/rails', ref: 'd2876141d08341ec67cf6a11a073d1acfb920de7' gem 'arel', github: 'rails/arel' gem 'sqlite3' gem 'benchmark-ips' end require 'active_record' require 'benchmark/ips' ActiveRecord::Base.establish_connection('sqlite3::memory:') ActiveRecord::Migration.verbose = false ActiveRecord::Schema.define do create_table :users, force: true do |t| t.string :name, :email t.boolean :admin t.timestamps null: false end end class User < ActiveRecord::Base default_scope { where(admin: true) } end admin = true 1000.times do attributes = { name: "Lorem ipsum dolor sit amet, consectetur adipiscing elit.", email: "foobar@email.com", admin: admin } User.create!(attributes) admin = !admin end GC.disable Benchmark.ips(5, 3) do |x| x.report { User.all.to_a } end key = if RUBY_VERSION < '2.2' :total_allocated_object else :total_allocated_objects end before = GC.stat[key] User.all.to_a after = GC.stat[key] puts "Total Allocated Object: #{after - before}" ```
* | docs, clarify the meanaing of return values from validation methods.Yves Senn2015-07-071-0/+3
| | | | | | | | | | | | | | | | | | | | [ci skip] Closes #20792. Custom validation methods are implemented in terms of callbacks. The `validate` callback chain can't be halted using return values of individual callbacks.
* | docs, remove accidental :nodoc: of ActiveModel::Validations::ClassMethods ↵Yves Senn2015-07-071-2/+1
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | methods. [ci skip] While this :nodoc: did hide the constant it also removed the following methods from the API docs: - #attribute_method? - #clear_validators! - #validate - #validators - #validators_on Those are public API and should be visible. Issue was caused by dee4fbc /cc @zzak
* | Separate the constraint and other options [ci skip]Robin Dupret2015-07-011-3/+8
| | | | | | | | | | | | | | | | | | | | Only one constraint option can be used at a time (except for the minimum and maximum ones that can eventually be combined). However, other options can be used with them (e.g. the validation failure message). So let's make the distinction between these two different options categories. [Yves Senn, Matthew Draper & Robin Dupret]
* | Improve Validation Helpers' documentation comments and testsRadan Skoric2015-06-273-7/+10
| |
* | A few documentation fixes [ci skip]Robin Dupret2015-06-231-1/+1
| |
* | Add nodoc to the Validations::Helpers [ci skip]Mehmet Emin İNAÇ2015-06-221-1/+1
| |
* | docs, :scissors: wrongly placed heading. [ci skip]Yves Senn2015-06-221-2/+0
| | | | | | | | | | The heading "Active Model Length Validator" was shown on the "ActiveModel::Validations" page without any text following it.
* | Move the validations HelperMethods to its own fileRoque Pinel2015-06-212-10/+13
| | | | | | | | | | | | Closes #11209 [Roque Pinel & Steven Yang]
* | Revert "Add code example for include option of ↵Rafael Mendonça França2015-06-101-14/+1
| | | | | | | | | | | | | | | | AM::Serialization#serializable_hash" This reverts commit 3d949f34816d6eca0a6b59cfa08d91f36e8e64dd. This was already documented in other PR.
* | Add code example for include option of AM::Serialization#serializable_hashRadan Skoric2015-06-091-1/+14
| |
* | Tiny documentation edits [ci skip]Robin Dupret2015-06-071-2/+2
| |
* | Merge pull request #20004 from rusikf/patch-1Robin Dupret2015-06-071-0/+31
|\ \ | | | | | | add docs to include option at ActiveModel::Serialization [ci skip]
| * | add docs to include option at ActiveModel::Serialization#serializable_hash ↵rusikf2015-05-111-0/+31
| | | | | | | | | | | | [ci skip]
* | | formatting changesunknown2015-05-292-5/+5
| | |
* | | minor rdoc syntax fix [ci skip]Gourav Tiwari2015-05-081-2/+2
| | |
* | | Adds/Corrects use case for adding an error messageZamith2015-05-041-1/+1
|/ / | | | | | | | | I believe this is a use case that was supposed to be supported, and it's a small fix.
* | ensure `method_missing` called for non-existing methods passed toJay Elaraj2015-04-281-1/+1
| | | | | | | | `ActiveModel::Serialization#serializable_hash`
* | Don't document private internal constant [ci skip]Zachary Scott2015-04-261-0/+1
| |
* | Fix grammar/style: assigns/declares -> assignments/declarations.Tim Wade2015-04-241-3/+3
| | | | | | | | [ci skip]