| Commit message (Collapse) | Author | Age | Files | Lines |
| |
|
|
|
|
|
|
|
|
|
| |
Instance level writers can have an impact on how the Active Model /
Record objects are saved. Specifically, they can be used to bypass
validations. This is a problem if mass assignment protection is
disabled and specific attributes are passed to the constructor.
CVE-2016-0753
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
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"]}
```
|
|
|
|
|
|
|
|
|
| |
dmitry/feature/validate-multiple-contexts-at-once"
This reverts commit 51dd2588433457960cca592d5b5dac6e0537feac, reversing
changes made to ecb4e4b21b3222b823fa24d4a0598b1f2f63ecfb.
This broke Active Record tests
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
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"]}
```
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
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}"
```
|
|
|
|
|
|
|
|
|
|
| |
[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.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
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
|
| |
|
|
|
|
| |
This reverts commit 796cab45561fce268aa74e6587cdb9cae3bb243e.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
I'm not sure what's the use case for this, but apparently it broke some apps.
Since it was not the intended result from #16210 I fixed it to not raise an
exception anymore. However, I didn't add documentation for it because I don't
know if this should be officially supported without knowing how it's meant to
be used.
In general, validations should be side-effect-free (other than adding to the
error message to `@errors`). Order-dependent validations seems like a bad idea.
Fixes #18002
|
|
|
|
| |
This will avoid naming clash with user defined methods
|
|\
| |
| |
| |
| | |
justinweiss/update_validation_context_documentation
Docs: Add a note on custom validation contexts. [ci skip]
|
| |
| |
| |
| |
| |
| |
| |
| |
| | |
The documentation on `:on` for validations was inconsistent, and most
only referenced the `:create` and `:update` contexts. I fixed those to
be consistent with the documentation on `AM::Validations.validates`,
which seemed to have the best docs.
[ci skip]
|
| | |
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| | |
Inspired by @tenderlove's work in
c363fff29f060e6a2effe1e4bb2c4dd4cd805d6e, this reduces the number of
strings allocated when running callbacks for ActiveRecord instances. I
measured that using this script:
```
require 'objspace'
require 'active_record'
require 'allocation_tracer'
ActiveRecord::Base.establish_connection adapter: "sqlite3",
database: ":memory:"
ActiveRecord::Base.connection.instance_eval do
create_table(:articles) { |t| t.string :name }
end
class Article < ActiveRecord::Base; end
a = Article.create name: "foo"
a = Article.find a.id
N = 10
result = ObjectSpace::AllocationTracer.trace do
N.times { Article.find a.id }
end
result.sort.each do |k,v|
p k => v
end
puts "total: #{result.values.map(&:first).inject(:+)}"
```
When I run this against master and this branch I get this output:
```
pete@balloon:~/projects/rails/activerecord$ git checkout master
M Gemfile
Switched to branch 'master'
pete@balloon:~/projects/rails/activerecord$ bundle exec ruby benchmark_allocation_with_callback_send.rb > allocations_before
pete@balloon:~/projects/rails/activerecord$ git checkout remove-dynamic-send-on-built-in-callbacks
M Gemfile
Switched to branch 'remove-dynamic-send-on-built-in-callbacks'
pete@balloon:~/projects/rails/activerecord$ bundle exec ruby benchmark_allocation_with_callback_send.rb > allocations_after
pete@balloon:~/projects/rails/activerecord$ diff allocations_before allocations_after
39d38
<
{["/home/pete/projects/rails/activesupport/lib/active_support/callbacks.rb",
81]=>[40, 0, 0, 0, 0, 0]}
42c41
< total: 630
---
> total: 590
```
In addition to this, there are two micro-optimizations present:
* Using `block.call if block` vs `yield if block_given?` when the block was being captured already.
```
pete@balloon:~/projects$ cat benchmark_block_call_vs_yield.rb
require 'benchmark/ips'
def block_capture_with_yield &block
yield if block_given?
end
def block_capture_with_call &block
block.call if block
end
def no_block_capture
yield if block_given?
end
Benchmark.ips do |b|
b.report("block_capture_with_yield") { block_capture_with_yield }
b.report("block_capture_with_call") { block_capture_with_call }
b.report("no_block_capture") { no_block_capture }
end
pete@balloon:~/projects$ ruby benchmark_block_call_vs_yield.rb
Calculating -------------------------------------
block_capture_with_yield
124979 i/100ms
block_capture_with_call
138340 i/100ms
no_block_capture 136827 i/100ms
-------------------------------------------------
block_capture_with_yield
5703108.9 (±2.4%) i/s - 28495212 in 4.999368s
block_capture_with_call
6840730.5 (±3.6%) i/s - 34169980 in 5.002649s
no_block_capture 5821141.4 (±2.8%) i/s - 29144151 in 5.010580s
```
* Defining and calling methods instead of using send.
```
pete@balloon:~/projects$ cat benchmark_method_call_vs_send.rb
require 'benchmark/ips'
class Foo
def tacos
nil
end
end
my_foo = Foo.new
Benchmark.ips do |b|
b.report('send') { my_foo.send('tacos') }
b.report('call') { my_foo.tacos }
end
pete@balloon:~/projects$ ruby benchmark_method_call_vs_send.rb
Calculating -------------------------------------
send 97736 i/100ms
call 151142 i/100ms
-------------------------------------------------
send 2683730.3 (±2.8%) i/s - 13487568 in 5.029763s
call 8005963.9 (±2.7%) i/s - 40052630 in 5.006604s
```
The result of this is making typical ActiveRecord operations slightly faster:
https://gist.github.com/phiggins/e46e51dcc7edb45b5f98
|
| | |
|
| |
| |
| |
| |
| | |
- Improve the error message by suggesting that the user may have
intended to call validates instead of validate method.
|
|\ \
| |/
|/|
| | |
Use #model_name on instances instead of classes
|
| |
| |
| |
| |
| |
| | |
This allows rails code to be more confdent when asking for a model name, instead of having to ask for the class.
Rails core discussion here: https://groups.google.com/forum/#!topic/rubyonrails-core/ThSaXw9y1F8
|
| | |
|
|/
|
|
|
|
|
|
|
|
|
| |
This change prevents a certain class of user error which results when
mistakenly using the `validate` class method instead of the `validates`
class method.
Only apply when all arguments are symbols, because some validations use
the `validate` method and pass in additional options, namely the
`LenghValidator` via the `ActiveMode::Validations::validates_with`
method.
|
|
|
|
|
|
|
|
| |
It's unintuitive to call '#valid?' when you want to run validations but
don't care about the return value.
The alias in ActiveRecord isn't strictly necessary (the ActiveModel
alias is still in effect), but it clarifies.
|
| |
|
|
|
|
|
|
| |
Example:
validates_presence_of :name, on: [:update, :custom_validation_context]
|
|
|
|
|
|
| |
& Xavier Noria]
Closes #11247.
|
|
|
|
| |
links in rdoc [ci skip]
|
| |
|
| |
|
|
|
|
|
| |
I also attempted to fix other styleguide violations such as
{ a: :b } over {a: :b} and foo(b: 'bar') over foo( b: 'bar' ).
|
|
|
|
| |
rest of the code the wat the includes are done
|
|
|
|
|
|
| |
it only cleared the validations that created :validate callbacks. This
didn't include the validates created by validates_with, so I've added a
method to clear all validations.
|
| |
|
| |
|
|\
| |
| |
| |
| |
| | |
Conflicts:
activesupport/lib/active_support/core_ext/hash/slice.rb
guides/source/active_support_core_extensions.md
|
| | |
|
| | |
|
|/ |
|
|
|
|
| |
Thanks to @jeremy to teach me this one.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
This reverts commit 4e9f53f9736544f070e75e516c71137b7eb49a7a, reversing
changes made to 6b802cdb4f5b84e1bf49aaeb0e994b3be6028af9.
Revert "Don't use tap in this case."
This reverts commit 454d820bf0a18fe1db4c55b0145197d70fef1f82.
Reason: Is not a good idea to add options to this method since we can do
the same thing using method composition.
Person.validators_on(:name).select { |v| v.kind == :presence }
Also it avoids to change the method again to add more options.
|
|
|
|
|
| |
The use of tap in this case is very confusing since we are mutating the
return value inside the block
|
|
|
|
|
| |
This will filter out the validators on a particular attribute based on
its kind.
|
|\
| |
| |
| |
| |
| | |
Conflicts:
activemodel/lib/active_model/secure_password.rb
activerecord/lib/active_record/associations/collection_proxy.rb
|
| | |
|
|/ |
|
|
|
|
|
|
|
|
| |
There's no need to create two extra hashes with options.merge(another_hash),
with the goal of setting only one value, so lets just set it.
Also refactor validates_each to use _merge_attributes, like other
validates_* helpers do.
|
|\ |
|
| | |
|
| | |
|