mirror of https://github.com/rails/rails
Clean up checks to see if DidYouMean is defined
As of Ruby 2.7 DidYouMean is included as a default gem, so there is no need to check if DidYouMean is defined in the test suite. We still need to check if the DidYouMean modules are defined in the actual code, as someone might run Rails with DidYouMean disabled by using the `--disable-did_you_mean` flag. This is ussually done for performance reasons. This commit also includes some of the changes made by Yuki in: https://github.com/rails/rails/pull/39555 These changes include replacing Jaro with the more accurate SpellChecker, and using DidYouMean::Correctable for simplere corrections. The DidYouMean::SpellChecker does have a treshold for corrections. If there is not enough similarity it might not return a suggestion. To stop the tests from failing some test data had to be changed. For example, `non_existent` does not meet the treshold for `hello`, but `ello` does: DidYouMean::SpellChecker.new(dictionary: %w[hello]).correct('non_existent') => [] DidYouMean::SpellChecker.new(dictionary: %w[hello]).correct('ello') => ["hello"] The treshold makes sense for spelling errors. But maybe we should add a different SpellChecker that helps to get a suggestion even if there is little overlap. For example for when a model only has 2 attributes (title and body), it's helpful to get a suggestion for `name` Co-Authored-By: Yuki Nishijima <yk.nishijima@gmail.com>
This commit is contained in:
parent
7179dcb269
commit
0409ed57ac
|
@ -16,28 +16,13 @@ module AbstractController
|
||||||
super(message)
|
super(message)
|
||||||
end
|
end
|
||||||
|
|
||||||
class Correction
|
if defined?(DidYouMean::Correctable) && defined?(DidYouMean::SpellChecker)
|
||||||
def initialize(error)
|
include DidYouMean::Correctable
|
||||||
@error = error
|
|
||||||
end
|
|
||||||
|
|
||||||
def corrections
|
def corrections
|
||||||
if @error.action
|
@corrections ||= DidYouMean::SpellChecker.new(dictionary: controller.class.action_methods).correct(action)
|
||||||
maybe_these = @error.controller.class.action_methods
|
|
||||||
|
|
||||||
maybe_these.sort_by { |n|
|
|
||||||
DidYouMean::Jaro.distance(@error.action.to_s, n)
|
|
||||||
}.reverse.first(4)
|
|
||||||
else
|
|
||||||
[]
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# We may not have DYM, and DYM might not let us register error handlers
|
|
||||||
if defined?(DidYouMean) && DidYouMean.respond_to?(:correct_error)
|
|
||||||
DidYouMean.correct_error(self, Correction)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# AbstractController::Base is a low-level API. Nobody should be
|
# AbstractController::Base is a low-level API. Nobody should be
|
||||||
|
|
|
@ -33,29 +33,18 @@ module ActionController
|
||||||
super(message)
|
super(message)
|
||||||
end
|
end
|
||||||
|
|
||||||
class Correction
|
if defined?(DidYouMean::Correctable) && defined?(DidYouMean::SpellChecker)
|
||||||
def initialize(error)
|
include DidYouMean::Correctable
|
||||||
@error = error
|
|
||||||
end
|
|
||||||
|
|
||||||
def corrections
|
def corrections
|
||||||
if @error.method_name
|
@corrections ||= begin
|
||||||
maybe_these = @error.routes.named_routes.helper_names.grep(/#{@error.route_name}/)
|
maybe_these = routes&.named_routes&.helper_names&.grep(/#{route_name}/) || []
|
||||||
maybe_these -= [@error.method_name.to_s] # remove exact match
|
maybe_these -= [method_name.to_s] # remove exact match
|
||||||
|
|
||||||
maybe_these.sort_by { |n|
|
DidYouMean::SpellChecker.new(dictionary: maybe_these).correct(route_name)
|
||||||
DidYouMean::Jaro.distance(@error.route_name, n)
|
|
||||||
}.reverse.first(4)
|
|
||||||
else
|
|
||||||
[]
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# We may not have DYM, and DYM might not let us register error handlers
|
|
||||||
if defined?(DidYouMean) && DidYouMean.respond_to?(:correct_error)
|
|
||||||
DidYouMean.correct_error(self, Correction)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
class MethodNotAllowed < ActionControllerError #:nodoc:
|
class MethodNotAllowed < ActionControllerError #:nodoc:
|
||||||
|
|
|
@ -27,28 +27,13 @@ module ActionController
|
||||||
super("param is missing or the value is empty: #{param}")
|
super("param is missing or the value is empty: #{param}")
|
||||||
end
|
end
|
||||||
|
|
||||||
class Correction
|
if defined?(DidYouMean::Correctable) && defined?(DidYouMean::SpellChecker)
|
||||||
def initialize(error)
|
include DidYouMean::Correctable
|
||||||
@error = error
|
|
||||||
end
|
|
||||||
|
|
||||||
def corrections
|
def corrections
|
||||||
if @error.param && @error.keys
|
@corrections ||= DidYouMean::SpellChecker.new(dictionary: keys).correct(param.to_s)
|
||||||
maybe_these = @error.keys
|
|
||||||
|
|
||||||
maybe_these.sort_by { |n|
|
|
||||||
DidYouMean::Jaro.distance(@error.param.to_s, n)
|
|
||||||
}.reverse.first(4)
|
|
||||||
else
|
|
||||||
[]
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# We may not have DYM, and DYM might not let us register error handlers
|
|
||||||
if defined?(DidYouMean) && DidYouMean.respond_to?(:correct_error)
|
|
||||||
DidYouMean.correct_error(self, Correction)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# Raised when a supplied parameter is not expected and
|
# Raised when a supplied parameter is not expected and
|
||||||
|
|
|
@ -172,14 +172,12 @@ class PerformActionTest < ActionController::TestCase
|
||||||
assert_equal "The action 'non_existent' could not be found for EmptyController", exception.message
|
assert_equal "The action 'non_existent' could not be found for EmptyController", exception.message
|
||||||
end
|
end
|
||||||
|
|
||||||
if defined?(DidYouMean) && DidYouMean.respond_to?(:correct_error)
|
def test_exceptions_have_suggestions_for_fix
|
||||||
def test_exceptions_have_suggestions_for_fix
|
use_controller SimpleController
|
||||||
use_controller SimpleController
|
exception = assert_raise AbstractController::ActionNotFound do
|
||||||
exception = assert_raise AbstractController::ActionNotFound do
|
get :ello
|
||||||
get :non_existent
|
|
||||||
end
|
|
||||||
assert_match "Did you mean?", exception.message
|
|
||||||
end
|
end
|
||||||
|
assert_match "Did you mean?", exception.message
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_action_missing_should_work
|
def test_action_missing_should_work
|
||||||
|
|
|
@ -22,18 +22,16 @@ class ActionControllerRequiredParamsTest < ActionController::TestCase
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
if defined?(DidYouMean) && DidYouMean.respond_to?(:correct_error)
|
test "exceptions have suggestions for fix" do
|
||||||
test "exceptions have suggestions for fix" do
|
error = assert_raise ActionController::ParameterMissing do
|
||||||
error = assert_raise ActionController::ParameterMissing do
|
post :create, params: { boko: { name: "Mjallo!" } }
|
||||||
post :create, params: { magazine: { name: "Mjallo!" } }
|
|
||||||
end
|
|
||||||
assert_match "Did you mean?", error.message
|
|
||||||
|
|
||||||
error = assert_raise ActionController::ParameterMissing do
|
|
||||||
post :create, params: { book: { title: "Mjallo!" } }
|
|
||||||
end
|
|
||||||
assert_match "Did you mean?", error.message
|
|
||||||
end
|
end
|
||||||
|
assert_match "Did you mean?", error.message
|
||||||
|
|
||||||
|
error = assert_raise ActionController::ParameterMissing do
|
||||||
|
post :create, params: { book: { naem: "Mjallo!" } }
|
||||||
|
end
|
||||||
|
assert_match "Did you mean?", error.message
|
||||||
end
|
end
|
||||||
|
|
||||||
test "required parameters that are present will not raise" do
|
test "required parameters that are present will not raise" do
|
||||||
|
|
|
@ -64,7 +64,7 @@ class DebugExceptionsTest < ActionDispatch::IntegrationTest
|
||||||
[404, { "X-Cascade" => "pass" }, self]
|
[404, { "X-Cascade" => "pass" }, self]
|
||||||
when "/not_found"
|
when "/not_found"
|
||||||
controller = SimpleController.new
|
controller = SimpleController.new
|
||||||
raise AbstractController::ActionNotFound.new(nil, controller, :not_found)
|
raise AbstractController::ActionNotFound.new(nil, controller, :ello)
|
||||||
when "/runtime_error"
|
when "/runtime_error"
|
||||||
raise RuntimeError
|
raise RuntimeError
|
||||||
when "/method_not_allowed"
|
when "/method_not_allowed"
|
||||||
|
@ -98,7 +98,7 @@ class DebugExceptionsTest < ActionDispatch::IntegrationTest
|
||||||
when "/missing_keys"
|
when "/missing_keys"
|
||||||
raise ActionController::UrlGenerationError, "No route matches"
|
raise ActionController::UrlGenerationError, "No route matches"
|
||||||
when "/parameter_missing"
|
when "/parameter_missing"
|
||||||
raise ActionController::ParameterMissing.new(:missing_param_key, %w(valid_param_key))
|
raise ActionController::ParameterMissing.new(:invalid_param_key, %w(valid_param_key))
|
||||||
when "/original_syntax_error"
|
when "/original_syntax_error"
|
||||||
eval "broke_syntax =" # `eval` need for raise native SyntaxError at runtime
|
eval "broke_syntax =" # `eval` need for raise native SyntaxError at runtime
|
||||||
when "/syntax_error_into_view"
|
when "/syntax_error_into_view"
|
||||||
|
@ -318,20 +318,18 @@ class DebugExceptionsTest < ActionDispatch::IntegrationTest
|
||||||
assert_match(/ActionDispatch::Http::MimeNegotiation::InvalidType/, body)
|
assert_match(/ActionDispatch::Http::MimeNegotiation::InvalidType/, body)
|
||||||
end
|
end
|
||||||
|
|
||||||
if defined?(DidYouMean) && DidYouMean.respond_to?(:correct_error)
|
test "rescue with suggestions" do
|
||||||
test "rescue with suggestions" do
|
@app = DevelopmentApp
|
||||||
@app = DevelopmentApp
|
|
||||||
|
|
||||||
get "/not_found", headers: { "action_dispatch.show_exceptions" => true }
|
get "/not_found", headers: { "action_dispatch.show_exceptions" => true }
|
||||||
assert_response 404
|
assert_response 404
|
||||||
assert_select("b", /Did you mean\?/)
|
assert_select("b", /Did you mean\?/)
|
||||||
assert_select("li", "hello")
|
assert_select("li", "hello")
|
||||||
|
|
||||||
get "/parameter_missing", headers: { "action_dispatch.show_exceptions" => true }
|
get "/parameter_missing", headers: { "action_dispatch.show_exceptions" => true }
|
||||||
assert_response 400
|
assert_response 400
|
||||||
assert_select("b", /Did you mean\?/)
|
assert_select("b", /Did you mean\?/)
|
||||||
assert_select("li", "valid_param_key")
|
assert_select("li", "valid_param_key")
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
test "rescue with HTML format for HTML API request" do
|
test "rescue with HTML format for HTML API request" do
|
||||||
|
|
|
@ -4913,11 +4913,9 @@ class TestUrlGenerationErrors < ActionDispatch::IntegrationTest
|
||||||
assert_match message, error.message
|
assert_match message, error.message
|
||||||
end
|
end
|
||||||
|
|
||||||
if defined?(DidYouMean) && DidYouMean.respond_to?(:correct_error)
|
test "exceptions have suggestions for fix" do
|
||||||
test "exceptions have suggestions for fix" do
|
error = assert_raises(ActionController::UrlGenerationError) { product_path(nil, "id" => "url-tested") }
|
||||||
error = assert_raises(ActionController::UrlGenerationError) { product_path(nil, "id" => "url-tested") }
|
assert_match "Did you mean?", error.message
|
||||||
assert_match "Did you mean?", error.message
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# FIXME: we should fix all locations that raise this exception to provide
|
# FIXME: we should fix all locations that raise this exception to provide
|
||||||
|
@ -4926,8 +4924,8 @@ class TestUrlGenerationErrors < ActionDispatch::IntegrationTest
|
||||||
# we don't want to break other code.
|
# we don't want to break other code.
|
||||||
test "correct for empty UrlGenerationError" do
|
test "correct for empty UrlGenerationError" do
|
||||||
err = ActionController::UrlGenerationError.new("oh no!")
|
err = ActionController::UrlGenerationError.new("oh no!")
|
||||||
correction = ActionController::UrlGenerationError::Correction.new(err)
|
|
||||||
assert_equal [], correction.corrections
|
assert_equal [], err.corrections
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -627,31 +627,29 @@ module RenderTestCases
|
||||||
assert_match "Missing partial /_true with", e.message
|
assert_match "Missing partial /_true with", e.message
|
||||||
end
|
end
|
||||||
|
|
||||||
if defined?(DidYouMean) && DidYouMean.respond_to?(:correct_error)
|
def test_render_partial_provides_spellcheck
|
||||||
def test_render_partial_provides_spellcheck
|
e = assert_raises(ActionView::MissingTemplate) { @view.render(partial: "test/partail") }
|
||||||
e = assert_raises(ActionView::MissingTemplate) { @view.render(partial: "test/partail") }
|
assert_match %r{Did you mean\? test/partial\n *test/partialhtml}, e.message
|
||||||
assert_match %r{Did you mean\? test/partial\n *test/partialhtml}, e.message
|
end
|
||||||
end
|
|
||||||
|
|
||||||
def test_spellcheck_doesnt_list_directories
|
def test_spellcheck_doesnt_list_directories
|
||||||
e = assert_raises(ActionView::MissingTemplate) { @view.render(partial: "test/directory") }
|
e = assert_raises(ActionView::MissingTemplate) { @view.render(partial: "test/directory") }
|
||||||
assert_match %r{Did you mean\?}, e.message
|
assert_match %r{Did you mean\?}, e.message
|
||||||
assert_no_match %r{Did you mean\? test/directory\n}, e.message # test/hello is a directory
|
assert_no_match %r{Did you mean\? test/directory\n}, e.message # test/hello is a directory
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_spellcheck_only_lists_templates
|
def test_spellcheck_only_lists_templates
|
||||||
e = assert_raises(ActionView::MissingTemplate) { @view.render(template: "test/partial") }
|
e = assert_raises(ActionView::MissingTemplate) { @view.render(template: "test/partial") }
|
||||||
|
|
||||||
assert_match %r{Did you mean\?}, e.message
|
assert_match %r{Did you mean\?}, e.message
|
||||||
assert_no_match %r{Did you mean\? test/partial\n}, e.message
|
assert_no_match %r{Did you mean\? test/partial\n}, e.message
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_spellcheck_only_lists_partials
|
def test_spellcheck_only_lists_partials
|
||||||
e = assert_raises(ActionView::MissingTemplate) { @view.render(partial: "test/template") }
|
e = assert_raises(ActionView::MissingTemplate) { @view.render(partial: "test/template") }
|
||||||
|
|
||||||
assert_match %r{Did you mean\?}, e.message
|
assert_match %r{Did you mean\?}, e.message
|
||||||
assert_no_match %r{Did you mean\? test/template\n}, e.message
|
assert_no_match %r{Did you mean\? test/template\n}, e.message
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_render_partial_wrong_details_no_spellcheck
|
def test_render_partial_wrong_details_no_spellcheck
|
||||||
|
|
|
@ -13,28 +13,16 @@ module ActiveRecord
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
class Correction
|
if defined?(DidYouMean::Correctable) && defined?(DidYouMean::SpellChecker)
|
||||||
def initialize(error)
|
include DidYouMean::Correctable
|
||||||
@error = error
|
|
||||||
end
|
|
||||||
|
|
||||||
def corrections
|
def corrections
|
||||||
if @error.association_name
|
@corrections ||= begin
|
||||||
maybe_these = @error.record.class.reflections.keys
|
maybe_these = record&.class&.reflections&.keys
|
||||||
|
DidYouMean::SpellChecker.new(dictionary: maybe_these).correct(association_name.to_s)
|
||||||
maybe_these.sort_by { |n|
|
|
||||||
DidYouMean::Jaro.distance(@error.association_name.to_s, n)
|
|
||||||
}.reverse.first(4)
|
|
||||||
else
|
|
||||||
[]
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# We may not have DYM, and DYM might not let us register error handlers
|
|
||||||
if defined?(DidYouMean) && DidYouMean.respond_to?(:correct_error)
|
|
||||||
DidYouMean.correct_error(self, Correction)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
class InverseOfAssociationNotFoundError < ActiveRecordError #:nodoc:
|
class InverseOfAssociationNotFoundError < ActiveRecordError #:nodoc:
|
||||||
|
@ -49,28 +37,20 @@ module ActiveRecord
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
class Correction
|
if defined?(DidYouMean::Correctable) && defined?(DidYouMean::SpellChecker)
|
||||||
def initialize(error)
|
include DidYouMean::Correctable
|
||||||
@error = error
|
|
||||||
end
|
|
||||||
|
|
||||||
def corrections
|
def corrections
|
||||||
if @error.reflection && @error.associated_class
|
if reflection && associated_class
|
||||||
maybe_these = @error.associated_class.reflections.keys
|
@corrections ||= begin
|
||||||
|
maybe_these = associated_class.reflections.keys
|
||||||
maybe_these.sort_by { |n|
|
DidYouMean::SpellChecker.new(dictionary: maybe_these).correct(reflection.options[:inverse_of].to_s)
|
||||||
DidYouMean::Jaro.distance(@error.reflection.options[:inverse_of].to_s, n)
|
end
|
||||||
}.reverse.first(4)
|
|
||||||
else
|
else
|
||||||
[]
|
[]
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# We may not have DYM, and DYM might not let us register error handlers
|
|
||||||
if defined?(DidYouMean) && DidYouMean.respond_to?(:correct_error)
|
|
||||||
DidYouMean.correct_error(self, Correction)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
class HasManyThroughAssociationNotFoundError < ActiveRecordError #:nodoc:
|
class HasManyThroughAssociationNotFoundError < ActiveRecordError #:nodoc:
|
||||||
|
@ -86,29 +66,21 @@ module ActiveRecord
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
class Correction
|
if defined?(DidYouMean::Correctable) && defined?(DidYouMean::SpellChecker)
|
||||||
def initialize(error)
|
include DidYouMean::Correctable
|
||||||
@error = error
|
|
||||||
end
|
|
||||||
|
|
||||||
def corrections
|
def corrections
|
||||||
if @error.reflection && @error.owner_class
|
if owner_class && reflection
|
||||||
maybe_these = @error.owner_class.reflections.keys
|
@corrections ||= begin
|
||||||
maybe_these -= [@error.reflection.name.to_s] # remove failing reflection
|
maybe_these = owner_class.reflections.keys
|
||||||
|
maybe_these -= [reflection.name.to_s] # remove failing reflection
|
||||||
maybe_these.sort_by { |n|
|
DidYouMean::SpellChecker.new(dictionary: maybe_these).correct(reflection.options[:through].to_s)
|
||||||
DidYouMean::Jaro.distance(@error.reflection.options[:through].to_s, n)
|
end
|
||||||
}.reverse.first(4)
|
|
||||||
else
|
else
|
||||||
[]
|
[]
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# We may not have DYM, and DYM might not let us register error handlers
|
|
||||||
if defined?(DidYouMean) && DidYouMean.respond_to?(:correct_error)
|
|
||||||
DidYouMean.correct_error(self, Correction)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
class HasManyThroughAssociationPolymorphicSourceError < ActiveRecordError #:nodoc:
|
class HasManyThroughAssociationPolymorphicSourceError < ActiveRecordError #:nodoc:
|
||||||
|
|
|
@ -848,13 +848,11 @@ class EagerAssociationTest < ActiveRecord::TestCase
|
||||||
assert_match(/Association named 'monkeys' was not found on Post; perhaps you misspelled it\?/, e.message)
|
assert_match(/Association named 'monkeys' was not found on Post; perhaps you misspelled it\?/, e.message)
|
||||||
end
|
end
|
||||||
|
|
||||||
if defined?(DidYouMean) && DidYouMean.respond_to?(:correct_error)
|
test "exceptions have suggestions for fix" do
|
||||||
test "exceptions have suggestions for fix" do
|
error = assert_raise(ActiveRecord::AssociationNotFoundError) {
|
||||||
error = assert_raise(ActiveRecord::AssociationNotFoundError) {
|
Post.all.merge!(includes: :taggingz).find(6)
|
||||||
Post.all.merge!(includes: :monkeys).find(6)
|
}
|
||||||
}
|
assert_match "Did you mean? tagging\n", error.message
|
||||||
assert_match "Did you mean?", error.message
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_eager_has_many_through_with_order
|
def test_eager_has_many_through_with_order
|
||||||
|
|
|
@ -336,15 +336,13 @@ class InverseHasOneTests < ActiveRecord::TestCase
|
||||||
assert_raise(ActiveRecord::InverseOfAssociationNotFoundError) { Human.first.confused_face }
|
assert_raise(ActiveRecord::InverseOfAssociationNotFoundError) { Human.first.confused_face }
|
||||||
end
|
end
|
||||||
|
|
||||||
if defined?(DidYouMean) && DidYouMean.respond_to?(:correct_error)
|
def test_trying_to_use_inverses_that_dont_exist_should_have_suggestions_for_fix
|
||||||
def test_trying_to_use_inverses_that_dont_exist_should_have_suggestions_for_fix
|
error = assert_raise(ActiveRecord::InverseOfAssociationNotFoundError) {
|
||||||
error = assert_raise(ActiveRecord::InverseOfAssociationNotFoundError) {
|
Human.first.confused_face
|
||||||
Human.first.confused_face
|
}
|
||||||
}
|
|
||||||
|
|
||||||
assert_match "Did you mean?", error.message
|
assert_match "Did you mean?", error.message
|
||||||
assert_equal "super_human", error.corrections.first
|
assert_equal "confused_human", error.corrections.first
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -751,18 +749,16 @@ class InverseBelongsToTests < ActiveRecord::TestCase
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_trying_to_use_inverses_that_dont_exist_should_raise_an_error
|
def test_trying_to_use_inverses_that_dont_exist_should_raise_an_error
|
||||||
assert_raise(ActiveRecord::InverseOfAssociationNotFoundError) { Face.first.puzzled_human }
|
assert_raise(ActiveRecord::InverseOfAssociationNotFoundError) { Face.first.confused_human }
|
||||||
end
|
end
|
||||||
|
|
||||||
if defined?(DidYouMean) && DidYouMean.respond_to?(:correct_error)
|
def test_trying_to_use_inverses_that_dont_exist_should_have_suggestions_for_fix
|
||||||
def test_trying_to_use_inverses_that_dont_exist_should_have_suggestions_for_fix
|
error = assert_raise(ActiveRecord::InverseOfAssociationNotFoundError) {
|
||||||
error = assert_raise(ActiveRecord::InverseOfAssociationNotFoundError) {
|
Face.first.confused_human
|
||||||
Face.first.puzzled_human
|
}
|
||||||
}
|
|
||||||
|
|
||||||
assert_match "Did you mean?", error.message
|
assert_match "Did you mean?", error.message
|
||||||
assert_equal "confused_face", error.corrections.first
|
assert_equal "confused_face", error.corrections.first
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_building_has_many_parent_association_inverses_one_record
|
def test_building_has_many_parent_association_inverses_one_record
|
||||||
|
|
|
@ -341,13 +341,11 @@ class AssociationsJoinModelTest < ActiveRecord::TestCase
|
||||||
assert_raise(ActiveRecord::HasManyThroughAssociationNotFoundError) { authors(:david).nothings }
|
assert_raise(ActiveRecord::HasManyThroughAssociationNotFoundError) { authors(:david).nothings }
|
||||||
end
|
end
|
||||||
|
|
||||||
if defined?(DidYouMean) && DidYouMean.respond_to?(:correct_error)
|
def test_exceptions_have_suggestions_for_fix
|
||||||
def test_exceptions_have_suggestions_for_fix
|
error = assert_raise(ActiveRecord::HasManyThroughAssociationNotFoundError) {
|
||||||
error = assert_raise(ActiveRecord::HasManyThroughAssociationNotFoundError) {
|
authors(:david).nothings
|
||||||
authors(:david).nothings
|
}
|
||||||
}
|
assert_match "Did you mean?", error.message
|
||||||
assert_match "Did you mean?", error.message
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_has_many_through_join_model_with_conditions
|
def test_has_many_through_join_model_with_conditions
|
||||||
|
|
|
@ -149,7 +149,7 @@ class Author < ActiveRecord::Base
|
||||||
has_many :categorized_posts, through: :categorizations, source: :post
|
has_many :categorized_posts, through: :categorizations, source: :post
|
||||||
has_many :unique_categorized_posts, -> { distinct }, through: :categorizations, source: :post
|
has_many :unique_categorized_posts, -> { distinct }, through: :categorizations, source: :post
|
||||||
|
|
||||||
has_many :nothings, through: :kateggorisatons, class_name: "Category"
|
has_many :nothings, through: :kateggorizatons, class_name: "Category"
|
||||||
|
|
||||||
has_many :author_favorites
|
has_many :author_favorites
|
||||||
has_many :favorite_authors, -> { order("name") }, through: :author_favorites
|
has_many :favorite_authors, -> { order("name") }, through: :author_favorites
|
||||||
|
|
|
@ -8,7 +8,7 @@ class Face < ActiveRecord::Base
|
||||||
# Oracle identifier length is limited to 30 bytes or less, `polymorphic` renamed `poly`
|
# Oracle identifier length is limited to 30 bytes or less, `polymorphic` renamed `poly`
|
||||||
belongs_to :poly_human_without_inverse, polymorphic: true
|
belongs_to :poly_human_without_inverse, polymorphic: true
|
||||||
# These are "broken" inverse_of associations for the purposes of testing
|
# These are "broken" inverse_of associations for the purposes of testing
|
||||||
belongs_to :puzzled_human, class_name: "Human", inverse_of: :puzzled_face
|
belongs_to :confused_human, class_name: "Human", inverse_of: :cnffused_face
|
||||||
belongs_to :puzzled_polymorphic_human, polymorphic: true, inverse_of: :puzzled_polymorphic_face
|
belongs_to :puzzled_polymorphic_human, polymorphic: true, inverse_of: :puzzled_polymorphic_face
|
||||||
|
|
||||||
validate do
|
validate do
|
||||||
|
|
|
@ -24,7 +24,7 @@ class Human < ActiveRecord::Base
|
||||||
after_add: :add_called,
|
after_add: :add_called,
|
||||||
inverse_of: :polymorphic_human
|
inverse_of: :polymorphic_human
|
||||||
# These are "broken" inverse_of associations for the purposes of testing
|
# These are "broken" inverse_of associations for the purposes of testing
|
||||||
has_one :confused_face, class_name: "Face", inverse_of: :confused_human
|
has_one :confused_face, class_name: "Face", inverse_of: :cnffused_human
|
||||||
has_many :secret_interests, class_name: "Interest", inverse_of: :secret_human
|
has_many :secret_interests, class_name: "Interest", inverse_of: :secret_human
|
||||||
has_one :mixed_case_monkey
|
has_one :mixed_case_monkey
|
||||||
|
|
||||||
|
|
|
@ -26,7 +26,7 @@ module Rails
|
||||||
include DidYouMean::Correctable
|
include DidYouMean::Correctable
|
||||||
|
|
||||||
def corrections
|
def corrections
|
||||||
DidYouMean::SpellChecker.new(dictionary: options).correct(key)
|
@corrections ||= DidYouMean::SpellChecker.new(dictionary: options).correct(key)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in New Issue