Uploaded image for project: 'Mongoid'
  1. Mongoid
  2. MONGOID-5009

Belongs to relationship makes all target association methods effectively public

    • Type: Icon: Bug Bug
    • Resolution: Unresolved
    • Priority: Icon: Major - P3 Major - P3
    • None
    • Affects Version/s: 7.1.4
    • Component/s: Associations
    • Labels:
    • Environment:
      Tried in macOS and Ubuntu

      When defining belongs_to/has_one associations, the methods in the associated object change visibilty and ruby's `defined?` doesn't detect them.
      When doing `parent.child = child`, the associated object is cloned (object_id changes) and while the class, ancestors, and everything looks and feels the same, something happens where the private methods are made public, and public methods are there but not recognized by ruby's `defined?`.
      Same happens when doing `child.parent = parent`

      Here's a minimal reproduction case:

      require 'bundler/inline'
      
      gemfile do
        source 'https://rubygems.org'
        gem 'mongoid', '~> 7.1.4'
        gem 'minitest', '~> 5.14.1', require: ['minitest', 'minitest/autorun']
      end
      
      class Parent
        include Mongoid::Document
      
        belongs_to :child
      
        def a_public_method
          'parent public'
        end
      
        private
      
        def a_private_method
          'parent private'
        end
      end
      
      class Child
        include Mongoid::Document
      
        has_one :parent
      
        def a_public_method
          'child public'
        end
      
        private
      
        def a_private_method
          'child private'
        end
      end
      
      class TestRelationships < Minitest::Test
        def test_child_private_methods_stay_private
          parent = Parent.new
          child = Child.new
      
          parent.child = child
      
          assert_raises NoMethodError do
            child.a_private_method
          end
      
          assert_raises NoMethodError do
            parent.child.a_private_method
          end
        end
      
        def test_child_methods_are_defined
          parent = Parent.new
          child = Child.new
      
          parent.child = child
      
          assert_equal 'method', defined?(child.a_public_method)
          assert_equal 'method', defined?(parent.child.a_public_method)
        end
      
        def test_parent_private_methods_stay_private
          child = Child.new
          parent = Parent.new
      
          child.parent = parent
      
          assert_raises NoMethodError do
            parent.a_private_method
          end
      
          assert_raises NoMethodError do
            child.parent.a_private_method
          end
        end
      
        def test_parent_methods_are_defined
          child = Child.new
          parent = Parent.new
      
          child.parent = parent
      
          assert_equal 'method', defined?(parent.a_public_method)
          assert_equal 'method', defined?(child.parent.a_public_method)
        end
      end
      

            Assignee:
            Unassigned Unassigned
            Reporter:
            ejpastorino@gmail.com Esteban Pastorino
            Votes:
            0 Vote for this issue
            Watchers:
            5 Start watching this issue

              Created:
              Updated: