1
0
Fork 0
mirror of https://github.com/rails/rails.git synced 2022-11-09 12:12:34 -05:00

updates docs about engine overrides [skip ci]

This commit is contained in:
Xavier Noria 2020-02-02 01:09:11 +01:00
parent cb6f25c757
commit b1d94dabc5

View file

@ -1102,81 +1102,56 @@ main Rails application.
### Overriding Models and Controllers ### Overriding Models and Controllers
Engine model and controller classes can be extended by open classing them in the Engine models and controllers can be reopened by the parent application to extend or decorate them.
main Rails application (since model and controller classes are just Ruby classes
that inherit Rails specific functionality). Open classing an Engine class
redefines it for use in the main application.
For simple class modifications, use `Class#class_eval`. For complex class Overrides may be organized in a dedicated directory `app/overrides` that is preloaded in a `to_prepare` callback.
modifications, consider using `ActiveSupport::Concern`.
#### A note on Overriding and Loading Code In `zeitwerk` mode you'd do this:
Because these overrides are not referenced by your Rails application itself,
Rails' autoloading system will not kick in and load your overrides. This means
that you need to require them yourself.
Here is some sample code to do this:
```ruby ```ruby
# lib/blorgh/engine.rb # config/application.rb
module Blorgh module MyApp
class Engine < ::Rails::Engine class Application < Rails::Application
isolate_namespace Blorgh ...
overrides = "#{Rails.root}/app/overrides"
Rails.autoloaders.main.ignore(overrides)
config.to_prepare do
Dir.glob("#{overrides}/**/*_override.rb").each do |override|
load override
end
end
end
end
```
and in `classsic` mode this:
```ruby
# config/application.rb
module MyApp
class Application < Rails::Application
...
config.to_prepare do config.to_prepare do
Dir.glob(Rails.root + "app/overrides/**/*_override*.rb").each do |c| Dir.glob("#{Rails.root}/app/overrides/**/*_override.rb").each do |override|
require_dependency(c) require_dependency override
end end
end end
end end
end end
``` ```
This doesn't apply to just overrides, but anything that you add in an engine #### Reopening existing classes using `class_eval`
that isn't referenced by your main application.
#### Reopening existing classes using Class#class_eval For example, in order to override the engine model
**Adding** `Article#time_since_created`:
```ruby
# MyApp/app/overrides/models/blorgh/article_override.rb
Blorgh::Article.class_eval do
def time_since_created
Time.current - created_at
end
end
```
```ruby ```ruby
# Blorgh/app/models/blorgh/article.rb # Blorgh/app/models/blorgh/article.rb
module Blorgh module Blorgh
class Article < ApplicationRecord class Article < ApplicationRecord
has_many :comments has_many :comments
end
end
```
**Overriding** `Article#summary`:
```ruby
# MyApp/app/overrides/models/blorgh/article_override.rb
Blorgh::Article.class_eval do
def summary
"#{title} - #{truncate(text)}"
end
end
```
```ruby
# Blorgh/app/models/blorgh/article.rb
module Blorgh
class Article < ApplicationRecord
has_many :comments
def summary def summary
"#{title}" "#{title}"
end end
@ -1184,6 +1159,23 @@ module Blorgh
end end
``` ```
you just create a file that _reopens_ that class:
```ruby
# MyApp/app/overrides/models/blorgh/article_override.rb
Blorgh::Article.class_eval do
def time_since_created
Time.current - created_at
end
def summary
"#{title} - #{truncate(text)}"
end
end
```
It is very important that the override _reopens_ the class or module. Using the `class` or `module` keywords would define them if they were not already in memory, which would be incorrect because the definition lives in the engine. Using `class_eval` as shown above ensures you are reopening.
#### Reopening existing classes using ActiveSupport::Concern #### Reopening existing classes using ActiveSupport::Concern
Using `Class#class_eval` is great for simple adjustments, but for more complex Using `Class#class_eval` is great for simple adjustments, but for more complex