简体   繁体   中英

In Rails tutorial, how can Article subclass from ApplicationRecord without 'require_relative “application_record”'?

Coming from the Python/Django background, I'm reading the https://guides.rubyonrails.org/getting_started.html tutorial. In the sample project, there is an app/models directory with these files,

app/models
├── application_record.rb
└── article.rb

where article.rb contains

class Article < ApplicationRecord
end

and application_record.rb

class ApplicationRecord < ActiveRecord::Base
  self.abstract_class = true
end

Following this answer , I would expect article.rb to have a

require_relative "application_record"

at the top of the file in order to get 'access' to the ApplicationRecord class. Why is this not required in the rails sample project?

The key thing to understand is that imports (requires) in Ruby are global.

Under the hood Rails is requiring application record and then requiring your model files. Since application record was required already (albeit in a different file), the models, and all other bits of code loaded thereafter, have access to it.

You can see this in the following simple example:

# a.rb
require 'b'
require 'c'

# b.rb
class ThisIsExported; end

# c.rb
puts defined?(ThisisExported) # => 'constant'

Remember that classes, modules, and constants are all globals (although they can be namespaced), and that these are the only things 'exported' from a file (well, naked methods can also be exported, but these are actually defined on a global Object instance). So, requiring a file in Ruby is not so much 'importing' it to a specific file, but rather like calling 'eval' on that file's source code.

You can think of it as as if Ruby is just find-and-replacing all require calls with that file's actual source code ... this isn't actally what's happening but the effect is the same.

The closest thing Ruby has to strictly file-specific imports are refinements, but you still need to package those up into a global anyway, and the behaviour is not entirely consistent with regular imports (for example defined? will not be accurate)

# a.rb
require 'b'
require 'c'
require 'd'

# b.rb
module FileSpecificModuleInclude
  refine(Object) do
    def patched; 'ok'; end
  end
end

# c.rb
using FileSpecificModuleInclude
# It says it's not defined ....
puts defined?(patched) # => nil
# But it actually is ...
puts patched # => 'ok'

# d.rb
patched # => NoMethodError

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