Commit Graph

845 Commits

Author SHA1 Message Date
Ryuta Kamizono
6d6ec6f936 Support where with comparison operators (>, >=, <, and <=)
```ruby
posts = Post.order(:id)

posts.where("id >": 9).pluck(:id)  # => [10, 11]
posts.where("id >=": 9).pluck(:id) # => [9, 10, 11]
posts.where("id <": 3).pluck(:id)  # => [1, 2]
posts.where("id <=": 3).pluck(:id) # => [1, 2, 3]
```

From type casting and table/column name resolution's point of view,
`where("create_at >=": time)` is better alternative than `where("create_at >= ?", time)`.

```ruby
class Post < ActiveRecord::Base
  attribute :created_at, :datetime, precision: 3
end

time = Time.now.utc # => 2020-06-24 10:11:12.123456 UTC

Post.create!(created_at: time) # => #<Post id: 1, created_at: "2020-06-24 10:11:12.123000">

# SELECT `posts`.* FROM `posts` WHERE (created_at >= '2020-06-24 10:11:12.123456')
Post.where("created_at >= ?", time) # => []

# SELECT `posts`.* FROM `posts` WHERE `posts`.`created_at` >= '2020-06-24 10:11:12.123000'
Post.where("created_at >=": time) # => [#<Post id: 1, created_at: "2020-06-24 10:11:12.123000">]
```
2020-07-06 10:24:48 +09:00
Ryuta Kamizono
c53c418e6f has_attribute? should be aware of attribute aliases
Related to #39495.

For now, `read_attribute`, `write_attribute`, `[]`, `[]=` are aware of
attribute aliases, but `has_attribute?` is not. It will easily miss
attribute alias resolution before using `has_attribute?`, it is very
inconvenient.

I think the inconvenience is not intended, so `has_attribute?` should be
aware of attribute aliases like as others for consistency.
2020-06-03 00:59:35 +09:00
Ryuta Kamizono
8504576bcf
Merge pull request #39501 from kamipo/alias_attribute_for_validation
Allow attribute aliases for `validates_uniqueness_of`
2020-06-02 21:16:42 +09:00
Ryuta Kamizono
7ae406a810 Allow attribute aliases for validates_uniqueness_of
For now, the target attribute allows attribute aliases, but `:scope`'s
attribute does not, the cause is that the former use
`read_attribute_for_validation`, but the latter does not.

Unfortunately we cannot use `read_attribute_for_validation` in this
case, it intentionally bypass custom attribute getter to allow #7072.

To work both alias and #7072, `read_attribute` should be used to resolve
attribute aliases.
2020-06-01 22:44:39 +09:00
Ryuta Kamizono
abae7fcd5f Allow attribute aliases for timestamp magic columns
For now, timestamp magic columns are only allowed for real physical
columns, it is not a matter for newly created app, but it is harder to
get the usefulness for legacy databases.

The reason that doesn't work is some low-level API does not care about
attribute aliases. I think that uses low-level API without attribute
alias resolution for timestamp attributes is not intended (e.g.
`updated_at_before_type_cast` works, but `has_attribute?("updated_at")`
and `_read_attribute("updated_at")` doesn't work).

I've addressed all missing attribute alias resolution for timestamp
attributes to work that consistently.

Fixes #37554.
2020-06-01 21:29:33 +09:00
Ryuta Kamizono
9641d0b2ef Support type casting for grandchild's attributes
Related to #39292.

Fixes #39460.
2020-05-29 04:55:13 +09:00
David Heinemeier Hansson
fd8fd4ae76
Add delegated type to Active Record (#39341) 2020-05-23 15:14:40 -07:00
Ryuta Kamizono
6a617cc61e Fix through association with source/through scope which has joins
If source/through scope references other tables in where/order, we
should explicitly maintain joins in the scope, otherwise association
queries will fail with referenced unknown column.

Fixes #33525.
2020-05-22 04:05:27 +09:00
Ryuta Kamizono
489df7eb28 Fix through association to respect source scope for includes/preload
`reflection.scope` is not aware of all source scopes if the association
is through association.

It should use `reflection.join_scopes` for that.

Fixes #39376.
2020-05-21 07:40:01 +09:00
Ryuta Kamizono
8589e8c236 Allow define scope for Ruby reserved keywords
For now argument forwarding doesn't allow some keywords like `true` as a
method name.

To bypass the issue, fallback to `define_method` if method names are
Ruby reserved keywords.

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

```ruby
class Works
  def true(*args)
    puts(*args)
  end
end

Works.new.true 1, 2, 3
# => 1, 2, 3

class WontWork
  def true(...)
    puts(...)
  end
end
```

```
% ruby a.rb
a.rb:12: syntax error, unexpected ..., expecting ')'
  def true(...)
a.rb:13: unexpected ...
a.rb:15: syntax error, unexpected `end', expecting end-of-input
```
2020-05-14 21:39:39 +09:00
Ryuta Kamizono
71f0df943d Fix pluck to correctly type cast same column names and association columns
That issues are caused by using only the model's cast types on the
relation.
To fix that issues, use the attribute's type caster takes precedence
over the model's cast types on the relation.

Fixes #35232.
Fixes #36042.
Fixes #37484.
2020-05-13 20:24:42 +09:00
Ryuta Kamizono
5f59eac239 Fix type casting aggregated values on association's attributes
Follow up of #39255.

Previously aggregation functions only use the model's attribute types on
the relation for type cast, this will be looking up association's
attribute and type caster if a column name is table name qualified.

Fixes #39248.
2020-05-13 11:32:11 +09:00
John Hawthorn
1b773bca5c Avoid confliting Kernel-named scopes on Relation
A previous change made singleton methods eagerly define their relation
methods if it shared a name with a method on Kernel. This caused issues
with a few methods which were both defined on Kernel and on
AcitveRecord::Relation.

This commit avoids defining the method if it exists on AR::Relation.
2020-05-12 11:10:39 -07:00
Ryuta Kamizono
981299e3d2 Eager generate relation methods if a method is on Kernel
Follow up of #34122.

Relation method call is relying on method_missing, but if `Kernel` has
the same named method (e.g. `open`, etc), it will invoke Kernel's method
since method_missing is not happened.

To prevent that, eager generate relation methods if a method is the same
name on `Kernel`.

Fixes #39195.
2020-05-10 06:14:29 +09:00
Ryuta Kamizono
47779e75b9 Support kwargs for named scopes
We fixed `generate_relation_method` to address kwargs warnings at
#38038, but I missed generated named scopes also need the same fix.

Test case has picked from #39196.

Co-authored-by: John Hawthorn <john@hawthorn.email>
2020-05-09 06:25:43 +09:00
Ryuta Kamizono
7ce3451927 Add test case for generate_relation_method
Positional hash argument should not be dup-ed.
2020-05-09 02:46:07 +09:00
Xavier Noria
afabe994e0 Removes require_dependency from the AR test suite
In the AR test suite require_dependency does not make much sense. Just
call vanilla require/load.

Note that in the test that made explicit use of it, there are no
autoload paths, and no constants have been autoloaded. In reality, the
code ended up calling Kernel#load.
2020-05-06 09:01:38 +02:00
Ryuta Kamizono
6187b7138c Fix rewhere to truly overwrite collided where clause by new where clause
```ruby
steve = Person.find_by(name: "Steve")
david = Author.find_by(name: "David")

relation = Essay.where(writer: steve)

# Before
relation.rewhere(writer: david).to_a # => []

# After
relation.rewhere(writer: david).to_a # => [david]
```

For now `rewhere` only works for truly column names, doesn't work for
alias attributes, nested conditions, associations.

To fix that, need to build new where clause first, and then get
attribute names from new where clause.
2020-05-05 11:45:29 +09:00
Ryuta Kamizono
4c724df058 Fix random CI failure due to non-deterministic has_one record
https://buildkite.com/rails/rails/builds/68645#ebd598f6-fe4c-4273-b1a9-c78055f21874/1016-1027
2020-05-03 23:52:35 +09:00
Ryuta Kamizono
699b64ab63 Improve WhereClause#ast to make concise Arel ast
If only one Arel node exist, wrapping a node by `And` node is obviously
redundant, make concise Arel ast will improve performance for visiting
the ast (about 20% faster for complex ast case).

```ruby
class Post < ActiveRecord::Base
end

posts = (0..500).map { |i| Post.where(id: i) }

Benchmark.ips do |x|
  x.report("inject scopes") { posts.inject { |res, scope| res.or(scope) }.to_sql }
end
```

Before:

```
Warming up --------------------------------------
      where with ids     8.000  i/100ms
Calculating -------------------------------------
      where with ids     80.416  (± 2.5%) i/s -    408.000  in   5.078118s
```

After:

```
Warming up --------------------------------------
      where with ids     9.000  i/100ms
Calculating -------------------------------------
      where with ids     96.126  (± 2.1%) i/s -    486.000  in   5.058960s
```
2020-04-25 18:46:10 +09:00
Flavio Wuensche
712ef53c9a Reload schema after ignored_columns reassignment
reload column_names after ignored_columns assignment

code review: remove unnecessary setup and move up reload_schema_from_cache
2020-04-23 07:50:06 +02:00
Ryuta Kamizono
e93f416abe Fix unscoping association scope on joins not to raise an error
#29589 changed merging scope order to allow to unscope default scopes on
association scope (#29611), but that caused a regression #38811 that
accidentally allow join constraint which is required.

```
% bin/test test/cases/associations/has_many_associations_test.rb -n test_unscopes_the_default_scope_of_associated_model_when_used_with_include
Run options: -n test_unscopes_the_default_scope_of_associated_model_when_used_with_include --seed 32978

# Running:

E

Error:
HasManyAssociationsTest#test_unscopes_the_default_scope_of_associated_model_when_used_with_include:
NoMethodError: undefined method `children' for nil:NilClass
    ~/rails/activerecord/lib/active_record/associations/join_dependency/join_association.rb:39:in `block in join_constraints'
    ~/rails/activerecord/lib/active_record/associations/join_dependency/join_association.rb:30:in `reverse_each'
    ~/rails/activerecord/lib/active_record/associations/join_dependency/join_association.rb:30:in `with_index'
    ~/rails/activerecord/lib/active_record/associations/join_dependency/join_association.rb:30:in `join_constraints'
    ~/rails/activerecord/lib/active_record/associations/join_dependency.rb:171:in `make_constraints'
    ~/rails/activerecord/lib/active_record/associations/join_dependency.rb:196:in `block in walk'
    ~/rails/activerecord/lib/active_record/associations/join_dependency.rb:196:in `each'
    ~/rails/activerecord/lib/active_record/associations/join_dependency.rb:196:in `flat_map'
    ~/rails/activerecord/lib/active_record/associations/join_dependency.rb:196:in `walk'
    ~/rails/activerecord/lib/active_record/associations/join_dependency.rb:90:in `block in join_constraints'
    ~/rails/activerecord/lib/active_record/associations/join_dependency.rb:87:in `each'
    ~/rails/activerecord/lib/active_record/associations/join_dependency.rb:87:in `flat_map'
    ~/rails/activerecord/lib/active_record/associations/join_dependency.rb:87:in `join_constraints'
    ~/rails/activerecord/lib/active_record/relation/query_methods.rb:1226:in `build_join_query'
    ~/rails/activerecord/lib/active_record/relation/query_methods.rb:1211:in `build_joins'
    ~/rails/activerecord/lib/active_record/relation/query_methods.rb:1091:in `build_arel'
    ~/rails/activerecord/lib/active_record/relation/query_methods.rb:1063:in `arel'
    ~/rails/activerecord/lib/active_record/relation/finder_methods.rb:419:in `block in limited_ids_for'
    ~/rails/activerecord/lib/active_record/relation.rb:867:in `skip_query_cache_if_necessary'
    ~/rails/activerecord/lib/active_record/relation/finder_methods.rb:419:in `limited_ids_for'
    ~/rails/activerecord/lib/active_record/relation/finder_methods.rb:398:in `apply_join_dependency'
    ~/rails/activerecord/lib/active_record/relation.rb:839:in `block in exec_queries'
    ~/rails/activerecord/lib/active_record/relation.rb:867:in `skip_query_cache_if_necessary'
    ~/rails/activerecord/lib/active_record/relation.rb:834:in `exec_queries'
    ~/rails/activerecord/lib/active_record/relation.rb:639:in `load'
    ~/rails/activerecord/lib/active_record/relation.rb:250:in `records'
    ~/rails/activerecord/lib/active_record/relation/finder_methods.rb:508:in `find_take'
    ~/rails/activerecord/lib/active_record/relation/finder_methods.rb:98:in `take'
    ~/rails/activerecord/lib/active_record/relation/finder_methods.rb:458:in `find_one'
    ~/rails/activerecord/lib/active_record/relation/finder_methods.rb:442:in `find_with_ids'
    ~/rails/activerecord/lib/active_record/relation/finder_methods.rb:69:in `find'
    ~/rails/activerecord/test/cases/associations/has_many_associations_test.rb:2689:in `block in <class:HasManyAssociationsTest>'

bin/test test/cases/associations/has_many_associations_test.rb:2683
```

Required join constraint should not be allowed to unscoping.

Fixes #38811.
2020-04-16 00:34:41 +09:00
Ryuta Kamizono
f64b5fb942 Allow extra scoping in callbacks when create on association relation
#37523 has a regression that ignore extra scoping in callbacks when
create on association relation.

It should respect `klass.current_scope` even when create on association
relation to allow extra scoping in callbacks.

Fixes #38741.
2020-04-10 16:10:49 +09:00
Kevin Deisz
b8ae104318
Support strict_loading on association declarations 2020-02-21 13:11:24 -05:00
eileencodes
dbb92f8a77
Add strict_loading mode to prevent lazy loading
Add `#strict_loading` to any record to prevent lazy loading of associations.
`strict_loading` will cascade down from the parent record to all the
associations to help you catch any places where you may want to use
`preload` instead of lazy loading. This is useful for preventing N+1's.

Co-authored-by: Aaron Patterson <aaron.patterson@gmail.com>
2020-02-20 08:32:48 -05:00
Sebastián Palma
db6eb846eb This PR adds support to retrieve partitioned indexes when asking for
indexes in a table.

Currently the pg_class catalog is filtered out to retrieve the indexes in a
table by its relkind value. Which in versions lower than 11 of PostgreSQL
is always `i` (lower case). But since version 11, PostgreSQL
supports partitioned indexes referenced with a relkind value of `I`
(upper case). This makes any feature within the current code base to exclude those
partitioned indexes.

The solution proposed is to make use of the `IN` clause to filter those
relkind values of `i` and/or `I` when retrieving a table indexes.
2020-02-06 07:36:44 +02:00
Ryuta Kamizono
21c89dcc75 Using define_attribute_method on ivar attrs is not officially supported
It doesn't work dirty tracking on Active Record. Use `attribute` API
instead.
2020-01-29 09:56:27 +09:00
Michael Fowler
9aa59f9d4a Avoid extraneous preloading when loading across has_one associations
The Preloader relies on other objects to bind the retrieved records to their
parents. When executed across a hash, it assumes that the results of
`preloaded_records` is the appropriate set of records to pass in to the next
layer.

Filtering based on the reflection properties in `preloaded_records` allows us to
avoid excessive preloading in the instance where we are loading across a
`has_one` association distinguished by an order (e.g. "last comment" or
similar), by dropping these records before they are returned to the
Preloader. In this situation, we avoid potentially very long key lists in
generated queries and the consequential AR object instantiations.

This is mostly relevant if the underlying linked set has relatively many
records, because this is effectively a multiplier on the number of records
returned on the far side of the preload. Unfortunately, avoiding the
over-retrieval of the `has_one` association seems to require substantial changes
to the preloader design, and probably adaptor-specific logic -- it is a
top-by-group problem.
2020-01-08 08:14:04 +13:00
Yoshiyuki Hirano
f4fbdb1b4e Allow AR::Enum definitions with boolean values
If `AR::Enum` is used for boolean field, it would be not expected
behavior for us.

fixes #38075

Problem:

In case of using boolean for enum, we can set with string (hash key)
to instance, but we cannot set with actual value (hash value).

```ruby
class Post < ActiveRecord::Base
  enum status: { enabled: true, disabled: false }
end

post.status = 'enabled'
post.status # 'enabled'

post.status = true
post.status # 'enabled'

post.status = 'disabled'
post.status # 'disabled'

post.status = false
post.status # nil (This is not expected behavior)
```

After looking into `AR::Enum::EnumType#cast`, I found that `blank?`
method converts from false value to nil (it seems it may not intentional behavior).

In this patch, I improved that if it defines enum with boolean,
it returns reasonable behavior.
2019-12-24 07:05:42 -10:00
Brad Price
0a5b41c4c0 Check that entire collection has been loaded before short circuiting
Currently, when checking that the collection has been loaded, only the first
record is checked. In specific scenarios, if a record is fetched via an `after_initialize`
hook, there is a chance that the first record has been loaded, but other records in the
collection have not.

In order to successfully short circuit the fetching of data, we need to verify that
all of the records in the collection have been loaded.

* Create test for edge case
* Move `reset_callbacks` method to `cases/helper`, since it has been defined in multiple
  locations.

Closes #37730
2019-11-19 15:32:36 -06:00
Ryuta Kamizono
2c008d9f63 :polymorphic, :as, and :foreign_type are valid for polymorphic association 2019-11-10 10:54:58 +09:00
Ryuta Kamizono
ff8981faeb Fix collection callbacks not terminating when abort is thrown
Cherry-picking tests from #37643.

Fixes #37273.

Co-authored-by: Edouard CHIN <edouard.chin@shopify.com>
2019-11-06 18:19:33 +09:00
Gannon McGibbon
61401184e9 Don't run callbacks on has_many inverse add
Stop running association callbacks when setting `has_many` inverse
records. The `before_add` and `after_add` callbacks are meant for
newly added records.
2019-10-10 16:18:13 -04:00
Tekin Suleyman
5a3e34ed1d
Ensure Contextual validations fire on associations
If a custom validation context is used, the validations on dependent
association records should fire regardless of whether those record have
`changed_for_autosave?` or not as the use of a custom validation context
increases the chance that validations for the context will be different
to those from when the record was first saved.

6ea80b6 changed the autosave behaviour for single associations such that
validations would only fire on an associated record if the record was
`changed_for_autosave?`. This brought the behaviour inline with that for
collection associations, but introduce a regression in that validations
would no longer fire on dependent associations, even when using a custom
validation context.

This change updates the behaviour for both single and collection
associations.

This commit also updates another related regression test that became a
potential false-positive when 6ea80b6 was merged. The original test was
written to protect against non-custom validations firing on associations
(see #14106). At the time validations on autosaving singular
associations would always fire, even when the association was not dirty,
whereas after 6ea80b6 the validations only fire if the association is
dirty. This update to the test makes the association record dirty to
ensure the validations will fire so that the code responsible for
excluding non-custom contexts is correctly exercised.
2019-10-04 12:17:53 +01:00
Ryuta Kamizono
9b234bbdfd
Merge pull request #37360 from kamipo/deprecate_leaking_scope
Deprecate leaking scope in callback block for association relation
2019-10-04 15:47:46 +09:00
Ryuta Kamizono
e0a9af9543 Deprecate leaking scope in callback block for association relation
Follow up of #35280, I missed that `AssociationRelation` is using
`scoping` and not use `super`.
2019-10-04 14:49:41 +09:00
Ryuta Kamizono
0e76553934 Maintain extra joins for string or complex arel conditions
49bcb00 has changed to maintain extra joins only if other table's
condition is found (e.g. `other_table[:id].eq(table[:foreign_id])`).

It means that cannot maintain extra joins for complex conditions
(especially "(... OR ...)"), so it has caused a regression #37167.

This changes to maintain extra joins for complex conditions too like as
before.

Fixes #37167.
2019-10-04 13:29:18 +09:00
Rafael Mendonça França
a273da7619 Merge pull request #35915 from bernardoamc/allow-has-secure-token-length-manipulation
Allow token length configuration for has_secure_token method
2019-09-30 15:13:04 -04:00
Gannon McGibbon
5ec2f35f27 Ensure custom PK types are casted in through reflection queries
Make sure primary keys with non-integer types can be correctly type
casted in through reflections.
2019-08-07 16:27:33 -04:00
Kasper Timm Hansen
cea392eb96
Polymorphic has_one touch: Reset association cache result after create transaction
In case of a polymorphic association there's no automatic inverse_of to assign the
inverse record. So to get the record there needs to be a query executed,
however, if the query fires within the transaction that's trying to create
the associated record, no record can be found. And worse, the nil result is cached
on the association so after the transaction commits the record can't be found.

That's what happens if touch is enabled on a polymorphic has_one association.

Consider a Comment with a commentable association that needs to be touched.

For `Comment.create(commentable: Post.new)`, the existing code essentially
does `commentable.send(:comment)` within the create transaction for the comment
and thus not finding the comment.

Now we're purposefully clearing the cache in case we've tried accessing
the association within the transaction and found no object.

Before:

```
kaspth-imac 2.6.3 ~/code/rails/activerecord master *= ARCONN=postgresql bin/test test/cases/associations/has_one_associations_test.rb -n /commit/
Using postgresql
Run options: -n /commit/ --seed 46022

D, [2019-07-19T03:30:37.864537 #96022] DEBUG -- :   Chef Load (0.2ms)  SELECT "chefs".* FROM "chefs" WHERE "chefs"."employable_id" = $1 AND "chefs"."employable_type" = $2 LIMIT $3  [["employable_id", 1], ["employable_type", "DrinkDesignerWithPolymorphicTouchChef"], ["LIMIT", 1]]
D, [2019-07-19T03:30:37.865013 #96022] DEBUG -- :   Chef Create (0.2ms)  INSERT INTO "chefs" ("employable_id", "employable_type") VALUES ($1, $2) RETURNING "id"  [["employable_id", 1], ["employable_type", "DrinkDesignerWithPolymorphicTouchChef"]]
D, [2019-07-19T03:30:37.865201 #96022] DEBUG -- :   TRANSACTION (0.1ms)  RELEASE SAVEPOINT active_record_1
D, [2019-07-19T03:30:37.874136 #96022] DEBUG -- :   TRANSACTION (0.1ms)  ROLLBACK
D, [2019-07-19T03:30:37.874323 #96022] DEBUG -- :   TRANSACTION (0.1ms)  ROLLBACK
F

Failure:
HasOneAssociationsTest#test_polymorphic_has_one_with_touch_option_on_create_wont_cache_assocation_so_fetching_after_transaction_commit_works [/Users/kaspth/code/rails/activerecord/test/cases/associations/has_one_associations_test.rb:716]:
--- expected
+++ actual
@@ -1 +1 @@
-#<Chef id: 1, employable_id: 1, employable_type: "DrinkDesignerWithPolymorphicTouchChef", department_id: nil, employable_list_type: nil, employable_list_id: nil>
+nil
```

After:

```
kaspth-imac 2.6.3 ~/code/rails/activerecord master *= ARCONN=postgresql bin/test test/cases/associations/has_one_associations_test.rb -n /commit/
Using postgresql
Run options: -n /commit/ --seed 46022

D, [2019-07-19T03:30:22.479387 #95973] DEBUG -- :   Chef Create (0.3ms)  INSERT INTO "chefs" ("employable_id", "employable_type") VALUES ($1, $2) RETURNING "id"  [["employable_id", 1], ["employable_type", "DrinkDesignerWithPolymorphicTouchChef"]]
D, [2019-07-19T03:30:22.479574 #95973] DEBUG -- :   TRANSACTION (0.1ms)  RELEASE SAVEPOINT active_record_1
D, [2019-07-19T03:30:22.482051 #95973] DEBUG -- :   Chef Load (0.1ms)  SELECT "chefs".* FROM "chefs" WHERE "chefs"."employable_id" = $1 AND "chefs"."employable_type" = $2 LIMIT $3  [["employable_id", 1], ["employable_type", "DrinkDesignerWithPolymorphicTouchChef"], ["LIMIT", 1]]
D, [2019-07-19T03:30:22.482317 #95973] DEBUG -- :   TRANSACTION (0.1ms)  ROLLBACK
D, [2019-07-19T03:30:22.482437 #95973] DEBUG -- :   TRANSACTION (0.1ms)  ROLLBACK
.

Finished in 0.088498s, 11.2997 runs/s, 22.5994 assertions/s.
1 runs, 2 assertions, 0 failures, 0 errors, 0 skips
```

Notice the select now fires after the commit.
2019-07-31 05:59:23 +02:00
Eileen M. Uchitelle
0206d9cb7c
Merge pull request #36671 from wjessop/do_not_validate_non_dirty_association_targets
Don't validate non dirty association targets
2019-07-24 14:44:53 -04:00
Will Jessop
6ea80b6103
Don't validate non dirty association targets
Fixes #36581.

This fixes an issue where validations would return differently when a previously saved invalid association was loaded between calls:

    assert_equal true, squeak.valid?
    assert_equal true, squeak.mouse.present?
    assert_equal true, squeak.valid?

Here the second assert would return

    Expected: true
    Actual: false

Limiting validations to associations that would be normally saved (using autosave: true) due to changes means that loading invalid associated relations will not change the return value of the parent relations's `valid?` method.
2019-07-15 18:21:20 +01:00
Edouard CHIN
07ff343857 Fix errors getting duplicated when passed validations options:
- In 86620cc3aa8e2630bc8d934b1a86453276b9eee9, 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
Rafael França
b65f88652f
Merge pull request #36210 from vishaltelangre/raise-record-invalid-when-associations-fail-to-save-due-to-uniqueness-failure
Fix: ActiveRecord::RecordInvalid is not raised when an associated record fails to #save! due to uniqueness validation failure
2019-06-24 13:59:15 -04:00
Kasper Timm Hansen
aae270de9e
Merge pull request #35891 from Shopify/schema-cache-deduplication
Deduplicate various Active Record schema cache structures
2019-06-19 13:04:32 +02: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
Jean Boussier
17acb771d8 Deduplicate various Active Record schema cache structures
Real world database schemas contain a lot of duplicated data.
Some column names like `id`, `created_at` etc can easily be repeated
hundreds of times. Same for SqlTypeMetada, most database will contain
only a limited number of possible combinations.

This result in a lot of wasted memory.

The idea here is to make these data sctructures immutable, use a registry
to substitute similar instances with pre-existing ones.
2019-06-03 13:31:42 +02:00
Petrik
9dce7d9268 Fix comment for "broken" inverse_of associations [ci skip] 2019-05-28 18:22:22 +02:00
Ryuta Kamizono
ec6dfdc8d2 Fix eager loading associations with string joins not to raise NoMethodError
Fixes #34456.
2019-05-15 22:00:01 +09:00
Vishal Telangre
bbcd707aef
Fix: ActiveRecord::RecordInvalid is not raised when an associated record fails to #save! due to uniqueness validation failure
Add tests

Fix tests failing due to introduction of uniquness rule added to Book model
2019-05-10 01:37:12 +05:30