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?
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.