Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

MONGOID-5789 database_field_name given nil or empty string should raise UnknownAttribute exception #5836

Merged
merged 6 commits into from
Jul 12, 2024
Merged

MONGOID-5789 database_field_name given nil or empty string should raise UnknownAttribute exception #5836

merged 6 commits into from
Jul 12, 2024

Conversation

danhealy
Copy link
Contributor

From github discussion: #5540

We are seeing this behavior in 8.1.4

record = Person.first
record[nil]
undefined method `include?' for nil:NilClass      string.include?(".")
            ^^^^^^^^^
/usr/local/bundle/gems/mongoid-8.1.4/lib/mongoid/attributes.rb:272:in `hash_dot_syntax?': undefined method `include?' for nil:NilClass
      
string.include?(".")
            
^^^^^^^^^ (NoMethodError)
    
from /usr/local/bundle/gems/mongoid-8.1.4/lib/mongoid/attributes.rb:297:in `read_raw_attribute'
    
from /usr/local/bundle/gems/mongoid-8.1.4/lib/mongoid/attributes.rb:88:in `read_attribute'

This PR changes the behavior to raise a more helpful Mongoid::Errors::UnknownAttribute exception instead

@jamis
Copy link
Contributor

jamis commented Jul 2, 2024

@danhealy -- as you noted on the Jira ticket, returning an empty string (instead of raising an exception) is probably more appropriate here. A few reasons:

  1. The Mongoid::Errors::UnknownAttribute error is specifically intended for cases where an assignment is detected to an undeclared attribute. You can see this explicitly in the lib/config/locales/en.yml file, under the unknown_attribute key, where it declares "Attempted to set a value for '%{name}' which is not allowed on the model %{klass}." By raising this exception on a simple access, we risk confusing users more because the message is accusing them of attempting to set a value somewhere.
  2. In Mongoid 7.5 and earlier, the default behavior was to return an empty string here (because the name argument was previously invoked with to_s before being passed in, and was thus never nil along the path that's relevant to us here). In Mongoid 8.x, the default was changed, but the legacy behavior could still be accessed by setting Mongoid.broken_alias_handling = true. That compatibility flag was removed in Mongoid 9. Given that the legacy behavior was (effectively) to return an empty string, it's probably appropriate to do the same, here.

There may still be collateral damage from such a change, but a quick check shows that at least some of the tests that were failing as a result raising the exception, pass successfully when an empty string is returned. It's worth experimenting with returning the empty string, I think.

Thank you for your work on this issue!

@johnnyshields
Copy link
Contributor

johnnyshields commented Jul 9, 2024

@danhealy I agree with @jamis and would vote against this change. I have code like the following which would break:

MyModel.database_field_name(:foo) || MyModel.database_field_name(:bar)

Nothing stops you from doing a monkey patch like:

module Mongoid::Document
  class_methods do
    def database_field_name!(name)
      database_field_name(name) || raise(ArgumentError.new("#{self.class} field name not found: #{name}"))
    end
  end
end

@jamis could consider this as a bang (!) variant of the method.

@danhealy
Copy link
Contributor Author

danhealy commented Jul 9, 2024

@jamis and @johnnyshields thank you, I appreciate the feedback!

I see 3 paths forward with this issue:

  1. Do nothing and allow record[nil] to continue to raise the unhelpful exception mentioned in the description
  2. Modify record[nil] to not raise an exception and match the behavior of Mongoid 7 by returning nil
  3. Have record[nil] raise a new exception class

After @jamis 's comment I modified the PR so that it attempts to implement option 2. I will need some assistance going through the test failures.

@jamis
Copy link
Contributor

jamis commented Jul 9, 2024

@danhealy -- I agree that option 2 will be ideal. I'll take a look this afternoon/tomorrow and see what I can find regarding the failures, and what options we might have to fix those. Thanks for your work on this!

This is okay, because the database_field_name method is a private API.
We can change the contract here without regard for who else might
be using it.
@jamis jamis merged commit b2fec3e into mongodb:master Jul 12, 2024
58 checks passed
jamis added a commit to jamis/mongoid that referenced this pull request Jul 12, 2024
…se UnknownAttribute exception (mongodb#5836)

* database_field_name given nil or empty string should raise UnknownAttribute exception

* fix spec syntax

* database_field_name return empty string instead of exception

* `field` might be an empty string, not merely nil

* fix specs to expect empty string instead of nil

This is okay, because the database_field_name method is a private API.
We can change the contract here without regard for who else might
be using it.

---------

Co-authored-by: Jamis Buck <[email protected]>
jamis added a commit that referenced this pull request Jul 15, 2024
* MONGOID-5789 database_field_name given nil or empty string should raise UnknownAttribute exception (#5836)

* database_field_name given nil or empty string should raise UnknownAttribute exception

* fix spec syntax

* database_field_name return empty string instead of exception

* `field` might be an empty string, not merely nil

* fix specs to expect empty string instead of nil

This is okay, because the database_field_name method is a private API.
We can change the contract here without regard for who else might
be using it.

---------

Co-authored-by: Jamis Buck <[email protected]>

* see if we can update the permissions for the Ruby directories

---------

Co-authored-by: Dan Healy <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants