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:
parent
cb6f25c757
commit
b1d94dabc5
1 changed files with 42 additions and 50 deletions
|
@ -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
|
||||||
|
|
Loading…
Reference in a new issue