Skip to content

Commit

Permalink
Introduce reload_<association> reader for singular associations.
Browse files Browse the repository at this point in the history
This patch brings back the functionality of passing true to the
association proxy. The behavior was deprecated with #20888 and scheduled
for removal in Rails 5.1.

The deprecation mentioned that instead of `Article.category(true)` one
should use `article#reload.category`. Unfortunately the alternative does
not expose the same behavior as passing true to the reader
did. Specifically reloading the parent record throws unsaved changes and
other caches away. Passing true only affected the association.

This is problematic and there is no easy workaround. I propose to bring
back the old functionality by introducing this new reader method for
singular associations.
  • Loading branch information
senny committed Nov 22, 2016
1 parent b89ddd4 commit 0e99571
Show file tree
Hide file tree
Showing 5 changed files with 51 additions and 1 deletion.
14 changes: 14 additions & 0 deletions activerecord/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,17 @@
* Introduce `Model#reload_<association>` to bring back the behavior
of `Article.category(true)` where `category` is a singular
association.

The force reloading of the association reader was deprecated in
#20888. Unfortunately the suggested alternative of
`article.reload.category` does not expose the same behavior.

This patch adds a reader method with the prefix `reload_` for
singular associations. This method has the same semantics as
passing true to the association reader used to have.

*Yves Senn*

* Make sure eager loading `ActiveRecord::Associations` also loads
constants defined in `ActiveRecord::Associations::Preloader`.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,16 @@ def self.valid_options(options)

def self.define_accessors(model, reflection)
super
define_constructors(model.generated_association_methods, reflection.name) if reflection.constructable?
mixin = model.generated_association_methods
name = reflection.name

define_constructors(mixin, name) if reflection.constructable?

mixin.class_eval <<-CODE, __FILE__, __LINE__ + 1
def reload_#{name}
association(:#{name}).force_reload_reader
end
CODE
end

# Defines the (build|create)_association methods for belongs_to or has_one association
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,13 @@ def build(attributes = {})
record
end

# Implements the reload reader method, e.g. foo.reload_bar for
# Foo.has_one :bar
def force_reload_reader
klass.uncached { reload }
target
end

private

def create_scope
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -291,6 +291,16 @@ def test_failing_create!
assert client.account.new_record?
end

def test_reloading_the_belonging_object
odegy_account = accounts(:odegy_account)

assert_equal "Odegy", odegy_account.firm.name
Company.where(id: odegy_account.firm_id).update_all(name: "ODEGY")
assert_equal "Odegy", odegy_account.firm.name

assert_equal "ODEGY", odegy_account.reload_firm.name
end

def test_natural_assignment_to_nil
client = Client.find(3)
client.firm = nil
Expand Down
10 changes: 10 additions & 0 deletions activerecord/test/cases/associations/has_one_associations_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -326,6 +326,16 @@ def test_create_with_inexistent_foreign_key_failing
end
end

def test_reload_association
odegy = companies(:odegy)

assert_equal 53, odegy.account.credit_limit
Account.where(id: odegy.account.id).update_all(credit_limit: 80)
assert_equal 53, odegy.account.credit_limit

assert_equal 80, odegy.reload_account.credit_limit
end

def test_build
firm = Firm.new("name" => "GlobalMegaCorp")
firm.save
Expand Down

0 comments on commit 0e99571

Please sign in to comment.