aboutsummaryrefslogtreecommitdiffstats
path: root/activerecord/lib/active_record/associations
Commit message (Collapse)AuthorAgeFilesLines
* Fix inconsistent touching behavior between assigning and unassigningRyuta Kamizono2018-05-272-2/+3
| | | | | | | | | | | On belongs_to with `touch: true` association, unassigned object is caused touching, but assigned object is not touched. And also, if primary key is customized, it will touch against the wrong target looked up by the customized key as primary key. This change ensures correctly touching consistently between assigning and unassigning.
* Fix `belongs_to_counter_cache_after_update` to respect polymorphic type changeRyuta Kamizono2018-05-273-2/+9
|
* Avoid a subquery in updating counter cacheRyuta Kamizono2018-05-261-6/+1
| | | | Since UPDATE with a subquery doesn't work on MySQL.
* Fix `belongs_to_counter_cache_after_update` to respect custom primary key ↵Ryuta Kamizono2018-05-261-0/+13
| | | | | | | | | | counter If belongs_to primary key is customized, the callback will update counters against the wrong target looked up by the customized key as primary key. We need to convert the customized key into an object that can be referred to as primary key.
* Fix `different_target?` to respect custom primary key counterRyuta Kamizono2018-05-261-3/+6
|
* Eager loading won't mutate owner recordRyuta Kamizono2018-05-252-11/+19
| | | | | | | | | | | | | | | Since #31575, `BelongsToAssociation#target=` replaces owner record's foreign key to fix an inverse association bug. But the method is not only used for inverse association but also used for eager loading/preloading, it caused some public behavior changes (#32338, #32375). To avoid any side-effect in loading associations, I reverted the overriding `#target=`, then introduced `#inversed_from` to replace foreign key in `set_inverse_instance`. Closes #32375.
* Don't expose `SingularAssociation#replace` which is internal APIRyuta Kamizono2018-05-163-47/+44
| | | | | Originally `SingularAssociation#replace` abstract method is private, and doesn't intend to be called directly.
* Allow a belonging to object to be created from a new recordJolyon Pawlyn2018-05-012-4/+8
| | | | If a 'has one' object is created from a new record, an ActiveRecord::RecordNotSaved error is raised but this behavior was also applied to the reverse scenario.
* Ensure that `ids_reader` respects dirty target whether target is loaded or notRyuta Kamizono2018-04-271-1/+3
| | | | | | | Currently `ids_reader` doesn't respect dirty target when the target is not loaded yet unlike `collection.size`. I believe the inconsistency is a bug, fixes the `ids_reader` to behave consistently regardless of whether target is loaded or not.
* Loaded associations should not run a new query when size is calledGraham Turner2018-04-261-1/+3
| | | | | | | Already loaded associations were running an extra query when `size` was called on the association. This fix ensures that an extra query is no longer run. Update tests to use proper methods
* Merge pull request #32514 from ↵Ryuta Kamizono2018-04-221-1/+5
|\ | | | | | | | | samdec/multiple-has-one-through-associations-build-bug Fix .new with multiple through associations
| * Fix .new with multiple through associationsSam DeCesare2018-04-091-1/+5
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | This fixes a bug with building an object that has multiple `has_many :through` associations through the same object. Previously, when building the object via .new, the intermediate object would be created instead of just being built. Here's an example: Given a GameBoard, that has_one Owner and Collection through Game. The following line would cause a game object to be created in the database. GameBoard.new(owner: some_owner, collection: some_collection) Whereas, if passing only one of those associations into `.new` would cause the Game object to be built and not created in the database. Now the above code will only build the Game object, and not save it.
* | `target` in `CollectionAssociation` is always an arrayRyuta Kamizono2018-04-211-2/+2
| | | | | | | | | | So `target.is_a?(Array)` is meaningless, and just use `target.empty?` instead of `target.blank?`.
* | Can preload associations through polymorphic associationsDana Sherson2018-04-201-10/+15
|/
* Don't unset foreign key when preloading missing recordEugene Kenny2018-03-241-2/+2
| | | | | | | | | When a belongs to association's target is set, its foreign key is now updated to match the new target. This is the correct behaviour when a new record is assigned, but not when the existing record is preloaded. As long as we mark the association as loaded, we can skip setting the target when the record is missing and avoid clobbering the foreign key.
* Fix dependence on has_one/belongs_to relationshipsFernando Gorodscy2018-03-062-1/+10
| | | | | | | | | | | | | | | | | | | | | | | | | | When a class has a belongs_to or has_one relationship with dependent: :destroy option enabled, objects of this class should not be deleted if it's dependents cannot be deleted. Example: class Parent has_one :child, dependent: :destroy end class Child belongs_to :parent, inverse_of: :child before_destroy { throw :abort } end c = Child.create p = Parent.create(child: c) p.destroy p.destroyed? # expected: false; actual: true; Fixes #32022
* Eager loading with polymorphic associations should behave consistentlyRyuta Kamizono2018-03-041-4/+2
| | | | | | | | | | This reverts ignoring polymorphic error introduced at 02da8ae. What the ignoring want to solve was caused by force eager loading regardless of whether it is necessary, but it has been fixed by #29043. The ignoring is now only causing a mismatch of `exists?` behavior with `to_a`, `count`, etc. It should behave consistently.
* Extract all `base_class.name` as `polymorphic_name`Ryuta Kamizono2018-03-044-8/+8
| | | | | | | This is an alternative of #29722, and follow up of #32048. This does not change the current behavior, but makes it easier to modify all polymorphic names consistently.
* Remove staled comment for `JoinDependency#initialize`Ryuta Kamizono2018-03-021-21/+0
| | | | | | | | | | | This comment was added at 070dda2. That arguments has already been changed since those are internal nodoc classes, but the comment does not reflect the current state. I decided to remove the staled comment since it is not useful for understanding what the class does. [ci skip]
* Association creation and finding should work consistently (#32048)Ryuta Kamizono2018-02-261-1/+1
| | | | | | | | | | | This is an alternative of #29722, and revert of #29601 and a1fcbd9. Currently, association creation and normal association finding doesn't respect `store_full_sti_class`. But eager loading and preloading respect the setting. This means that if set `store_full_sti_class = false` (`true` by default), eager loading and preloading can not find created polymorphic records. Association creation and finding should work consistently.
* Use private attr_readerRyuta Kamizono2018-02-233-4/+3
| | | | | Since #32028, Rails 6 requires Ruby 2.3+. No longer needed workaround for Ruby 2.2 "private attribute?" warning.
* Association scope's own order should be prioritized over through scope's orderRyuta Kamizono2018-02-181-2/+2
| | | | | | | | | | 3acc5d6 was changed the order of scope evaluation from through scope to the association's own scope to be prioritized over the through scope. But the sorting order will be prioritized that is evaluated first. It is unintentional effect, association scope's sorting order should be prioritized as well. Fixes #32008.
* Rails 6 requires Ruby 2.3+Jeremy Daer2018-02-171-5/+1
|
* Fix marshaling of models with `has_many :through` associationsfatkodima2018-02-081-2/+2
|
* Revert "✂️"Ryuta Kamizono2018-02-071-1/+2
| | | | | | | | This reverts commit 487a1061cc496455dfe5ee84d1e49d509c1675b5. This `#--` is necessary for the doc of `distinct`. [ci skip]
* ✂️schneems2018-02-061-2/+1
|
* Avoid extra calls to to_sDaniel Colson2018-01-292-3/+3
| | | | | | | With #31615 `type_for_attribute` accepts either a symbol as well as a string. `has_attribute?` and `attribute_alias` also accept either. Since these methods call `to_s` on the argument, we no longer need to do that at the call site.
* Avoid passing unnecessary arguments to relationDaniel Colson2018-01-242-2/+2
| | | | | | | | | | | | Most of the time the table and predicate_builder passed to Relation.new are exactly the arel_table and predicate builder of the given klass. This uses klass.arel_table and klass.predicate_builder as the defaults, so we don't have to pass them in most cases. This does change the signaure of both Relation and AssocationRelation. Are we ok with that?
* Fix building has_one through recordRyuta Kamizono2018-01-233-14/+10
| | | | Fixes #31762.
* Don't update counter cache when through record was not destroyedEugene Kenny2018-01-141-1/+1
| | | | | | When removing a record from a has many through association, the counter cache was being updated even if the through record halted the callback chain and prevented itself from being destroyed.
* Don't pass garbage args to alias trackerRyuta Kamizono2018-01-141-10/+2
| | | | | | | | | | | | | This is a complete fix to #30995. Originally alias tracker will only track table aliases on `Arel::Nodes::Join`, other args are ignored. Since c5ab6e5, parent aliases hash will be passed then it caused the regression #30995. It is enough to pass list of `Arel::Nodes::Join` simply, not need to pass garbage args which will be ignored.
* Merge pull request #23146 from piotrj/issue_18424Ryuta Kamizono2018-01-111-0/+1
|\ | | | | | | When deleting through records, take into account association conditions
| * When deleting through records, take into account association conditionsPiotr Jakubowski2016-05-041-8/+9
| | | | | | | | | | | | | | | | Fixes #18424. When deleting through records, it didn't take into account the conditions that may have been affecting join model table, but was defined in association definition.
* | Fix `stale_state` for nested `has_many :through` associationsRyuta Kamizono2018-01-101-2/+13
| | | | | | | | Need reloading when through record has replaced.
* | Merge pull request #16314 from ↵Ryuta Kamizono2018-01-101-1/+1
|\ \ | | | | | | | | | | | | | | | zoltankiss/allow-nested-has-many-associations-on-unpersisted-parent-instances fix nested `has many :through` associations on unpersisted parent instances
| * | Fix nested `has many :through` associations on unpersisted instancesZoltan Kiss2015-03-261-1/+1
| | | | | | | | | | | | Fixes: #16313
* | | Bring back passing single record support for `Preloader`Ryuta Kamizono2018-01-101-1/+1
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | I removed redundant `Array.wrap(records)` since `Preloader` is nodoc class and Active Record always pass `records` as an array to `Preloader`. But if users relies on that behavior, it is not worth dropping its behavior. Fixes #31661.
* | | Fix deleting through records when using has_many through with `source_type`Ryuta Kamizono2018-01-081-8/+6
| | | | | | | | | | | | | | | | | | | | | | | | Currently deleting through records doesn't respect `source_type`. It should not be ignored in that case. Related #23209. Fixes #24116.
* | | Simply use `scope.delete_all` instead of constructing delete managerRyuta Kamizono2018-01-071-8/+1
| | |
* | | Remove passing argument to singular and collection association readersRyuta Kamizono2018-01-051-2/+2
| | | | | | | | | | | | Follow up of 09cac8c67afdc4b2a1c6ae07931ddc082629b277.
* | | Merge pull request #27561 from fishbrain/count-all-in-has-many-associationRyuta Kamizono2018-01-031-1/+1
|\ \ \ | | | | | | | | | | | | Use `count(:all)` in HasManyAssociation#count_records
| * | | Use `count(:all)` in HasManyAssociation#count_recordsKlas Eskilson2017-02-071-1/+1
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Problem: Calling `count` on an association can cause invalid SQL queries to be created where the `SELECT COUNT(a, b, c)` function receives multiple columns. This will cause a `StatementInvalid` exception later on. Solution: Use `count(:all)`, which generates a `SELECT COUNT(*)...` query independently of the association. This also includes a test case that, before the fix, broke.
* | | | Remove `association_primary_key_type` from `AssociationReflection` and ↵Ryuta Kamizono2018-01-011-2/+2
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | `ThroughReflection` This method was introduced in #26718, which is internally used only in `CollectionAssociation`. There is no need to be in the reflection classes.
* | | | Bugfix foreign key replacement in inverse associationBogdan Gusiev2017-12-272-13/+8
| | | | | | | | | | | | | | | | when model is added to collection association
* | | | Fix conflicts `counter_cache` with `touch: true` by optimistic locking.bogdanvlviv2017-12-122-5/+9
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | ``` # create_table :posts do |t| # t.integer :comments_count, default: 0 # t.integer :lock_version # t.timestamps # end class Post < ApplicationRecord end # create_table :comments do |t| # t.belongs_to :post # end class Comment < ApplicationRecord belongs_to :post, touch: true, counter_cache: true end ``` Before: ``` post = Post.create! # => begin transaction INSERT INTO "posts" ("created_at", "updated_at", "lock_version") VALUES ("2017-12-11 21:27:11.387397", "2017-12-11 21:27:11.387397", 0) commit transaction comment = Comment.create!(post: post) # => begin transaction INSERT INTO "comments" ("post_id") VALUES (1) UPDATE "posts" SET "comments_count" = COALESCE("comments_count", 0) + 1, "lock_version" = COALESCE("lock_version", 0) + 1 WHERE "posts"."id" = 1 UPDATE "posts" SET "updated_at" = '2017-12-11 21:27:11.398330', "lock_version" = 1 WHERE "posts"."id" = 1 AND "posts"."lock_version" = 0 rollback transaction # => ActiveRecord::StaleObjectError: Attempted to touch a stale object: Post. Comment.take.destroy! # => begin transaction DELETE FROM "comments" WHERE "comments"."id" = 1 UPDATE "posts" SET "comments_count" = COALESCE("comments_count", 0) - 1, "lock_version" = COALESCE("lock_version", 0) + 1 WHERE "posts"."id" = 1 UPDATE "posts" SET "updated_at" = '2017-12-11 21:42:47.785901', "lock_version" = 1 WHERE "posts"."id" = 1 AND "posts"."lock_version" = 0 rollback transaction # => ActiveRecord::StaleObjectError: Attempted to touch a stale object: Post. ``` After: ``` post = Post.create! # => begin transaction INSERT INTO "posts" ("created_at", "updated_at", "lock_version") VALUES ("2017-12-11 21:27:11.387397", "2017-12-11 21:27:11.387397", 0) commit transaction comment = Comment.create!(post: post) # => begin transaction INSERT INTO "comments" ("post_id") VALUES (1) UPDATE "posts" SET "comments_count" = COALESCE("comments_count", 0) + 1, "lock_version" = COALESCE("lock_version", 0) + 1, "updated_at" = '2017-12-11 21:37:09.802642' WHERE "posts"."id" = 1 commit transaction comment.destroy! # => begin transaction DELETE FROM "comments" WHERE "comments"."id" = 1 UPDATE "posts" SET "comments_count" = COALESCE("comments_count", 0) - 1, "lock_version" = COALESCE("lock_version", 0) + 1, "updated_at" = '2017-12-11 21:39:02.685520' WHERE "posts"."id" = 1 commit transaction ``` Fixes #31199.
* | | | Provide arguments to RecordNotFoundNikita Misharin2017-11-251-1/+7
| | | |
* | | | Consolidate duplicated `to_ary`/`to_a` definitions in `Relation` and ↵Ryuta Kamizono2017-11-101-4/+6
| | | | | | | | | | | | | | | | `CollectionProxy`
* | | | Remove useless preloader classesRyuta Kamizono2017-11-1010-104/+15
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | They are only different by one line of code which doesn't deserve a hierarchy of 7 classes. Closes #31079. [Ryuta Kamizono & Bogdan Gusiev]
* | | | Don't expose accessors which are internal used onlyRyuta Kamizono2017-11-082-3/+6
| | | |
* | | | Don't expose internal methods in `Preloader::ThroughAssociation`Ryuta Kamizono2017-11-081-8/+7
| | | | | | | | | | | | | | | | `through_reflection` and `source_reflection` are used only in the class.