| Commit message (Collapse) | Author | Age | Files | Lines |
|
|
|
|
|
|
|
|
| |
When the association's primary key is manually set as a symbol and called with an array of strings, CollectionAssociation#ids_writer
fails to cast the ids to integers. This is because
AssociationReflection#association_primary_key_type and
ThroughReflection#association_primary_key_type return the incorrect
type, since ModelSchema.type_for_attribute only accepts a string. The
result is an ActiveRecord::RecordNotFound error.
|
| |
|
|
|
|
|
|
|
|
| |
The idea of `class_name` as an option of reflection is that passing a
string would allow us to lazy autoload the class.
Using `belongs_to :client, class_name: Customer` is eagerloading models more than necessary
and creating possible circular dependencies.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
We faced a significant performance decrease when we started using STI
without storing full namespaced class name in type column (because of PostgreSQL
length limit for ENUM types).
We realized that the cause of it is the slow STI model instantiation. Problematic
method appears to be `ActiveRecord::Base.compute_type`, which is used to find
the right class for STI model on every instantiation.
It builds an array of candidate types and then iterates through it calling
`safe_constantize` on every type until it finds appropriate constant. So if
desired type isn't the first element in this array there will be at least one
unsuccessful call to `safe_constantize`, which is very expensive, since it's
defined in terms of `begin; rescue; end`.
This commit is an attempt to speed up `compute_type` method simply by caching
results of previous calls.
```ruby
class MyCompany::MyApp::Business::Accounts::Base < ApplicationRecord
self.table_name = 'accounts'
self.store_full_sti_class = false
end
class MyCompany::MyApp::Business::Accounts::Free < Base
end
class MyCompany::MyApp::Business::Accounts::Standard < Base
# patch .compute_type there
end
puts '======================= .compute_type ======================='
Benchmark.ips do |x|
x.report("original method") do
MyCompany::MyApp::Business::Accounts::Free.send :compute_type, 'Free'
end
x.report("with types cached") do
MyCompany::MyApp::Business::Accounts::Standard.send :compute_type, 'Standard'
end
x.compare!
end
```
```
======================= .compute_type =======================
with types cached: 1529019.4 i/s
original method: 2850.2 i/s - 536.46x slower
```
```ruby
5_000.times do |i|
MyCompany::MyApp::Business::Accounts::Standard.create!(name: "standard_#{i}")
end
5_000.times do |i|
MyCompany::MyApp::Business::Accounts::Free.create!(name: "free_#{i}")
end
puts '====================== .limit(100).to_a ======================='
Benchmark.ips do |x|
x.report("without .compute_type patch") do
MyCompany::MyApp::Business::Accounts::Free.limit(100).to_a
end
x.report("with .compute_type patch") do
MyCompany::MyApp::Business::Accounts::Standard.limit(100).to_a
end
x.compare!
end
```
```
====================== .limit(100).to_a =======================
with .compute_type patch: 360.5 i/s
without .compute_type patch: 24.7 i/s - 14.59x slower
```
|
| |
|
|
|
|
|
|
| |
assert [1, 3].includes?(2) fails with unhelpful "Asserting failed" message
assert_includes [1, 3], 2 fails with "Expected [1, 3] to include 2" which makes it easier to debug and more obvious what went wrong
|
|
|
|
|
|
|
|
| |
Style/SpaceBeforeBlockBraces
Style/SpaceInsideBlockBraces
Style/SpaceInsideHashLiteralBraces
Fix all violations in the repository.
|
| |
|
|
|
|
|
| |
The current code base is not uniform. After some discussion,
we have chosen to go with double quotes by default.
|
| |
|
|
|
|
| |
Fixes #23209
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
This is a better test for 51660f0. It is testing that the SQL is the
same before and after the previously leaky scope is called. Before if
`hotel.drink_designers` was called first then `hotel.recipes` would
incorrectly get the scope applied. We want to be sure that the
polymorphic hm:t association is not leaking into or affecting the
SQL for the hm:t association on `Hotel`.
The reason I couldn't do this before was because there was an issue with
the SQL getting cached and wanted to resolve that later and then fix the
test to be better. Because of the caching, this test requires that
`Hotel.reflect_on_association(:recipes).clear_association_scope_cache`
be called after the first call to `hotel.recipes` to clear the
assocation scope chain and not interfere with the rest of the test.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
If there was a polymorphic hm:t association with a scope AND second
non-scoped hm:t association on a model the polymorphic scope would leak
through into the call for the non-polymorhic hm:t association.
This would only break if `hotel.drink_designers` was called before
`hotel.recipes`. If `hotel.recipes` was called first there would be
no problem with the SQL.
Before (employable_type should not be here):
```
SELECT COUNT(*) FROM "drink_designers" INNER JOIN "chefs" ON
"drink_designers"."id" = "chefs"."employable_id" INNER JOIN
"departments" ON "chefs"."department_id" = "departments"."id" WHERE
"departments"."hotel_id" = ? AND "chefs"."employable_type" = ?
[["hotel_id", 1], ["employable_type", "DrinkDesigner"]]
```
After:
```
SELECT COUNT(*) FROM "recipes" INNER JOIN "chefs" ON "recipes"."chef_id"
= "chefs"."id" INNER JOIN "departments" ON "chefs"."department_id" =
"departments"."id" WHERE "departments"."hotel_id" = ? [["hotel_id", 1]]
```
From the SQL you can see that `employable_type` was leaking through when
calling recipes. The solution is to dup the chain of the polymorphic
association so it doesn't get cached. Additionally, this follows
`scope_chain` which dup's the `source_reflection`'s `scope_chain`.
This required another model/table/relationship because the leak only
happens on a hm:t polymorphic that's called before another hm:t on the
same model.
I am specifically testing the SQL here instead of the number of records
becasue the test could pass if there was 1 drink designer recipe for the
drink designer chef even though the `employable_type` was leaking through.
This needs to specifically check that `employable_type` is not in the SQL
statement.
|
| |
|
| |
|
| |
|
|
|
|
|
|
| |
Remaining are `limit`, `precision`, `scale`, and `type` (the symbol
version). These will remain on the column, since they mirror the options
to the `column` method in the schema definition DSL
|
|
|
|
|
|
|
|
| |
This reverts commit ae96f229f6501d8635811d6b22d75d43cdb880a4.
Conflicts:
activerecord/CHANGELOG.md
activerecord/lib/active_record/attribute_methods.rb
|
| |
|
|
|
|
| |
See also PR: #17610
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
This allows us to decouple AssociationReflection and
ThroughReflection making ThroughReflection it's own Reflection
bucket in a way. The benefit of this is to be able to remove
checks against the macro's symbol for exmaple `macro == :belongs_to`.
Get all tests passing again
Some of the methods that used to be inherited from MacroReflection
through AssociationReflection were no longer getting passed through.
They needed to be duplicated into the ThroughReflection. I will
extract these out into a separate class.
Refactor shared methods into strategy object
Now that we've separated ThroughReflection and AssociationReflection
we can combine shared methods into one class to avoid duplication.
Break out class for each type of reflection
This creates a class for each reflection type (has_many, has_one,
belongs_to and habtm). We then can remove the need to set the macro
symbol in each initialization.
Tests were updated to reflect these changes because creation of
these reflections is now different.
Remove need for @collection instance var
We now define `collection?` as `false` by default and set it to
`true` in `has_and_belongs_to_many` and `has_many` reflections.
This removes the need for the `@collection` instance variable.
Raise exception on unknown macro types
We shouldn't accept just any macro when creating reflections. An
unrecongnized AssociationReflection raises an error. Tests in
`reflection_test` were updated to reflect these new changes.
`:has_and_belongs_to_many` macro tests were removed because we no
longer internally return HABTM.
|
|
|
|
|
|
| |
This adds the regressions tests from issue #15893 to
master. It's checking that both strings and symbols are
accepted as keys for nested associations.
|
|
|
|
|
|
| |
This is public API, and `simple_form` depends on the `nil` return value.
We need to go through a deprecation cycle to return a null object. If
people want hash access, they can access the hash.
|
|
|
|
|
|
|
|
| |
In some cases there is a difference between the two, we should always
be doing one or the other. For convenience, `type_cast` is still a
private method on type, so new types that do not need different behavior
don't need to implement two methods, but it has been moved to private so
it cannot be used accidentally.
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
- The following is now true for all types, all the time
- `model.attribute_before_type_cast == given_value`
- `model.attribute == model.save_and_reload.attribute`
- `model.attribute == model.dup.attribute`
- `model.attribute == YAML.load(YAML.dump(model)).attribute`
- Removes the remaining types implementing `type_cast_for_write`
- Simplifies the implementation of time zone aware attributes
- Brings tz aware attributes closer to being implemented as an attribute
decorator
- Adds additional point of control for custom types
|
|
|
|
|
|
| |
Follow up to #15438 and #15502.
/cc @sgrif
|
| |
|
|
|
|
|
|
|
|
|
| |
Fix habtm reflection
Conflicts:
activerecord/CHANGELOG.md
activerecord/lib/active_record/counter_cache.rb
activerecord/lib/active_record/reflection.rb
activerecord/test/cases/reflection_test.rb
|
|
|
|
|
|
|
| |
Also add a Changelog entry
[related #9702]
[fixes #8928]
|
|
|
|
| |
cache.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
& Yves Senn]
There is no reason for the PG adapter to have a default limit of 255 on :string
columns. See this snippet from the PG docs:
Tip: There is no performance difference among these three types, apart
from increased storage space when using the blank-padded type, and a
few extra CPU cycles to check the length when storing into a
length-constrained column. While character(n) has performance
advantages in some other database systems, there is no such advantage
in PostgreSQL; in fact character(n) is usually the slowest of the
three because of its additional storage costs. In most situations text
or character varying should be used instead.
|
|
|
|
|
|
|
|
|
|
|
| |
Currently `scope_chain` uses same array for building different
`scope_chain` for different associations. During processing
these arrays are sometimes mutated and because of in-place
mutation the changed `scope_chain` impacts other reflections.
Fix is to dup the value before adding to the `scope_chain`.
Fixes #3882.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
The comment in the test pretty much summarizes the issue.
`FIXME these assertions bust a lot`
Adding any type of association in class `Firm` will break this test.
I removed some deprecated stuff and this test failed.
I do not think this test provides any useful value. First of all who
counted last that 39 is the right number of associations.
Secondly there are a large number of tests which depend on reflection
returning right information about associations. Those tests will start
failing if there is a bug in the code.
|
|
|
|
|
|
|
|
| |
0123c39f41e2062311b2197e6e230ef8ad67e20e
Due to commit 0123c39f41e2062311b2197e6e230ef8ad67e20e, column
topic.unique_replies_count has been added, and these test started to
fail since the tests depends on the topic tables column info.
|
| |
|
|
|
|
|
|
|
|
|
| |
This reverts commit 3803fcce26b837c0117f7d278b83c366dc4ed370.
Conflicts:
activerecord/CHANGELOG.md
It will be deprecated only in 4.0, and removed properly in 4.1.
|
|
|
|
|
|
|
|
|
|
|
| |
This reverts commit 14fc8b34521f8354a17e50cd11fa3f809e423592.
Reason: we need to discuss a better path from this removal.
Conflicts:
activerecord/lib/active_record/reflection.rb
activerecord/test/cases/base_test.rb
activerecord/test/models/developer.rb
|
| |
|
| |
|
| |
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
This feature adds a lot of complication to ActiveRecord for dubious
value. Let's talk about what it does currently:
class Customer < ActiveRecord::Base
composed_of :balance, :class_name => "Money", :mapping => %w(balance amount)
end
Instead, you can do something like this:
def balance
@balance ||= Money.new(value, currency)
end
def balance=(balance)
self[:value] = balance.value
self[:currency] = balance.currency
@balance = balance
end
Since that's fairly easy code to write, and doesn't need anything
extra from the framework, if you use composed_of today, you'll
have to add accessors/mutators like that.
Closes #1436
Closes #2084
Closes #3807
|
| |
|
| |
|
|
|
|
|
|
| |
See the CHANGELOG for details.
Fixes #950.
|
| |
|
| |
|