Restore RecordNotFound when *_ids= can't find records by ID

9c9fb19b changed the behaviour of the _ids= setters for associations to
raise an AssociationTypeMismatch when unknown IDs are given:

    Class: <ActiveRecord::AssociationTypeMismatch>
    Message: <"Developer(#43811860) expected, got NilClass(#16732720)">

This restores the original ActiveRecord::RecordNotFound exception with a
much clearer error message:

    Class: <ActiveRecord::RecordNotFound>
    Message: <"Couldn't find all Developers with 'id': (1, -9999) [WHERE \"contracts\".\"company_id\" = ?] (found 1 results, but was looking for 2)">

Fixes #25719
上级 8556ab50
* Raise ActiveRecord::RecordNotFound from collection `*_ids` setters
for unknown IDs with a better error message.
*Dominic Cleal*
* For PostgreSQL >= 9.4 use `pgcrypto`'s `gen_random_uuid()` instead of
`uuid-ossp`'s UUID generation function.
......
......@@ -73,8 +73,12 @@ def ids_writer(ids)
ids.map! { |i| pk_type.cast(i) }
records = klass.where(reflection.association_primary_key => ids).index_by do |r|
r.send(reflection.association_primary_key)
end.values_at(*ids)
replace(records)
end.values_at(*ids).compact
if records.size != ids.size
scope.raise_record_not_found_exception!(ids, records.size, ids.size, reflection.association_primary_key)
else
replace(records)
end
end
def reset
......
......@@ -345,7 +345,7 @@ def exists?(conditions = :none)
# of results obtained should be provided in the +result_size+ argument and
# the expected number of results should be provided in the +expected_size+
# argument.
def raise_record_not_found_exception!(ids = nil, result_size = nil, expected_size = nil) # :nodoc:
def raise_record_not_found_exception!(ids = nil, result_size = nil, expected_size = nil, key = primary_key) # :nodoc:
conditions = arel.where_sql(@klass.arel_engine)
conditions = " [#{conditions}]" if conditions
name = @klass.name
......@@ -355,10 +355,10 @@ def raise_record_not_found_exception!(ids = nil, result_size = nil, expected_siz
error << " with#{conditions}" if conditions
raise RecordNotFound.new(error, name)
elsif Array(ids).size == 1
error = "Couldn't find #{name} with '#{primary_key}'=#{ids}#{conditions}"
raise RecordNotFound.new(error, name, primary_key, ids)
error = "Couldn't find #{name} with '#{key}'=#{ids}#{conditions}"
raise RecordNotFound.new(error, name, key, ids)
else
error = "Couldn't find all #{name.pluralize} with '#{primary_key}': "
error = "Couldn't find all #{name.pluralize} with '#{key}': "
error << "(#{ids.join(", ")})#{conditions} (found #{result_size} results, but was looking for #{expected_size})"
raise RecordNotFound.new(error, name, primary_key, ids)
......
......@@ -886,7 +886,8 @@ def test_collection_singular_ids_setter_with_string_primary_keys
def test_collection_singular_ids_setter_raises_exception_when_invalid_ids_set
company = companies(:rails_core)
ids = [Developer.first.id, -9999]
assert_raises(ActiveRecord::AssociationTypeMismatch) { company.developer_ids = ids }
e = assert_raises(ActiveRecord::RecordNotFound) { company.developer_ids = ids }
assert_match(/Couldn't find all Developers with 'id'/, e.message)
end
def test_build_a_model_from_hm_through_association_with_where_clause
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册