简体   繁体   中英

autoload_paths not aware of namespace?

In app/services , I have some classes, as Notification::Finder and Notification::Builder .

They are placed as app/services/notification/builder.rb and app/services/notification/finder.rb .

There is also the Notification class as a model, at app/models/notification.rb

The autoload_path is configurated as in config.autoload_paths += %W(#{config.root}/app/services)

When I try to load Finder , it works:

Loading development environment (Rails 3.2.9)
[1] pry(main)> Notification::Finder
=> Notification::Finder

But when I try the Builder , I get a problem with the rails autoloading:

Loading development environment (Rails 3.2.9)
[1] pry(main)> Notification::Builder
=> ActiveRecord::Associations::Builder

It just ignores the namespace I've used when the constant name (Builder) has already been defined by other namespace, and gets the ActiveRecord::Associations::Builder instead.

Is this the expected behavior, or a rails bug?

Going more detailed, the const_missing method at activesupport/dependencies.rb receives a const_name 'Builder' , and nesting.inspect => 'nil' .

Curious that when I use constantize, it resolves as expected:

Loading development environment (Rails 3.2.9)
[1] pry(main)> 'Notification::Builder'.constantize
=> Notification::Builder

( Rails issue at github: https://github.com/rails/rails/issues/8726 )

ActiveRecord::Associations::Builder is a module in Rails. If you have a Notification::Builder, you can ask it its class:

>> Notification::Builder
=> ActiveRecord::Associations::Builder
>> Notification::Builder.class
=> Module
>> Notification::Builder.ancestors
=> [ActiveRecord::Associations::Builder]

Is this expected behavior?

Yes

OK, so... what choices do you have?

  • You can use a different term than Builder. Like Factory. or Notification::NotificationBuilder

More info:
* http://www.rubydoc.info/docs/rails/3.1.1/ActiveRecord/Associations/Builder/Association
* http://apidock.com/rails/ActiveRecord/Associations/Builder

This problem exists because you are using an ActiveRecord model as a namespace. I created a gist with some experimentation until I saw the root cause.

ActiveRecord models include the ActiveRecord::Associations module. Since you can get to a constant when including a module the Builder constant defined within Associations is now also reachable through the AR model. You will get this behavior with every class defined in the modules, which are included into an AR model:

1.9.3-p194 :010 > Post.ancestors
 => [Post(id: integer, title: string, published_at: datetime, created_at: datetime, updated_at: datetime), Post::GeneratedFeatureMethods, #<Module:0x007fec74dc33a0>, ActiveRecord::Base, ActiveRecord::Core, ActiveRecord::Store, ActiveRecord::Serialization, ActiveModel::Serializers::Xml, ActiveModel::Serializers::JSON, ActiveModel::Serialization, ActiveRecord::Reflection, ActiveRecord::Transactions, ActiveRecord::Aggregations, ActiveRecord::NestedAttributes, ActiveRecord::AutosaveAssociation, ActiveModel::SecurePassword, ActiveRecord::Associations, ActiveRecord::Timestamp, ActiveModel::Validations::Callbacks, ActiveRecord::Callbacks, ActiveRecord::AttributeMethods::Serialization, ActiveRecord::AttributeMethods::Dirty, ActiveModel::Dirty, ActiveRecord::AttributeMethods::TimeZoneConversion, ActiveRecord::AttributeMethods::PrimaryKey, ActiveRecord::AttributeMethods::Query, ActiveRecord::AttributeMethods::BeforeTypeCast, ActiveRecord::AttributeMethods::Write, ActiveRecord::AttributeMethods::Read, ActiveRecord::AttributeMethods, ActiveModel::AttributeMethods, ActiveRecord::Locking::Pessimistic, ActiveRecord::Locking::Optimistic, ActiveRecord::CounterCache, ActiveRecord::Validations, ActiveModel::Validations::HelperMethods, ActiveSupport::Callbacks, ActiveModel::Validations, ActiveRecord::Integration, ActiveModel::Conversion, ActiveRecord::AttributeAssignment, ActiveModel::ForbiddenAttributesProtection, ActiveModel::DeprecatedMassAssignmentSecurity, ActiveRecord::Sanitization, ActiveRecord::Scoping::Named, ActiveRecord::Scoping::Default, ActiveRecord::Scoping, ActiveRecord::Inheritance, ActiveRecord::ModelSchema, ActiveRecord::ReadonlyAttributes, ActiveRecord::Persistence, Object, PP::ObjectMixin, ActiveSupport::Dependencies::Loadable, V8::Conversion::Object, JSON::Ext::Generator::GeneratorMethods::Object, Kernel, BasicObject] 

A possible solution is to use a module as a namespace. For example module Notifications .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM