rails 4.2.7.1 → 6.1.2.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (218) hide show
  1. checksums.yaml +5 -5
  2. data/README.md +54 -36
  3. metadata +87 -249
  4. data/guides/CHANGELOG.md +0 -78
  5. data/guides/Rakefile +0 -79
  6. data/guides/assets/images/akshaysurve.jpg +0 -0
  7. data/guides/assets/images/belongs_to.png +0 -0
  8. data/guides/assets/images/book_icon.gif +0 -0
  9. data/guides/assets/images/bullet.gif +0 -0
  10. data/guides/assets/images/chapters_icon.gif +0 -0
  11. data/guides/assets/images/check_bullet.gif +0 -0
  12. data/guides/assets/images/credits_pic_blank.gif +0 -0
  13. data/guides/assets/images/csrf.png +0 -0
  14. data/guides/assets/images/edge_badge.png +0 -0
  15. data/guides/assets/images/favicon.ico +0 -0
  16. data/guides/assets/images/feature_tile.gif +0 -0
  17. data/guides/assets/images/footer_tile.gif +0 -0
  18. data/guides/assets/images/fxn.png +0 -0
  19. data/guides/assets/images/getting_started/article_with_comments.png +0 -0
  20. data/guides/assets/images/getting_started/challenge.png +0 -0
  21. data/guides/assets/images/getting_started/confirm_dialog.png +0 -0
  22. data/guides/assets/images/getting_started/forbidden_attributes_for_new_article.png +0 -0
  23. data/guides/assets/images/getting_started/form_with_errors.png +0 -0
  24. data/guides/assets/images/getting_started/index_action_with_edit_link.png +0 -0
  25. data/guides/assets/images/getting_started/new_article.png +0 -0
  26. data/guides/assets/images/getting_started/rails_welcome.png +0 -0
  27. data/guides/assets/images/getting_started/routing_error_no_controller.png +0 -0
  28. data/guides/assets/images/getting_started/routing_error_no_route_matches.png +0 -0
  29. data/guides/assets/images/getting_started/show_action_for_articles.png +0 -0
  30. data/guides/assets/images/getting_started/template_is_missing_articles_new.png +0 -0
  31. data/guides/assets/images/getting_started/unknown_action_create_for_articles.png +0 -0
  32. data/guides/assets/images/getting_started/unknown_action_new_for_articles.png +0 -0
  33. data/guides/assets/images/grey_bullet.gif +0 -0
  34. data/guides/assets/images/habtm.png +0 -0
  35. data/guides/assets/images/has_many.png +0 -0
  36. data/guides/assets/images/has_many_through.png +0 -0
  37. data/guides/assets/images/has_one.png +0 -0
  38. data/guides/assets/images/has_one_through.png +0 -0
  39. data/guides/assets/images/header_backdrop.png +0 -0
  40. data/guides/assets/images/header_tile.gif +0 -0
  41. data/guides/assets/images/i18n/demo_html_safe.png +0 -0
  42. data/guides/assets/images/i18n/demo_localized_pirate.png +0 -0
  43. data/guides/assets/images/i18n/demo_translated_en.png +0 -0
  44. data/guides/assets/images/i18n/demo_translated_pirate.png +0 -0
  45. data/guides/assets/images/i18n/demo_translation_missing.png +0 -0
  46. data/guides/assets/images/i18n/demo_untranslated.png +0 -0
  47. data/guides/assets/images/icons/README +0 -5
  48. data/guides/assets/images/icons/callouts/1.png +0 -0
  49. data/guides/assets/images/icons/callouts/10.png +0 -0
  50. data/guides/assets/images/icons/callouts/11.png +0 -0
  51. data/guides/assets/images/icons/callouts/12.png +0 -0
  52. data/guides/assets/images/icons/callouts/13.png +0 -0
  53. data/guides/assets/images/icons/callouts/14.png +0 -0
  54. data/guides/assets/images/icons/callouts/15.png +0 -0
  55. data/guides/assets/images/icons/callouts/2.png +0 -0
  56. data/guides/assets/images/icons/callouts/3.png +0 -0
  57. data/guides/assets/images/icons/callouts/4.png +0 -0
  58. data/guides/assets/images/icons/callouts/5.png +0 -0
  59. data/guides/assets/images/icons/callouts/6.png +0 -0
  60. data/guides/assets/images/icons/callouts/7.png +0 -0
  61. data/guides/assets/images/icons/callouts/8.png +0 -0
  62. data/guides/assets/images/icons/callouts/9.png +0 -0
  63. data/guides/assets/images/icons/caution.png +0 -0
  64. data/guides/assets/images/icons/example.png +0 -0
  65. data/guides/assets/images/icons/home.png +0 -0
  66. data/guides/assets/images/icons/important.png +0 -0
  67. data/guides/assets/images/icons/next.png +0 -0
  68. data/guides/assets/images/icons/note.png +0 -0
  69. data/guides/assets/images/icons/prev.png +0 -0
  70. data/guides/assets/images/icons/tip.png +0 -0
  71. data/guides/assets/images/icons/up.png +0 -0
  72. data/guides/assets/images/icons/warning.png +0 -0
  73. data/guides/assets/images/nav_arrow.gif +0 -0
  74. data/guides/assets/images/oscardelben.jpg +0 -0
  75. data/guides/assets/images/polymorphic.png +0 -0
  76. data/guides/assets/images/radar.png +0 -0
  77. data/guides/assets/images/rails4_features.png +0 -0
  78. data/guides/assets/images/rails_guides_kindle_cover.jpg +0 -0
  79. data/guides/assets/images/rails_guides_logo.gif +0 -0
  80. data/guides/assets/images/rails_logo_remix.gif +0 -0
  81. data/guides/assets/images/session_fixation.png +0 -0
  82. data/guides/assets/images/tab_grey.gif +0 -0
  83. data/guides/assets/images/tab_info.gif +0 -0
  84. data/guides/assets/images/tab_note.gif +0 -0
  85. data/guides/assets/images/tab_red.gif +0 -0
  86. data/guides/assets/images/tab_yellow.gif +0 -0
  87. data/guides/assets/images/tab_yellow.png +0 -0
  88. data/guides/assets/images/vijaydev.jpg +0 -0
  89. data/guides/assets/javascripts/guides.js +0 -59
  90. data/guides/assets/javascripts/jquery.min.js +0 -4
  91. data/guides/assets/javascripts/responsive-tables.js +0 -43
  92. data/guides/assets/javascripts/syntaxhighlighter/shBrushAS3.js +0 -59
  93. data/guides/assets/javascripts/syntaxhighlighter/shBrushAppleScript.js +0 -75
  94. data/guides/assets/javascripts/syntaxhighlighter/shBrushBash.js +0 -59
  95. data/guides/assets/javascripts/syntaxhighlighter/shBrushCSharp.js +0 -65
  96. data/guides/assets/javascripts/syntaxhighlighter/shBrushColdFusion.js +0 -100
  97. data/guides/assets/javascripts/syntaxhighlighter/shBrushCpp.js +0 -97
  98. data/guides/assets/javascripts/syntaxhighlighter/shBrushCss.js +0 -91
  99. data/guides/assets/javascripts/syntaxhighlighter/shBrushDelphi.js +0 -55
  100. data/guides/assets/javascripts/syntaxhighlighter/shBrushDiff.js +0 -41
  101. data/guides/assets/javascripts/syntaxhighlighter/shBrushErlang.js +0 -52
  102. data/guides/assets/javascripts/syntaxhighlighter/shBrushGroovy.js +0 -67
  103. data/guides/assets/javascripts/syntaxhighlighter/shBrushJScript.js +0 -52
  104. data/guides/assets/javascripts/syntaxhighlighter/shBrushJava.js +0 -57
  105. data/guides/assets/javascripts/syntaxhighlighter/shBrushJavaFX.js +0 -58
  106. data/guides/assets/javascripts/syntaxhighlighter/shBrushPerl.js +0 -72
  107. data/guides/assets/javascripts/syntaxhighlighter/shBrushPhp.js +0 -88
  108. data/guides/assets/javascripts/syntaxhighlighter/shBrushPlain.js +0 -33
  109. data/guides/assets/javascripts/syntaxhighlighter/shBrushPowerShell.js +0 -74
  110. data/guides/assets/javascripts/syntaxhighlighter/shBrushPython.js +0 -64
  111. data/guides/assets/javascripts/syntaxhighlighter/shBrushRuby.js +0 -55
  112. data/guides/assets/javascripts/syntaxhighlighter/shBrushSass.js +0 -94
  113. data/guides/assets/javascripts/syntaxhighlighter/shBrushScala.js +0 -51
  114. data/guides/assets/javascripts/syntaxhighlighter/shBrushSql.js +0 -66
  115. data/guides/assets/javascripts/syntaxhighlighter/shBrushVb.js +0 -56
  116. data/guides/assets/javascripts/syntaxhighlighter/shBrushXml.js +0 -69
  117. data/guides/assets/javascripts/syntaxhighlighter/shCore.js +0 -17
  118. data/guides/assets/stylesheets/fixes.css +0 -16
  119. data/guides/assets/stylesheets/kindle.css +0 -11
  120. data/guides/assets/stylesheets/main.css +0 -713
  121. data/guides/assets/stylesheets/print.css +0 -52
  122. data/guides/assets/stylesheets/reset.css +0 -43
  123. data/guides/assets/stylesheets/responsive-tables.css +0 -50
  124. data/guides/assets/stylesheets/style.css +0 -13
  125. data/guides/assets/stylesheets/syntaxhighlighter/shCore.css +0 -226
  126. data/guides/assets/stylesheets/syntaxhighlighter/shCoreDefault.css +0 -328
  127. data/guides/assets/stylesheets/syntaxhighlighter/shCoreDjango.css +0 -331
  128. data/guides/assets/stylesheets/syntaxhighlighter/shCoreEclipse.css +0 -339
  129. data/guides/assets/stylesheets/syntaxhighlighter/shCoreEmacs.css +0 -324
  130. data/guides/assets/stylesheets/syntaxhighlighter/shCoreFadeToGrey.css +0 -328
  131. data/guides/assets/stylesheets/syntaxhighlighter/shCoreMDUltra.css +0 -324
  132. data/guides/assets/stylesheets/syntaxhighlighter/shCoreMidnight.css +0 -324
  133. data/guides/assets/stylesheets/syntaxhighlighter/shCoreRDark.css +0 -324
  134. data/guides/assets/stylesheets/syntaxhighlighter/shThemeDefault.css +0 -117
  135. data/guides/assets/stylesheets/syntaxhighlighter/shThemeDjango.css +0 -120
  136. data/guides/assets/stylesheets/syntaxhighlighter/shThemeEclipse.css +0 -128
  137. data/guides/assets/stylesheets/syntaxhighlighter/shThemeEmacs.css +0 -113
  138. data/guides/assets/stylesheets/syntaxhighlighter/shThemeFadeToGrey.css +0 -117
  139. data/guides/assets/stylesheets/syntaxhighlighter/shThemeMDUltra.css +0 -113
  140. data/guides/assets/stylesheets/syntaxhighlighter/shThemeMidnight.css +0 -113
  141. data/guides/assets/stylesheets/syntaxhighlighter/shThemeRDark.css +0 -113
  142. data/guides/assets/stylesheets/syntaxhighlighter/shThemeRailsGuides.css +0 -116
  143. data/guides/bug_report_templates/action_controller_gem.rb +0 -47
  144. data/guides/bug_report_templates/action_controller_master.rb +0 -54
  145. data/guides/bug_report_templates/active_record_gem.rb +0 -40
  146. data/guides/bug_report_templates/active_record_master.rb +0 -49
  147. data/guides/bug_report_templates/generic_gem.rb +0 -15
  148. data/guides/bug_report_templates/generic_master.rb +0 -26
  149. data/guides/rails_guides.rb +0 -63
  150. data/guides/rails_guides/generator.rb +0 -248
  151. data/guides/rails_guides/helpers.rb +0 -53
  152. data/guides/rails_guides/indexer.rb +0 -68
  153. data/guides/rails_guides/kindle.rb +0 -119
  154. data/guides/rails_guides/levenshtein.rb +0 -37
  155. data/guides/rails_guides/markdown.rb +0 -167
  156. data/guides/rails_guides/markdown/renderer.rb +0 -82
  157. data/guides/source/2_2_release_notes.md +0 -435
  158. data/guides/source/2_3_release_notes.md +0 -621
  159. data/guides/source/3_0_release_notes.md +0 -611
  160. data/guides/source/3_1_release_notes.md +0 -559
  161. data/guides/source/3_2_release_notes.md +0 -568
  162. data/guides/source/4_0_release_notes.md +0 -279
  163. data/guides/source/4_1_release_notes.md +0 -730
  164. data/guides/source/4_2_release_notes.md +0 -877
  165. data/guides/source/_license.html.erb +0 -2
  166. data/guides/source/_welcome.html.erb +0 -23
  167. data/guides/source/action_controller_overview.md +0 -1192
  168. data/guides/source/action_mailer_basics.md +0 -757
  169. data/guides/source/action_view_overview.md +0 -1561
  170. data/guides/source/active_job_basics.md +0 -339
  171. data/guides/source/active_model_basics.md +0 -554
  172. data/guides/source/active_record_basics.md +0 -374
  173. data/guides/source/active_record_callbacks.md +0 -413
  174. data/guides/source/active_record_migrations.md +0 -1018
  175. data/guides/source/active_record_postgresql.md +0 -433
  176. data/guides/source/active_record_querying.md +0 -1781
  177. data/guides/source/active_record_validations.md +0 -1179
  178. data/guides/source/active_support_core_extensions.md +0 -3857
  179. data/guides/source/active_support_instrumentation.md +0 -488
  180. data/guides/source/api_documentation_guidelines.md +0 -361
  181. data/guides/source/asset_pipeline.md +0 -1304
  182. data/guides/source/association_basics.md +0 -2245
  183. data/guides/source/autoloading_and_reloading_constants.md +0 -1311
  184. data/guides/source/caching_with_rails.md +0 -379
  185. data/guides/source/command_line.md +0 -625
  186. data/guides/source/configuring.md +0 -1072
  187. data/guides/source/contributing_to_ruby_on_rails.md +0 -628
  188. data/guides/source/credits.html.erb +0 -80
  189. data/guides/source/debugging_rails_applications.md +0 -861
  190. data/guides/source/development_dependencies_install.md +0 -289
  191. data/guides/source/documents.yaml +0 -205
  192. data/guides/source/engines.md +0 -1412
  193. data/guides/source/form_helpers.md +0 -1024
  194. data/guides/source/generators.md +0 -676
  195. data/guides/source/getting_started.md +0 -2086
  196. data/guides/source/i18n.md +0 -1087
  197. data/guides/source/index.html.erb +0 -28
  198. data/guides/source/initialization.md +0 -704
  199. data/guides/source/kindle/copyright.html.erb +0 -1
  200. data/guides/source/kindle/layout.html.erb +0 -27
  201. data/guides/source/kindle/rails_guides.opf.erb +0 -52
  202. data/guides/source/kindle/toc.html.erb +0 -24
  203. data/guides/source/kindle/toc.ncx.erb +0 -64
  204. data/guides/source/kindle/welcome.html.erb +0 -5
  205. data/guides/source/layout.html.erb +0 -140
  206. data/guides/source/layouts_and_rendering.md +0 -1226
  207. data/guides/source/maintenance_policy.md +0 -78
  208. data/guides/source/nested_model_forms.md +0 -228
  209. data/guides/source/plugins.md +0 -444
  210. data/guides/source/rails_application_templates.md +0 -266
  211. data/guides/source/rails_on_rack.md +0 -336
  212. data/guides/source/routing.md +0 -1155
  213. data/guides/source/ruby_on_rails_guides_guidelines.md +0 -127
  214. data/guides/source/security.md +0 -1024
  215. data/guides/source/testing.md +0 -1132
  216. data/guides/source/upgrading_ruby_on_rails.md +0 -1186
  217. data/guides/source/working_with_javascript_in_rails.md +0 -407
  218. data/guides/w3c_validator.rb +0 -97
@@ -1,1412 +0,0 @@
1
- Getting Started with Engines
2
- ============================
3
-
4
- In this guide you will learn about engines and how they can be used to provide
5
- additional functionality to their host applications through a clean and very
6
- easy-to-use interface.
7
-
8
- After reading this guide, you will know:
9
-
10
- * What makes an engine.
11
- * How to generate an engine.
12
- * Building features for the engine.
13
- * Hooking the engine into an application.
14
- * Overriding engine functionality in the application.
15
-
16
- --------------------------------------------------------------------------------
17
-
18
- What are engines?
19
- -----------------
20
-
21
- Engines can be considered miniature applications that provide functionality to
22
- their host applications. A Rails application is actually just a "supercharged"
23
- engine, with the `Rails::Application` class inheriting a lot of its behavior
24
- from `Rails::Engine`.
25
-
26
- Therefore, engines and applications can be thought of almost the same thing,
27
- just with subtle differences, as you'll see throughout this guide. Engines and
28
- applications also share a common structure.
29
-
30
- Engines are also closely related to plugins. The two share a common `lib`
31
- directory structure, and are both generated using the `rails plugin new`
32
- generator. The difference is that an engine is considered a "full plugin" by
33
- Rails (as indicated by the `--full` option that's passed to the generator
34
- command). We'll actually be using the `--mountable` option here, which includes
35
- all the features of `--full`, and then some. This guide will refer to these
36
- "full plugins" simply as "engines" throughout. An engine **can** be a plugin,
37
- and a plugin **can** be an engine.
38
-
39
- The engine that will be created in this guide will be called "blorgh". This
40
- engine will provide blogging functionality to its host applications, allowing
41
- for new articles and comments to be created. At the beginning of this guide, you
42
- will be working solely within the engine itself, but in later sections you'll
43
- see how to hook it into an application.
44
-
45
- Engines can also be isolated from their host applications. This means that an
46
- application is able to have a path provided by a routing helper such as
47
- `articles_path` and use an engine also that provides a path also called
48
- `articles_path`, and the two would not clash. Along with this, controllers, models
49
- and table names are also namespaced. You'll see how to do this later in this
50
- guide.
51
-
52
- It's important to keep in mind at all times that the application should
53
- **always** take precedence over its engines. An application is the object that
54
- has final say in what goes on in its environment. The engine should
55
- only be enhancing it, rather than changing it drastically.
56
-
57
- To see demonstrations of other engines, check out
58
- [Devise](https://github.com/plataformatec/devise), an engine that provides
59
- authentication for its parent applications, or
60
- [Forem](https://github.com/radar/forem), an engine that provides forum
61
- functionality. There's also [Spree](https://github.com/spree/spree) which
62
- provides an e-commerce platform, and
63
- [RefineryCMS](https://github.com/refinery/refinerycms), a CMS engine.
64
-
65
- Finally, engines would not have been possible without the work of James Adam,
66
- Piotr Sarnacki, the Rails Core Team, and a number of other people. If you ever
67
- meet them, don't forget to say thanks!
68
-
69
- Generating an engine
70
- --------------------
71
-
72
- To generate an engine, you will need to run the plugin generator and pass it
73
- options as appropriate to the need. For the "blorgh" example, you will need to
74
- create a "mountable" engine, running this command in a terminal:
75
-
76
- ```bash
77
- $ rails plugin new blorgh --mountable
78
- ```
79
-
80
- The full list of options for the plugin generator may be seen by typing:
81
-
82
- ```bash
83
- $ rails plugin --help
84
- ```
85
-
86
- The `--mountable` option tells the generator that you want to create a
87
- "mountable" and namespace-isolated engine. This generator will provide the same
88
- skeleton structure as would the `--full` option. The `--full` option tells the
89
- generator that you want to create an engine, including a skeleton structure
90
- that provides the following:
91
-
92
- * An `app` directory tree
93
- * A `config/routes.rb` file:
94
-
95
- ```ruby
96
- Rails.application.routes.draw do
97
- end
98
- ```
99
-
100
- * A file at `lib/blorgh/engine.rb`, which is identical in function to a
101
- standard Rails application's `config/application.rb` file:
102
-
103
- ```ruby
104
- module Blorgh
105
- class Engine < ::Rails::Engine
106
- end
107
- end
108
- ```
109
-
110
- The `--mountable` option will add to the `--full` option:
111
-
112
- * Asset manifest files (`application.js` and `application.css`)
113
- * A namespaced `ApplicationController` stub
114
- * A namespaced `ApplicationHelper` stub
115
- * A layout view template for the engine
116
- * Namespace isolation to `config/routes.rb`:
117
-
118
- ```ruby
119
- Blorgh::Engine.routes.draw do
120
- end
121
- ```
122
-
123
- * Namespace isolation to `lib/blorgh/engine.rb`:
124
-
125
- ```ruby
126
- module Blorgh
127
- class Engine < ::Rails::Engine
128
- isolate_namespace Blorgh
129
- end
130
- end
131
- ```
132
-
133
- Additionally, the `--mountable` option tells the generator to mount the engine
134
- inside the dummy testing application located at `test/dummy` by adding the
135
- following to the dummy application's routes file at
136
- `test/dummy/config/routes.rb`:
137
-
138
- ```ruby
139
- mount Blorgh::Engine => "/blorgh"
140
- ```
141
-
142
- ### Inside an Engine
143
-
144
- #### Critical Files
145
-
146
- At the root of this brand new engine's directory lives a `blorgh.gemspec` file.
147
- When you include the engine into an application later on, you will do so with
148
- this line in the Rails application's `Gemfile`:
149
-
150
- ```ruby
151
- gem 'blorgh', path: "vendor/engines/blorgh"
152
- ```
153
-
154
- Don't forget to run `bundle install` as usual. By specifying it as a gem within
155
- the `Gemfile`, Bundler will load it as such, parsing this `blorgh.gemspec` file
156
- and requiring a file within the `lib` directory called `lib/blorgh.rb`. This
157
- file requires the `blorgh/engine.rb` file (located at `lib/blorgh/engine.rb`)
158
- and defines a base module called `Blorgh`.
159
-
160
- ```ruby
161
- require "blorgh/engine"
162
-
163
- module Blorgh
164
- end
165
- ```
166
-
167
- TIP: Some engines choose to use this file to put global configuration options
168
- for their engine. It's a relatively good idea, so if you want to offer
169
- configuration options, the file where your engine's `module` is defined is
170
- perfect for that. Place the methods inside the module and you'll be good to go.
171
-
172
- Within `lib/blorgh/engine.rb` is the base class for the engine:
173
-
174
- ```ruby
175
- module Blorgh
176
- class Engine < ::Rails::Engine
177
- isolate_namespace Blorgh
178
- end
179
- end
180
- ```
181
-
182
- By inheriting from the `Rails::Engine` class, this gem notifies Rails that
183
- there's an engine at the specified path, and will correctly mount the engine
184
- inside the application, performing tasks such as adding the `app` directory of
185
- the engine to the load path for models, mailers, controllers and views.
186
-
187
- The `isolate_namespace` method here deserves special notice. This call is
188
- responsible for isolating the controllers, models, routes and other things into
189
- their own namespace, away from similar components inside the application.
190
- Without this, there is a possibility that the engine's components could "leak"
191
- into the application, causing unwanted disruption, or that important engine
192
- components could be overridden by similarly named things within the application.
193
- One of the examples of such conflicts is helpers. Without calling
194
- `isolate_namespace`, the engine's helpers would be included in an application's
195
- controllers.
196
-
197
- NOTE: It is **highly** recommended that the `isolate_namespace` line be left
198
- within the `Engine` class definition. Without it, classes generated in an engine
199
- **may** conflict with an application.
200
-
201
- What this isolation of the namespace means is that a model generated by a call
202
- to `bin/rails g model`, such as `bin/rails g model article`, won't be called `Article`, but
203
- instead be namespaced and called `Blorgh::Article`. In addition, the table for the
204
- model is namespaced, becoming `blorgh_articles`, rather than simply `articles`.
205
- Similar to the model namespacing, a controller called `ArticlesController` becomes
206
- `Blorgh::ArticlesController` and the views for that controller will not be at
207
- `app/views/articles`, but `app/views/blorgh/articles` instead. Mailers are namespaced
208
- as well.
209
-
210
- Finally, routes will also be isolated within the engine. This is one of the most
211
- important parts about namespacing, and is discussed later in the
212
- [Routes](#routes) section of this guide.
213
-
214
- #### `app` Directory
215
-
216
- Inside the `app` directory are the standard `assets`, `controllers`, `helpers`,
217
- `mailers`, `models` and `views` directories that you should be familiar with
218
- from an application. The `helpers`, `mailers` and `models` directories are
219
- empty, so they aren't described in this section. We'll look more into models in
220
- a future section, when we're writing the engine.
221
-
222
- Within the `app/assets` directory, there are the `images`, `javascripts` and
223
- `stylesheets` directories which, again, you should be familiar with due to their
224
- similarity to an application. One difference here, however, is that each
225
- directory contains a sub-directory with the engine name. Because this engine is
226
- going to be namespaced, its assets should be too.
227
-
228
- Within the `app/controllers` directory there is a `blorgh` directory that
229
- contains a file called `application_controller.rb`. This file will provide any
230
- common functionality for the controllers of the engine. The `blorgh` directory
231
- is where the other controllers for the engine will go. By placing them within
232
- this namespaced directory, you prevent them from possibly clashing with
233
- identically-named controllers within other engines or even within the
234
- application.
235
-
236
- NOTE: The `ApplicationController` class inside an engine is named just like a
237
- Rails application in order to make it easier for you to convert your
238
- applications into engines.
239
-
240
- Lastly, the `app/views` directory contains a `layouts` folder, which contains a
241
- file at `blorgh/application.html.erb`. This file allows you to specify a layout
242
- for the engine. If this engine is to be used as a stand-alone engine, then you
243
- would add any customization to its layout in this file, rather than the
244
- application's `app/views/layouts/application.html.erb` file.
245
-
246
- If you don't want to force a layout on to users of the engine, then you can
247
- delete this file and reference a different layout in the controllers of your
248
- engine.
249
-
250
- #### `bin` Directory
251
-
252
- This directory contains one file, `bin/rails`, which enables you to use the
253
- `rails` sub-commands and generators just like you would within an application.
254
- This means that you will be able to generate new controllers and models for this
255
- engine very easily by running commands like this:
256
-
257
- ```bash
258
- $ bin/rails g model
259
- ```
260
-
261
- Keep in mind, of course, that anything generated with these commands inside of
262
- an engine that has `isolate_namespace` in the `Engine` class will be namespaced.
263
-
264
- #### `test` Directory
265
-
266
- The `test` directory is where tests for the engine will go. To test the engine,
267
- there is a cut-down version of a Rails application embedded within it at
268
- `test/dummy`. This application will mount the engine in the
269
- `test/dummy/config/routes.rb` file:
270
-
271
- ```ruby
272
- Rails.application.routes.draw do
273
- mount Blorgh::Engine => "/blorgh"
274
- end
275
- ```
276
-
277
- This line mounts the engine at the path `/blorgh`, which will make it accessible
278
- through the application only at that path.
279
-
280
- Inside the test directory there is the `test/integration` directory, where
281
- integration tests for the engine should be placed. Other directories can be
282
- created in the `test` directory as well. For example, you may wish to create a
283
- `test/models` directory for your model tests.
284
-
285
- Providing engine functionality
286
- ------------------------------
287
-
288
- The engine that this guide covers provides submitting articles and commenting
289
- functionality and follows a similar thread to the [Getting Started
290
- Guide](getting_started.html), with some new twists.
291
-
292
- ### Generating an Article Resource
293
-
294
- The first thing to generate for a blog engine is the `Article` model and related
295
- controller. To quickly generate this, you can use the Rails scaffold generator.
296
-
297
- ```bash
298
- $ bin/rails generate scaffold article title:string text:text
299
- ```
300
-
301
- This command will output this information:
302
-
303
- ```
304
- invoke active_record
305
- create db/migrate/[timestamp]_create_blorgh_articles.rb
306
- create app/models/blorgh/article.rb
307
- invoke test_unit
308
- create test/models/blorgh/article_test.rb
309
- create test/fixtures/blorgh/articles.yml
310
- invoke resource_route
311
- route resources :articles
312
- invoke scaffold_controller
313
- create app/controllers/blorgh/articles_controller.rb
314
- invoke erb
315
- create app/views/blorgh/articles
316
- create app/views/blorgh/articles/index.html.erb
317
- create app/views/blorgh/articles/edit.html.erb
318
- create app/views/blorgh/articles/show.html.erb
319
- create app/views/blorgh/articles/new.html.erb
320
- create app/views/blorgh/articles/_form.html.erb
321
- invoke test_unit
322
- create test/controllers/blorgh/articles_controller_test.rb
323
- invoke helper
324
- create app/helpers/blorgh/articles_helper.rb
325
- invoke assets
326
- invoke js
327
- create app/assets/javascripts/blorgh/articles.js
328
- invoke css
329
- create app/assets/stylesheets/blorgh/articles.css
330
- invoke css
331
- create app/assets/stylesheets/scaffold.css
332
- ```
333
-
334
- The first thing that the scaffold generator does is invoke the `active_record`
335
- generator, which generates a migration and a model for the resource. Note here,
336
- however, that the migration is called `create_blorgh_articles` rather than the
337
- usual `create_articles`. This is due to the `isolate_namespace` method called in
338
- the `Blorgh::Engine` class's definition. The model here is also namespaced,
339
- being placed at `app/models/blorgh/article.rb` rather than `app/models/article.rb` due
340
- to the `isolate_namespace` call within the `Engine` class.
341
-
342
- Next, the `test_unit` generator is invoked for this model, generating a model
343
- test at `test/models/blorgh/article_test.rb` (rather than
344
- `test/models/article_test.rb`) and a fixture at `test/fixtures/blorgh/articles.yml`
345
- (rather than `test/fixtures/articles.yml`).
346
-
347
- After that, a line for the resource is inserted into the `config/routes.rb` file
348
- for the engine. This line is simply `resources :articles`, turning the
349
- `config/routes.rb` file for the engine into this:
350
-
351
- ```ruby
352
- Blorgh::Engine.routes.draw do
353
- resources :articles
354
- end
355
- ```
356
-
357
- Note here that the routes are drawn upon the `Blorgh::Engine` object rather than
358
- the `YourApp::Application` class. This is so that the engine routes are confined
359
- to the engine itself and can be mounted at a specific point as shown in the
360
- [test directory](#test-directory) section. It also causes the engine's routes to
361
- be isolated from those routes that are within the application. The
362
- [Routes](#routes) section of this guide describes it in detail.
363
-
364
- Next, the `scaffold_controller` generator is invoked, generating a controller
365
- called `Blorgh::ArticlesController` (at
366
- `app/controllers/blorgh/articles_controller.rb`) and its related views at
367
- `app/views/blorgh/articles`. This generator also generates a test for the
368
- controller (`test/controllers/blorgh/articles_controller_test.rb`) and a helper
369
- (`app/helpers/blorgh/articles_controller.rb`).
370
-
371
- Everything this generator has created is neatly namespaced. The controller's
372
- class is defined within the `Blorgh` module:
373
-
374
- ```ruby
375
- module Blorgh
376
- class ArticlesController < ApplicationController
377
- ...
378
- end
379
- end
380
- ```
381
-
382
- NOTE: The `ApplicationController` class being inherited from here is the
383
- `Blorgh::ApplicationController`, not an application's `ApplicationController`.
384
-
385
- The helper inside `app/helpers/blorgh/articles_helper.rb` is also namespaced:
386
-
387
- ```ruby
388
- module Blorgh
389
- module ArticlesHelper
390
- ...
391
- end
392
- end
393
- ```
394
-
395
- This helps prevent conflicts with any other engine or application that may have
396
- an article resource as well.
397
-
398
- Finally, the assets for this resource are generated in two files:
399
- `app/assets/javascripts/blorgh/articles.js` and
400
- `app/assets/stylesheets/blorgh/articles.css`. You'll see how to use these a little
401
- later.
402
-
403
- By default, the scaffold styling is not applied to the engine because the
404
- engine's layout file, `app/views/layouts/blorgh/application.html.erb`, doesn't
405
- load it. To make the scaffold styling apply, insert this line into the `<head>`
406
- tag of this layout:
407
-
408
- ```erb
409
- <%= stylesheet_link_tag "scaffold" %>
410
- ```
411
-
412
- You can see what the engine has so far by running `rake db:migrate` at the root
413
- of our engine to run the migration generated by the scaffold generator, and then
414
- running `rails server` in `test/dummy`. When you open
415
- `http://localhost:3000/blorgh/articles` you will see the default scaffold that has
416
- been generated. Click around! You've just generated your first engine's first
417
- functions.
418
-
419
- If you'd rather play around in the console, `rails console` will also work just
420
- like a Rails application. Remember: the `Article` model is namespaced, so to
421
- reference it you must call it as `Blorgh::Article`.
422
-
423
- ```ruby
424
- >> Blorgh::Article.find(1)
425
- => #<Blorgh::Article id: 1 ...>
426
- ```
427
-
428
- One final thing is that the `articles` resource for this engine should be the root
429
- of the engine. Whenever someone goes to the root path where the engine is
430
- mounted, they should be shown a list of articles. This can be made to happen if
431
- this line is inserted into the `config/routes.rb` file inside the engine:
432
-
433
- ```ruby
434
- root to: "articles#index"
435
- ```
436
-
437
- Now people will only need to go to the root of the engine to see all the articles,
438
- rather than visiting `/articles`. This means that instead of
439
- `http://localhost:3000/blorgh/articles`, you only need to go to
440
- `http://localhost:3000/blorgh` now.
441
-
442
- ### Generating a Comments Resource
443
-
444
- Now that the engine can create new articles, it only makes sense to add
445
- commenting functionality as well. To do this, you'll need to generate a comment
446
- model, a comment controller and then modify the articles scaffold to display
447
- comments and allow people to create new ones.
448
-
449
- From the application root, run the model generator. Tell it to generate a
450
- `Comment` model, with the related table having two columns: a `article_id` integer
451
- and `text` text column.
452
-
453
- ```bash
454
- $ bin/rails generate model Comment article_id:integer text:text
455
- ```
456
-
457
- This will output the following:
458
-
459
- ```
460
- invoke active_record
461
- create db/migrate/[timestamp]_create_blorgh_comments.rb
462
- create app/models/blorgh/comment.rb
463
- invoke test_unit
464
- create test/models/blorgh/comment_test.rb
465
- create test/fixtures/blorgh/comments.yml
466
- ```
467
-
468
- This generator call will generate just the necessary model files it needs,
469
- namespacing the files under a `blorgh` directory and creating a model class
470
- called `Blorgh::Comment`. Now run the migration to create our blorgh_comments
471
- table:
472
-
473
- ```bash
474
- $ rake db:migrate
475
- ```
476
-
477
- To show the comments on an article, edit `app/views/blorgh/articles/show.html.erb` and
478
- add this line before the "Edit" link:
479
-
480
- ```html+erb
481
- <h3>Comments</h3>
482
- <%= render @article.comments %>
483
- ```
484
-
485
- This line will require there to be a `has_many` association for comments defined
486
- on the `Blorgh::Article` model, which there isn't right now. To define one, open
487
- `app/models/blorgh/article.rb` and add this line into the model:
488
-
489
- ```ruby
490
- has_many :comments
491
- ```
492
-
493
- Turning the model into this:
494
-
495
- ```ruby
496
- module Blorgh
497
- class Article < ActiveRecord::Base
498
- has_many :comments
499
- end
500
- end
501
- ```
502
-
503
- NOTE: Because the `has_many` is defined inside a class that is inside the
504
- `Blorgh` module, Rails will know that you want to use the `Blorgh::Comment`
505
- model for these objects, so there's no need to specify that using the
506
- `:class_name` option here.
507
-
508
- Next, there needs to be a form so that comments can be created on an article. To
509
- add this, put this line underneath the call to `render @article.comments` in
510
- `app/views/blorgh/articles/show.html.erb`:
511
-
512
- ```erb
513
- <%= render "blorgh/comments/form" %>
514
- ```
515
-
516
- Next, the partial that this line will render needs to exist. Create a new
517
- directory at `app/views/blorgh/comments` and in it a new file called
518
- `_form.html.erb` which has this content to create the required partial:
519
-
520
- ```html+erb
521
- <h3>New comment</h3>
522
- <%= form_for [@article, @article.comments.build] do |f| %>
523
- <p>
524
- <%= f.label :text %><br>
525
- <%= f.text_area :text %>
526
- </p>
527
- <%= f.submit %>
528
- <% end %>
529
- ```
530
-
531
- When this form is submitted, it is going to attempt to perform a `POST` request
532
- to a route of `/articles/:article_id/comments` within the engine. This route doesn't
533
- exist at the moment, but can be created by changing the `resources :articles` line
534
- inside `config/routes.rb` into these lines:
535
-
536
- ```ruby
537
- resources :articles do
538
- resources :comments
539
- end
540
- ```
541
-
542
- This creates a nested route for the comments, which is what the form requires.
543
-
544
- The route now exists, but the controller that this route goes to does not. To
545
- create it, run this command from the application root:
546
-
547
- ```bash
548
- $ bin/rails g controller comments
549
- ```
550
-
551
- This will generate the following things:
552
-
553
- ```
554
- create app/controllers/blorgh/comments_controller.rb
555
- invoke erb
556
- exist app/views/blorgh/comments
557
- invoke test_unit
558
- create test/controllers/blorgh/comments_controller_test.rb
559
- invoke helper
560
- create app/helpers/blorgh/comments_helper.rb
561
- invoke assets
562
- invoke js
563
- create app/assets/javascripts/blorgh/comments.js
564
- invoke css
565
- create app/assets/stylesheets/blorgh/comments.css
566
- ```
567
-
568
- The form will be making a `POST` request to `/articles/:article_id/comments`, which
569
- will correspond with the `create` action in `Blorgh::CommentsController`. This
570
- action needs to be created, which can be done by putting the following lines
571
- inside the class definition in `app/controllers/blorgh/comments_controller.rb`:
572
-
573
- ```ruby
574
- def create
575
- @article = Article.find(params[:article_id])
576
- @comment = @article.comments.create(comment_params)
577
- flash[:notice] = "Comment has been created!"
578
- redirect_to articles_path
579
- end
580
-
581
- private
582
- def comment_params
583
- params.require(:comment).permit(:text)
584
- end
585
- ```
586
-
587
- This is the final step required to get the new comment form working. Displaying
588
- the comments, however, is not quite right yet. If you were to create a comment
589
- right now, you would see this error:
590
-
591
- ```
592
- Missing partial blorgh/comments/_comment with {:handlers=>[:erb, :builder],
593
- :formats=>[:html], :locale=>[:en, :en]}. Searched in: *
594
- "/Users/ryan/Sites/side_projects/blorgh/test/dummy/app/views" *
595
- "/Users/ryan/Sites/side_projects/blorgh/app/views"
596
- ```
597
-
598
- The engine is unable to find the partial required for rendering the comments.
599
- Rails looks first in the application's (`test/dummy`) `app/views` directory and
600
- then in the engine's `app/views` directory. When it can't find it, it will throw
601
- this error. The engine knows to look for `blorgh/comments/_comment` because the
602
- model object it is receiving is from the `Blorgh::Comment` class.
603
-
604
- This partial will be responsible for rendering just the comment text, for now.
605
- Create a new file at `app/views/blorgh/comments/_comment.html.erb` and put this
606
- line inside it:
607
-
608
- ```erb
609
- <%= comment_counter + 1 %>. <%= comment.text %>
610
- ```
611
-
612
- The `comment_counter` local variable is given to us by the `<%= render
613
- @article.comments %>` call, which will define it automatically and increment the
614
- counter as it iterates through each comment. It's used in this example to
615
- display a small number next to each comment when it's created.
616
-
617
- That completes the comment function of the blogging engine. Now it's time to use
618
- it within an application.
619
-
620
- Hooking Into an Application
621
- ---------------------------
622
-
623
- Using an engine within an application is very easy. This section covers how to
624
- mount the engine into an application and the initial setup required, as well as
625
- linking the engine to a `User` class provided by the application to provide
626
- ownership for articles and comments within the engine.
627
-
628
- ### Mounting the Engine
629
-
630
- First, the engine needs to be specified inside the application's `Gemfile`. If
631
- there isn't an application handy to test this out in, generate one using the
632
- `rails new` command outside of the engine directory like this:
633
-
634
- ```bash
635
- $ rails new unicorn
636
- ```
637
-
638
- Usually, specifying the engine inside the Gemfile would be done by specifying it
639
- as a normal, everyday gem.
640
-
641
- ```ruby
642
- gem 'devise'
643
- ```
644
-
645
- However, because you are developing the `blorgh` engine on your local machine,
646
- you will need to specify the `:path` option in your `Gemfile`:
647
-
648
- ```ruby
649
- gem 'blorgh', path: "/path/to/blorgh"
650
- ```
651
-
652
- Then run `bundle` to install the gem.
653
-
654
- As described earlier, by placing the gem in the `Gemfile` it will be loaded when
655
- Rails is loaded. It will first require `lib/blorgh.rb` from the engine, then
656
- `lib/blorgh/engine.rb`, which is the file that defines the major pieces of
657
- functionality for the engine.
658
-
659
- To make the engine's functionality accessible from within an application, it
660
- needs to be mounted in that application's `config/routes.rb` file:
661
-
662
- ```ruby
663
- mount Blorgh::Engine, at: "/blog"
664
- ```
665
-
666
- This line will mount the engine at `/blog` in the application. Making it
667
- accessible at `http://localhost:3000/blog` when the application runs with `rails
668
- server`.
669
-
670
- NOTE: Other engines, such as Devise, handle this a little differently by making
671
- you specify custom helpers (such as `devise_for`) in the routes. These helpers
672
- do exactly the same thing, mounting pieces of the engines's functionality at a
673
- pre-defined path which may be customizable.
674
-
675
- ### Engine setup
676
-
677
- The engine contains migrations for the `blorgh_articles` and `blorgh_comments`
678
- table which need to be created in the application's database so that the
679
- engine's models can query them correctly. To copy these migrations into the
680
- application use this command:
681
-
682
- ```bash
683
- $ rake blorgh:install:migrations
684
- ```
685
-
686
- If you have multiple engines that need migrations copied over, use
687
- `railties:install:migrations` instead:
688
-
689
- ```bash
690
- $ rake railties:install:migrations
691
- ```
692
-
693
- This command, when run for the first time, will copy over all the migrations
694
- from the engine. When run the next time, it will only copy over migrations that
695
- haven't been copied over already. The first run for this command will output
696
- something such as this:
697
-
698
- ```bash
699
- Copied migration [timestamp_1]_create_blorgh_articles.blorgh.rb from blorgh
700
- Copied migration [timestamp_2]_create_blorgh_comments.blorgh.rb from blorgh
701
- ```
702
-
703
- The first timestamp (`[timestamp_1]`) will be the current time, and the second
704
- timestamp (`[timestamp_2]`) will be the current time plus a second. The reason
705
- for this is so that the migrations for the engine are run after any existing
706
- migrations in the application.
707
-
708
- To run these migrations within the context of the application, simply run `rake
709
- db:migrate`. When accessing the engine through `http://localhost:3000/blog`, the
710
- articles will be empty. This is because the table created inside the application is
711
- different from the one created within the engine. Go ahead, play around with the
712
- newly mounted engine. You'll find that it's the same as when it was only an
713
- engine.
714
-
715
- If you would like to run migrations only from one engine, you can do it by
716
- specifying `SCOPE`:
717
-
718
- ```bash
719
- rake db:migrate SCOPE=blorgh
720
- ```
721
-
722
- This may be useful if you want to revert engine's migrations before removing it.
723
- To revert all migrations from blorgh engine you can run code such as:
724
-
725
- ```bash
726
- rake db:migrate SCOPE=blorgh VERSION=0
727
- ```
728
-
729
- ### Using a Class Provided by the Application
730
-
731
- #### Using a Model Provided by the Application
732
-
733
- When an engine is created, it may want to use specific classes from an
734
- application to provide links between the pieces of the engine and the pieces of
735
- the application. In the case of the `blorgh` engine, making articles and comments
736
- have authors would make a lot of sense.
737
-
738
- A typical application might have a `User` class that would be used to represent
739
- authors for an article or a comment. But there could be a case where the
740
- application calls this class something different, such as `Person`. For this
741
- reason, the engine should not hardcode associations specifically for a `User`
742
- class.
743
-
744
- To keep it simple in this case, the application will have a class called `User`
745
- that represents the users of the application (we'll get into making this
746
- configurable further on). It can be generated using this command inside the
747
- application:
748
-
749
- ```bash
750
- rails g model user name:string
751
- ```
752
-
753
- The `rake db:migrate` command needs to be run here to ensure that our
754
- application has the `users` table for future use.
755
-
756
- Also, to keep it simple, the articles form will have a new text field called
757
- `author_name`, where users can elect to put their name. The engine will then
758
- take this name and either create a new `User` object from it, or find one that
759
- already has that name. The engine will then associate the article with the found or
760
- created `User` object.
761
-
762
- First, the `author_name` text field needs to be added to the
763
- `app/views/blorgh/articles/_form.html.erb` partial inside the engine. This can be
764
- added above the `title` field with this code:
765
-
766
- ```html+erb
767
- <div class="field">
768
- <%= f.label :author_name %><br>
769
- <%= f.text_field :author_name %>
770
- </div>
771
- ```
772
-
773
- Next, we need to update our `Blorgh::ArticleController#article_params` method to
774
- permit the new form parameter:
775
-
776
- ```ruby
777
- def article_params
778
- params.require(:article).permit(:title, :text, :author_name)
779
- end
780
- ```
781
-
782
- The `Blorgh::Article` model should then have some code to convert the `author_name`
783
- field into an actual `User` object and associate it as that article's `author`
784
- before the article is saved. It will also need to have an `attr_accessor` set up
785
- for this field, so that the setter and getter methods are defined for it.
786
-
787
- To do all this, you'll need to add the `attr_accessor` for `author_name`, the
788
- association for the author and the `before_save` call into
789
- `app/models/blorgh/article.rb`. The `author` association will be hard-coded to the
790
- `User` class for the time being.
791
-
792
- ```ruby
793
- attr_accessor :author_name
794
- belongs_to :author, class_name: "User"
795
-
796
- before_save :set_author
797
-
798
- private
799
- def set_author
800
- self.author = User.find_or_create_by(name: author_name)
801
- end
802
- ```
803
-
804
- By representing the `author` association's object with the `User` class, a link
805
- is established between the engine and the application. There needs to be a way
806
- of associating the records in the `blorgh_articles` table with the records in the
807
- `users` table. Because the association is called `author`, there should be an
808
- `author_id` column added to the `blorgh_articles` table.
809
-
810
- To generate this new column, run this command within the engine:
811
-
812
- ```bash
813
- $ bin/rails g migration add_author_id_to_blorgh_articles author_id:integer
814
- ```
815
-
816
- NOTE: Due to the migration's name and the column specification after it, Rails
817
- will automatically know that you want to add a column to a specific table and
818
- write that into the migration for you. You don't need to tell it any more than
819
- this.
820
-
821
- This migration will need to be run on the application. To do that, it must first
822
- be copied using this command:
823
-
824
- ```bash
825
- $ rake blorgh:install:migrations
826
- ```
827
-
828
- Notice that only _one_ migration was copied over here. This is because the first
829
- two migrations were copied over the first time this command was run.
830
-
831
- ```
832
- NOTE Migration [timestamp]_create_blorgh_articles.blorgh.rb from blorgh has been skipped. Migration with the same name already exists.
833
- NOTE Migration [timestamp]_create_blorgh_comments.blorgh.rb from blorgh has been skipped. Migration with the same name already exists.
834
- Copied migration [timestamp]_add_author_id_to_blorgh_articles.blorgh.rb from blorgh
835
- ```
836
-
837
- Run the migration using:
838
-
839
- ```bash
840
- $ rake db:migrate
841
- ```
842
-
843
- Now with all the pieces in place, an action will take place that will associate
844
- an author - represented by a record in the `users` table - with an article,
845
- represented by the `blorgh_articles` table from the engine.
846
-
847
- Finally, the author's name should be displayed on the article's page. Add this code
848
- above the "Title" output inside `app/views/blorgh/articles/show.html.erb`:
849
-
850
- ```html+erb
851
- <p>
852
- <b>Author:</b>
853
- <%= @article.author %>
854
- </p>
855
- ```
856
-
857
- By outputting `@article.author` using the `<%=` tag, the `to_s` method will be
858
- called on the object. By default, this will look quite ugly:
859
-
860
- ```
861
- #<User:0x00000100ccb3b0>
862
- ```
863
-
864
- This is undesirable. It would be much better to have the user's name there. To
865
- do this, add a `to_s` method to the `User` class within the application:
866
-
867
- ```ruby
868
- def to_s
869
- name
870
- end
871
- ```
872
-
873
- Now instead of the ugly Ruby object output, the author's name will be displayed.
874
-
875
- #### Using a Controller Provided by the Application
876
-
877
- Because Rails controllers generally share code for things like authentication
878
- and accessing session variables, they inherit from `ApplicationController` by
879
- default. Rails engines, however are scoped to run independently from the main
880
- application, so each engine gets a scoped `ApplicationController`. This
881
- namespace prevents code collisions, but often engine controllers need to access
882
- methods in the main application's `ApplicationController`. An easy way to
883
- provide this access is to change the engine's scoped `ApplicationController` to
884
- inherit from the main application's `ApplicationController`. For our Blorgh
885
- engine this would be done by changing
886
- `app/controllers/blorgh/application_controller.rb` to look like:
887
-
888
- ```ruby
889
- module Blorgh
890
- class ApplicationController < ::ApplicationController
891
- end
892
- end
893
- ```
894
-
895
- By default, the engine's controllers inherit from
896
- `Blorgh::ApplicationController`. So, after making this change they will have
897
- access to the main application's `ApplicationController`, as though they were
898
- part of the main application.
899
-
900
- This change does require that the engine is run from a Rails application that
901
- has an `ApplicationController`.
902
-
903
- ### Configuring an Engine
904
-
905
- This section covers how to make the `User` class configurable, followed by
906
- general configuration tips for the engine.
907
-
908
- #### Setting Configuration Settings in the Application
909
-
910
- The next step is to make the class that represents a `User` in the application
911
- customizable for the engine. This is because that class may not always be
912
- `User`, as previously explained. To make this setting customizable, the engine
913
- will have a configuration setting called `author_class` that will be used to
914
- specify which class represents users inside the application.
915
-
916
- To define this configuration setting, you should use a `mattr_accessor` inside
917
- the `Blorgh` module for the engine. Add this line to `lib/blorgh.rb` inside the
918
- engine:
919
-
920
- ```ruby
921
- mattr_accessor :author_class
922
- ```
923
-
924
- This method works like its brothers, `attr_accessor` and `cattr_accessor`, but
925
- provides a setter and getter method on the module with the specified name. To
926
- use it, it must be referenced using `Blorgh.author_class`.
927
-
928
- The next step is to switch the `Blorgh::Article` model over to this new setting.
929
- Change the `belongs_to` association inside this model
930
- (`app/models/blorgh/article.rb`) to this:
931
-
932
- ```ruby
933
- belongs_to :author, class_name: Blorgh.author_class
934
- ```
935
-
936
- The `set_author` method in the `Blorgh::Article` model should also use this class:
937
-
938
- ```ruby
939
- self.author = Blorgh.author_class.constantize.find_or_create_by(name: author_name)
940
- ```
941
-
942
- To save having to call `constantize` on the `author_class` result all the time,
943
- you could instead just override the `author_class` getter method inside the
944
- `Blorgh` module in the `lib/blorgh.rb` file to always call `constantize` on the
945
- saved value before returning the result:
946
-
947
- ```ruby
948
- def self.author_class
949
- @@author_class.constantize
950
- end
951
- ```
952
-
953
- This would then turn the above code for `set_author` into this:
954
-
955
- ```ruby
956
- self.author = Blorgh.author_class.find_or_create_by(name: author_name)
957
- ```
958
-
959
- Resulting in something a little shorter, and more implicit in its behavior. The
960
- `author_class` method should always return a `Class` object.
961
-
962
- Since we changed the `author_class` method to return a `Class` instead of a
963
- `String`, we must also modify our `belongs_to` definition in the `Blorgh::Article`
964
- model:
965
-
966
- ```ruby
967
- belongs_to :author, class_name: Blorgh.author_class.to_s
968
- ```
969
-
970
- To set this configuration setting within the application, an initializer should
971
- be used. By using an initializer, the configuration will be set up before the
972
- application starts and calls the engine's models, which may depend on this
973
- configuration setting existing.
974
-
975
- Create a new initializer at `config/initializers/blorgh.rb` inside the
976
- application where the `blorgh` engine is installed and put this content in it:
977
-
978
- ```ruby
979
- Blorgh.author_class = "User"
980
- ```
981
-
982
- WARNING: It's very important here to use the `String` version of the class,
983
- rather than the class itself. If you were to use the class, Rails would attempt
984
- to load that class and then reference the related table. This could lead to
985
- problems if the table wasn't already existing. Therefore, a `String` should be
986
- used and then converted to a class using `constantize` in the engine later on.
987
-
988
- Go ahead and try to create a new article. You will see that it works exactly in the
989
- same way as before, except this time the engine is using the configuration
990
- setting in `config/initializers/blorgh.rb` to learn what the class is.
991
-
992
- There are now no strict dependencies on what the class is, only what the API for
993
- the class must be. The engine simply requires this class to define a
994
- `find_or_create_by` method which returns an object of that class, to be
995
- associated with an article when it's created. This object, of course, should have
996
- some sort of identifier by which it can be referenced.
997
-
998
- #### General Engine Configuration
999
-
1000
- Within an engine, there may come a time where you wish to use things such as
1001
- initializers, internationalization or other configuration options. The great
1002
- news is that these things are entirely possible, because a Rails engine shares
1003
- much the same functionality as a Rails application. In fact, a Rails
1004
- application's functionality is actually a superset of what is provided by
1005
- engines!
1006
-
1007
- If you wish to use an initializer - code that should run before the engine is
1008
- loaded - the place for it is the `config/initializers` folder. This directory's
1009
- functionality is explained in the [Initializers
1010
- section](configuring.html#initializers) of the Configuring guide, and works
1011
- precisely the same way as the `config/initializers` directory inside an
1012
- application. The same thing goes if you want to use a standard initializer.
1013
-
1014
- For locales, simply place the locale files in the `config/locales` directory,
1015
- just like you would in an application.
1016
-
1017
- Testing an engine
1018
- -----------------
1019
-
1020
- When an engine is generated, there is a smaller dummy application created inside
1021
- it at `test/dummy`. This application is used as a mounting point for the engine,
1022
- to make testing the engine extremely simple. You may extend this application by
1023
- generating controllers, models or views from within the directory, and then use
1024
- those to test your engine.
1025
-
1026
- The `test` directory should be treated like a typical Rails testing environment,
1027
- allowing for unit, functional and integration tests.
1028
-
1029
- ### Functional Tests
1030
-
1031
- A matter worth taking into consideration when writing functional tests is that
1032
- the tests are going to be running on an application - the `test/dummy`
1033
- application - rather than your engine. This is due to the setup of the testing
1034
- environment; an engine needs an application as a host for testing its main
1035
- functionality, especially controllers. This means that if you were to make a
1036
- typical `GET` to a controller in a controller's functional test like this:
1037
-
1038
- ```ruby
1039
- module Blorgh
1040
- class FooControllerTest < ActionController::TestCase
1041
- def test_index
1042
- get :index
1043
- ...
1044
- end
1045
- end
1046
- end
1047
- ```
1048
-
1049
- It may not function correctly. This is because the application doesn't know how
1050
- to route these requests to the engine unless you explicitly tell it **how**. To
1051
- do this, you must set the `@routes` instance variable to the engine's route set
1052
- in your setup code:
1053
-
1054
- ```ruby
1055
- module Blorgh
1056
- class FooControllerTest < ActionController::TestCase
1057
- setup do
1058
- @routes = Engine.routes
1059
- end
1060
-
1061
- def test_index
1062
- get :index
1063
- ...
1064
- end
1065
- end
1066
- end
1067
- ```
1068
-
1069
- This tells the application that you still want to perform a `GET` request to the
1070
- `index` action of this controller, but you want to use the engine's route to get
1071
- there, rather than the application's one.
1072
-
1073
- This also ensures that the engine's URL helpers will work as expected in your
1074
- tests.
1075
-
1076
- Improving engine functionality
1077
- ------------------------------
1078
-
1079
- This section explains how to add and/or override engine MVC functionality in the
1080
- main Rails application.
1081
-
1082
- ### Overriding Models and Controllers
1083
-
1084
- Engine model and controller classes can be extended by open classing them in the
1085
- main Rails application (since model and controller classes are just Ruby classes
1086
- that inherit Rails specific functionality). Open classing an Engine class
1087
- redefines it for use in the main application. This is usually implemented by
1088
- using the decorator pattern.
1089
-
1090
- For simple class modifications, use `Class#class_eval`. For complex class
1091
- modifications, consider using `ActiveSupport::Concern`.
1092
-
1093
- #### A note on Decorators and Loading Code
1094
-
1095
- Because these decorators are not referenced by your Rails application itself,
1096
- Rails' autoloading system will not kick in and load your decorators. This means
1097
- that you need to require them yourself.
1098
-
1099
- Here is some sample code to do this:
1100
-
1101
- ```ruby
1102
- # lib/blorgh/engine.rb
1103
- module Blorgh
1104
- class Engine < ::Rails::Engine
1105
- isolate_namespace Blorgh
1106
-
1107
- config.to_prepare do
1108
- Dir.glob(Rails.root + "app/decorators/**/*_decorator*.rb").each do |c|
1109
- require_dependency(c)
1110
- end
1111
- end
1112
- end
1113
- end
1114
- ```
1115
-
1116
- This doesn't apply to just Decorators, but anything that you add in an engine
1117
- that isn't referenced by your main application.
1118
-
1119
- #### Implementing Decorator Pattern Using Class#class_eval
1120
-
1121
- **Adding** `Article#time_since_created`:
1122
-
1123
- ```ruby
1124
- # MyApp/app/decorators/models/blorgh/article_decorator.rb
1125
-
1126
- Blorgh::Article.class_eval do
1127
- def time_since_created
1128
- Time.current - created_at
1129
- end
1130
- end
1131
- ```
1132
-
1133
- ```ruby
1134
- # Blorgh/app/models/article.rb
1135
-
1136
- class Article < ActiveRecord::Base
1137
- has_many :comments
1138
- end
1139
- ```
1140
-
1141
-
1142
- **Overriding** `Article#summary`:
1143
-
1144
- ```ruby
1145
- # MyApp/app/decorators/models/blorgh/article_decorator.rb
1146
-
1147
- Blorgh::Article.class_eval do
1148
- def summary
1149
- "#{title} - #{truncate(text)}"
1150
- end
1151
- end
1152
- ```
1153
-
1154
- ```ruby
1155
- # Blorgh/app/models/article.rb
1156
-
1157
- class Article < ActiveRecord::Base
1158
- has_many :comments
1159
- def summary
1160
- "#{title}"
1161
- end
1162
- end
1163
- ```
1164
-
1165
- #### Implementing Decorator Pattern Using ActiveSupport::Concern
1166
-
1167
- Using `Class#class_eval` is great for simple adjustments, but for more complex
1168
- class modifications, you might want to consider using [`ActiveSupport::Concern`]
1169
- (http://api.rubyonrails.org/classes/ActiveSupport/Concern.html).
1170
- ActiveSupport::Concern manages load order of interlinked dependent modules and
1171
- classes at run time allowing you to significantly modularize your code.
1172
-
1173
- **Adding** `Article#time_since_created` and **Overriding** `Article#summary`:
1174
-
1175
- ```ruby
1176
- # MyApp/app/models/blorgh/article.rb
1177
-
1178
- class Blorgh::Article < ActiveRecord::Base
1179
- include Blorgh::Concerns::Models::Article
1180
-
1181
- def time_since_created
1182
- Time.current - created_at
1183
- end
1184
-
1185
- def summary
1186
- "#{title} - #{truncate(text)}"
1187
- end
1188
- end
1189
- ```
1190
-
1191
- ```ruby
1192
- # Blorgh/app/models/article.rb
1193
-
1194
- class Article < ActiveRecord::Base
1195
- include Blorgh::Concerns::Models::Article
1196
- end
1197
- ```
1198
-
1199
- ```ruby
1200
- # Blorgh/lib/concerns/models/article
1201
-
1202
- module Blorgh::Concerns::Models::Article
1203
- extend ActiveSupport::Concern
1204
-
1205
- # 'included do' causes the included code to be evaluated in the
1206
- # context where it is included (article.rb), rather than being
1207
- # executed in the module's context (blorgh/concerns/models/article).
1208
- included do
1209
- attr_accessor :author_name
1210
- belongs_to :author, class_name: "User"
1211
-
1212
- before_save :set_author
1213
-
1214
- private
1215
- def set_author
1216
- self.author = User.find_or_create_by(name: author_name)
1217
- end
1218
- end
1219
-
1220
- def summary
1221
- "#{title}"
1222
- end
1223
-
1224
- module ClassMethods
1225
- def some_class_method
1226
- 'some class method string'
1227
- end
1228
- end
1229
- end
1230
- ```
1231
-
1232
- ### Overriding Views
1233
-
1234
- When Rails looks for a view to render, it will first look in the `app/views`
1235
- directory of the application. If it cannot find the view there, it will check in
1236
- the `app/views` directories of all engines that have this directory.
1237
-
1238
- When the application is asked to render the view for `Blorgh::ArticlesController`'s
1239
- index action, it will first look for the path
1240
- `app/views/blorgh/articles/index.html.erb` within the application. If it cannot
1241
- find it, it will look inside the engine.
1242
-
1243
- You can override this view in the application by simply creating a new file at
1244
- `app/views/blorgh/articles/index.html.erb`. Then you can completely change what
1245
- this view would normally output.
1246
-
1247
- Try this now by creating a new file at `app/views/blorgh/articles/index.html.erb`
1248
- and put this content in it:
1249
-
1250
- ```html+erb
1251
- <h1>Articles</h1>
1252
- <%= link_to "New Article", new_article_path %>
1253
- <% @articles.each do |article| %>
1254
- <h2><%= article.title %></h2>
1255
- <small>By <%= article.author %></small>
1256
- <%= simple_format(article.text) %>
1257
- <hr>
1258
- <% end %>
1259
- ```
1260
-
1261
- ### Routes
1262
-
1263
- Routes inside an engine are isolated from the application by default. This is
1264
- done by the `isolate_namespace` call inside the `Engine` class. This essentially
1265
- means that the application and its engines can have identically named routes and
1266
- they will not clash.
1267
-
1268
- Routes inside an engine are drawn on the `Engine` class within
1269
- `config/routes.rb`, like this:
1270
-
1271
- ```ruby
1272
- Blorgh::Engine.routes.draw do
1273
- resources :articles
1274
- end
1275
- ```
1276
-
1277
- By having isolated routes such as this, if you wish to link to an area of an
1278
- engine from within an application, you will need to use the engine's routing
1279
- proxy method. Calls to normal routing methods such as `articles_path` may end up
1280
- going to undesired locations if both the application and the engine have such a
1281
- helper defined.
1282
-
1283
- For instance, the following example would go to the application's `articles_path`
1284
- if that template was rendered from the application, or the engine's `articles_path`
1285
- if it was rendered from the engine:
1286
-
1287
- ```erb
1288
- <%= link_to "Blog articles", articles_path %>
1289
- ```
1290
-
1291
- To make this route always use the engine's `articles_path` routing helper method,
1292
- we must call the method on the routing proxy method that shares the same name as
1293
- the engine.
1294
-
1295
- ```erb
1296
- <%= link_to "Blog articles", blorgh.articles_path %>
1297
- ```
1298
-
1299
- If you wish to reference the application inside the engine in a similar way, use
1300
- the `main_app` helper:
1301
-
1302
- ```erb
1303
- <%= link_to "Home", main_app.root_path %>
1304
- ```
1305
-
1306
- If you were to use this inside an engine, it would **always** go to the
1307
- application's root. If you were to leave off the `main_app` "routing proxy"
1308
- method call, it could potentially go to the engine's or application's root,
1309
- depending on where it was called from.
1310
-
1311
- If a template rendered from within an engine attempts to use one of the
1312
- application's routing helper methods, it may result in an undefined method call.
1313
- If you encounter such an issue, ensure that you're not attempting to call the
1314
- application's routing methods without the `main_app` prefix from within the
1315
- engine.
1316
-
1317
- ### Assets
1318
-
1319
- Assets within an engine work in an identical way to a full application. Because
1320
- the engine class inherits from `Rails::Engine`, the application will know to
1321
- look up assets in the engine's 'app/assets' and 'lib/assets' directories.
1322
-
1323
- Like all of the other components of an engine, the assets should be namespaced.
1324
- This means that if you have an asset called `style.css`, it should be placed at
1325
- `app/assets/stylesheets/[engine name]/style.css`, rather than
1326
- `app/assets/stylesheets/style.css`. If this asset isn't namespaced, there is a
1327
- possibility that the host application could have an asset named identically, in
1328
- which case the application's asset would take precedence and the engine's one
1329
- would be ignored.
1330
-
1331
- Imagine that you did have an asset located at
1332
- `app/assets/stylesheets/blorgh/style.css` To include this asset inside an
1333
- application, just use `stylesheet_link_tag` and reference the asset as if it
1334
- were inside the engine:
1335
-
1336
- ```erb
1337
- <%= stylesheet_link_tag "blorgh/style.css" %>
1338
- ```
1339
-
1340
- You can also specify these assets as dependencies of other assets using Asset
1341
- Pipeline require statements in processed files:
1342
-
1343
- ```
1344
- /*
1345
- *= require blorgh/style
1346
- */
1347
- ```
1348
-
1349
- INFO. Remember that in order to use languages like Sass or CoffeeScript, you
1350
- should add the relevant library to your engine's `.gemspec`.
1351
-
1352
- ### Separate Assets & Precompiling
1353
-
1354
- There are some situations where your engine's assets are not required by the
1355
- host application. For example, say that you've created an admin functionality
1356
- that only exists for your engine. In this case, the host application doesn't
1357
- need to require `admin.css` or `admin.js`. Only the gem's admin layout needs
1358
- these assets. It doesn't make sense for the host app to include
1359
- `"blorgh/admin.css"` in its stylesheets. In this situation, you should
1360
- explicitly define these assets for precompilation. This tells sprockets to add
1361
- your engine assets when `rake assets:precompile` is triggered.
1362
-
1363
- You can define assets for precompilation in `engine.rb`:
1364
-
1365
- ```ruby
1366
- initializer "blorgh.assets.precompile" do |app|
1367
- app.config.assets.precompile += %w(admin.css admin.js)
1368
- end
1369
- ```
1370
-
1371
- For more information, read the [Asset Pipeline guide](asset_pipeline.html).
1372
-
1373
- ### Other Gem Dependencies
1374
-
1375
- Gem dependencies inside an engine should be specified inside the `.gemspec` file
1376
- at the root of the engine. The reason is that the engine may be installed as a
1377
- gem. If dependencies were to be specified inside the `Gemfile`, these would not
1378
- be recognized by a traditional gem install and so they would not be installed,
1379
- causing the engine to malfunction.
1380
-
1381
- To specify a dependency that should be installed with the engine during a
1382
- traditional `gem install`, specify it inside the `Gem::Specification` block
1383
- inside the `.gemspec` file in the engine:
1384
-
1385
- ```ruby
1386
- s.add_dependency "moo"
1387
- ```
1388
-
1389
- To specify a dependency that should only be installed as a development
1390
- dependency of the application, specify it like this:
1391
-
1392
- ```ruby
1393
- s.add_development_dependency "moo"
1394
- ```
1395
-
1396
- Both kinds of dependencies will be installed when `bundle install` is run inside
1397
- of the application. The development dependencies for the gem will only be used
1398
- when the tests for the engine are running.
1399
-
1400
- Note that if you want to immediately require dependencies when the engine is
1401
- required, you should require them before the engine's initialization. For
1402
- example:
1403
-
1404
- ```ruby
1405
- require 'other_engine/engine'
1406
- require 'yet_another_engine/engine'
1407
-
1408
- module MyEngine
1409
- class Engine < ::Rails::Engine
1410
- end
1411
- end
1412
- ```