rails 4.1.4 → 5.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (284) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +24 -18
  3. metadata +51 -304
  4. data/guides/CHANGELOG.md +0 -41
  5. data/guides/Rakefile +0 -77
  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 -53
  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 -710
  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 -53
  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/code/getting_started/Gemfile +0 -40
  148. data/guides/code/getting_started/Gemfile.lock +0 -125
  149. data/guides/code/getting_started/README.rdoc +0 -28
  150. data/guides/code/getting_started/Rakefile +0 -6
  151. data/guides/code/getting_started/app/assets/javascripts/application.js +0 -15
  152. data/guides/code/getting_started/app/assets/javascripts/comments.js.coffee +0 -3
  153. data/guides/code/getting_started/app/assets/javascripts/posts.js.coffee +0 -3
  154. data/guides/code/getting_started/app/assets/javascripts/welcome.js.coffee +0 -3
  155. data/guides/code/getting_started/app/assets/stylesheets/application.css +0 -13
  156. data/guides/code/getting_started/app/assets/stylesheets/comments.css.scss +0 -3
  157. data/guides/code/getting_started/app/assets/stylesheets/posts.css.scss +0 -3
  158. data/guides/code/getting_started/app/assets/stylesheets/welcome.css.scss +0 -3
  159. data/guides/code/getting_started/app/controllers/application_controller.rb +0 -5
  160. data/guides/code/getting_started/app/controllers/comments_controller.rb +0 -23
  161. data/guides/code/getting_started/app/controllers/posts_controller.rb +0 -53
  162. data/guides/code/getting_started/app/controllers/welcome_controller.rb +0 -4
  163. data/guides/code/getting_started/app/helpers/application_helper.rb +0 -2
  164. data/guides/code/getting_started/app/helpers/comments_helper.rb +0 -2
  165. data/guides/code/getting_started/app/helpers/posts_helper.rb +0 -2
  166. data/guides/code/getting_started/app/helpers/welcome_helper.rb +0 -2
  167. data/guides/code/getting_started/app/models/comment.rb +0 -3
  168. data/guides/code/getting_started/app/models/post.rb +0 -7
  169. data/guides/code/getting_started/app/views/comments/_comment.html.erb +0 -15
  170. data/guides/code/getting_started/app/views/comments/_form.html.erb +0 -13
  171. data/guides/code/getting_started/app/views/layouts/application.html.erb +0 -14
  172. data/guides/code/getting_started/app/views/posts/_form.html.erb +0 -27
  173. data/guides/code/getting_started/app/views/posts/edit.html.erb +0 -5
  174. data/guides/code/getting_started/app/views/posts/index.html.erb +0 -21
  175. data/guides/code/getting_started/app/views/posts/new.html.erb +0 -5
  176. data/guides/code/getting_started/app/views/posts/show.html.erb +0 -18
  177. data/guides/code/getting_started/app/views/welcome/index.html.erb +0 -4
  178. data/guides/code/getting_started/bin/bundle +0 -4
  179. data/guides/code/getting_started/bin/rails +0 -4
  180. data/guides/code/getting_started/bin/rake +0 -4
  181. data/guides/code/getting_started/config/application.rb +0 -18
  182. data/guides/code/getting_started/config/boot.rb +0 -4
  183. data/guides/code/getting_started/config/database.yml +0 -25
  184. data/guides/code/getting_started/config/environment.rb +0 -5
  185. data/guides/code/getting_started/config/environments/development.rb +0 -30
  186. data/guides/code/getting_started/config/environments/production.rb +0 -80
  187. data/guides/code/getting_started/config/environments/test.rb +0 -36
  188. data/guides/code/getting_started/config/initializers/backtrace_silencers.rb +0 -7
  189. data/guides/code/getting_started/config/initializers/filter_parameter_logging.rb +0 -4
  190. data/guides/code/getting_started/config/initializers/inflections.rb +0 -16
  191. data/guides/code/getting_started/config/initializers/locale.rb +0 -9
  192. data/guides/code/getting_started/config/initializers/mime_types.rb +0 -5
  193. data/guides/code/getting_started/config/initializers/secret_token.rb +0 -12
  194. data/guides/code/getting_started/config/initializers/session_store.rb +0 -3
  195. data/guides/code/getting_started/config/initializers/wrap_parameters.rb +0 -14
  196. data/guides/code/getting_started/config/locales/en.yml +0 -23
  197. data/guides/code/getting_started/config/routes.rb +0 -7
  198. data/guides/code/getting_started/config.ru +0 -4
  199. data/guides/code/getting_started/db/migrate/20130122042648_create_posts.rb +0 -10
  200. data/guides/code/getting_started/db/migrate/20130122045842_create_comments.rb +0 -11
  201. data/guides/code/getting_started/db/schema.rb +0 -33
  202. data/guides/code/getting_started/db/seeds.rb +0 -7
  203. data/guides/code/getting_started/public/404.html +0 -60
  204. data/guides/code/getting_started/public/422.html +0 -60
  205. data/guides/code/getting_started/public/500.html +0 -59
  206. data/guides/code/getting_started/public/favicon.ico +0 -0
  207. data/guides/code/getting_started/public/robots.txt +0 -5
  208. data/guides/code/getting_started/test/controllers/comments_controller_test.rb +0 -7
  209. data/guides/code/getting_started/test/controllers/posts_controller_test.rb +0 -7
  210. data/guides/code/getting_started/test/controllers/welcome_controller_test.rb +0 -9
  211. data/guides/code/getting_started/test/fixtures/comments.yml +0 -11
  212. data/guides/code/getting_started/test/fixtures/posts.yml +0 -9
  213. data/guides/code/getting_started/test/helpers/comments_helper_test.rb +0 -4
  214. data/guides/code/getting_started/test/helpers/posts_helper_test.rb +0 -4
  215. data/guides/code/getting_started/test/helpers/welcome_helper_test.rb +0 -4
  216. data/guides/code/getting_started/test/models/comment_test.rb +0 -7
  217. data/guides/code/getting_started/test/models/post_test.rb +0 -7
  218. data/guides/code/getting_started/test/test_helper.rb +0 -12
  219. data/guides/rails_guides/generator.rb +0 -248
  220. data/guides/rails_guides/helpers.rb +0 -53
  221. data/guides/rails_guides/indexer.rb +0 -68
  222. data/guides/rails_guides/kindle.rb +0 -119
  223. data/guides/rails_guides/levenshtein.rb +0 -31
  224. data/guides/rails_guides/markdown/renderer.rb +0 -82
  225. data/guides/rails_guides/markdown.rb +0 -163
  226. data/guides/rails_guides.rb +0 -63
  227. data/guides/source/2_2_release_notes.md +0 -435
  228. data/guides/source/2_3_release_notes.md +0 -621
  229. data/guides/source/3_0_release_notes.md +0 -611
  230. data/guides/source/3_1_release_notes.md +0 -556
  231. data/guides/source/3_2_release_notes.md +0 -565
  232. data/guides/source/4_0_release_notes.md +0 -276
  233. data/guides/source/4_1_release_notes.md +0 -731
  234. data/guides/source/_license.html.erb +0 -2
  235. data/guides/source/_welcome.html.erb +0 -25
  236. data/guides/source/action_controller_overview.md +0 -1175
  237. data/guides/source/action_mailer_basics.md +0 -689
  238. data/guides/source/action_view_overview.md +0 -1610
  239. data/guides/source/active_model_basics.md +0 -200
  240. data/guides/source/active_record_basics.md +0 -373
  241. data/guides/source/active_record_callbacks.md +0 -410
  242. data/guides/source/active_record_querying.md +0 -1773
  243. data/guides/source/active_record_validations.md +0 -1169
  244. data/guides/source/active_support_core_extensions.md +0 -3864
  245. data/guides/source/active_support_instrumentation.md +0 -496
  246. data/guides/source/api_documentation_guidelines.md +0 -315
  247. data/guides/source/asset_pipeline.md +0 -1163
  248. data/guides/source/association_basics.md +0 -2229
  249. data/guides/source/caching_with_rails.md +0 -354
  250. data/guides/source/command_line.md +0 -603
  251. data/guides/source/configuring.md +0 -942
  252. data/guides/source/contributing_to_ruby_on_rails.md +0 -544
  253. data/guides/source/credits.html.erb +0 -80
  254. data/guides/source/debugging_rails_applications.md +0 -707
  255. data/guides/source/development_dependencies_install.md +0 -278
  256. data/guides/source/documents.yaml +0 -193
  257. data/guides/source/engines.md +0 -1391
  258. data/guides/source/form_helpers.md +0 -1001
  259. data/guides/source/generators.md +0 -663
  260. data/guides/source/getting_started.md +0 -1947
  261. data/guides/source/i18n.md +0 -1043
  262. data/guides/source/index.html.erb +0 -27
  263. data/guides/source/initialization.md +0 -657
  264. data/guides/source/kindle/copyright.html.erb +0 -1
  265. data/guides/source/kindle/layout.html.erb +0 -27
  266. data/guides/source/kindle/rails_guides.opf.erb +0 -52
  267. data/guides/source/kindle/toc.html.erb +0 -24
  268. data/guides/source/kindle/toc.ncx.erb +0 -64
  269. data/guides/source/kindle/welcome.html.erb +0 -5
  270. data/guides/source/layout.html.erb +0 -146
  271. data/guides/source/layouts_and_rendering.md +0 -1226
  272. data/guides/source/maintenance_policy.md +0 -56
  273. data/guides/source/migrations.md +0 -1109
  274. data/guides/source/nested_model_forms.md +0 -225
  275. data/guides/source/plugins.md +0 -444
  276. data/guides/source/rails_application_templates.md +0 -248
  277. data/guides/source/rails_on_rack.md +0 -333
  278. data/guides/source/routing.md +0 -1115
  279. data/guides/source/ruby_on_rails_guides_guidelines.md +0 -128
  280. data/guides/source/security.md +0 -1018
  281. data/guides/source/testing.md +0 -1052
  282. data/guides/source/upgrading_ruby_on_rails.md +0 -899
  283. data/guides/source/working_with_javascript_in_rails.md +0 -405
  284. data/guides/w3c_validator.rb +0 -95
@@ -1,1391 +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). This guide will refer to them simply as "engines" throughout. An
35
- engine **can** be a plugin, and a plugin **can** be an engine.
36
-
37
- The engine that will be created in this guide will be called "blorgh". The
38
- engine will provide blogging functionality to its host applications, allowing
39
- for new posts and comments to be created. At the beginning of this guide, you
40
- will be working solely within the engine itself, but in later sections you'll
41
- see how to hook it into an application.
42
-
43
- Engines can also be isolated from their host applications. This means that an
44
- application is able to have a path provided by a routing helper such as
45
- `posts_path` and use an engine also that provides a path also called
46
- `posts_path`, and the two would not clash. Along with this, controllers, models
47
- and table names are also namespaced. You'll see how to do this later in this
48
- guide.
49
-
50
- It's important to keep in mind at all times that the application should
51
- **always** take precedence over its engines. An application is the object that
52
- has final say in what goes on in the universe (with the universe being the
53
- application's environment) where the engine should only be enhancing it, rather
54
- than changing it drastically.
55
-
56
- To see demonstrations of other engines, check out
57
- [Devise](https://github.com/plataformatec/devise), an engine that provides
58
- authentication for its parent applications, or
59
- [Forem](https://github.com/radar/forem), an engine that provides forum
60
- functionality. There's also [Spree](https://github.com/spree/spree) which
61
- provides an e-commerce platform, and
62
- [RefineryCMS](https://github.com/refinery/refinerycms), a CMS engine.
63
-
64
- Finally, engines would not have been possible without the work of James Adam,
65
- Piotr Sarnacki, the Rails Core Team, and a number of other people. If you ever
66
- meet them, don't forget to say thanks!
67
-
68
- Generating an engine
69
- --------------------
70
-
71
- To generate an engine, you will need to run the plugin generator and pass it
72
- options as appropriate to the need. For the "blorgh" example, you will need to
73
- create a "mountable" engine, running this command in a terminal:
74
-
75
- ```bash
76
- $ bin/rails plugin new blorgh --mountable
77
- ```
78
-
79
- The full list of options for the plugin generator may be seen by typing:
80
-
81
- ```bash
82
- $ bin/rails plugin --help
83
- ```
84
-
85
- The `--full` option tells the generator that you want to create an engine,
86
- including a skeleton structure that provides the following:
87
-
88
- * An `app` directory tree
89
- * A `config/routes.rb` file:
90
-
91
- ```ruby
92
- Rails.application.routes.draw do
93
- end
94
- ```
95
-
96
- * A file at `lib/blorgh/engine.rb`, which is identical in function to a
97
- * standard Rails application's `config/application.rb` file:
98
-
99
- ```ruby
100
- module Blorgh
101
- class Engine < ::Rails::Engine
102
- end
103
- end
104
- ```
105
-
106
- The `--mountable` option tells the generator that you want to create a
107
- "mountable" and namespace-isolated engine. This generator will provide the same
108
- skeleton structure as would the `--full` option, and will add:
109
-
110
- * Asset manifest files (`application.js` and `application.css`)
111
- * A namespaced `ApplicationController` stub
112
- * A namespaced `ApplicationHelper` stub
113
- * A layout view template for the engine
114
- * Namespace isolation to `config/routes.rb`:
115
-
116
- ```ruby
117
- Blorgh::Engine.routes.draw do
118
- end
119
- ```
120
-
121
- * Namespace isolation to `lib/blorgh/engine.rb`:
122
-
123
- ```ruby
124
- module Blorgh
125
- class Engine < ::Rails::Engine
126
- isolate_namespace Blorgh
127
- end
128
- end
129
- ```
130
-
131
- Additionally, the `--mountable` option tells the generator to mount the engine
132
- inside the dummy testing application located at `test/dummy` by adding the
133
- following to the dummy application's routes file at
134
- `test/dummy/config/routes.rb`:
135
-
136
- ```ruby
137
- mount Blorgh::Engine, at: "blorgh"
138
- ```
139
-
140
- ### Inside an Engine
141
-
142
- #### Critical Files
143
-
144
- At the root of this brand new engine's directory lives a `blorgh.gemspec` file.
145
- When you include the engine into an application later on, you will do so with
146
- this line in the Rails application's `Gemfile`:
147
-
148
- ```ruby
149
- gem 'blorgh', path: "vendor/engines/blorgh"
150
- ```
151
-
152
- Don't forget to run `bundle install` as usual. By specifying it as a gem within
153
- the `Gemfile`, Bundler will load it as such, parsing this `blorgh.gemspec` file
154
- and requiring a file within the `lib` directory called `lib/blorgh.rb`. This
155
- file requires the `blorgh/engine.rb` file (located at `lib/blorgh/engine.rb`)
156
- and defines a base module called `Blorgh`.
157
-
158
- ```ruby
159
- require "blorgh/engine"
160
-
161
- module Blorgh
162
- end
163
- ```
164
-
165
- TIP: Some engines choose to use this file to put global configuration options
166
- for their engine. It's a relatively good idea, so if you want to offer
167
- configuration options, the file where your engine's `module` is defined is
168
- perfect for that. Place the methods inside the module and you'll be good to go.
169
-
170
- Within `lib/blorgh/engine.rb` is the base class for the engine:
171
-
172
- ```ruby
173
- module Blorgh
174
- class Engine < Rails::Engine
175
- isolate_namespace Blorgh
176
- end
177
- end
178
- ```
179
-
180
- By inheriting from the `Rails::Engine` class, this gem notifies Rails that
181
- there's an engine at the specified path, and will correctly mount the engine
182
- inside the application, performing tasks such as adding the `app` directory of
183
- the engine to the load path for models, mailers, controllers and views.
184
-
185
- The `isolate_namespace` method here deserves special notice. This call is
186
- responsible for isolating the controllers, models, routes and other things into
187
- their own namespace, away from similar components inside the application.
188
- Without this, there is a possibility that the engine's components could "leak"
189
- into the application, causing unwanted disruption, or that important engine
190
- components could be overridden by similarly named things within the application.
191
- One of the examples of such conflicts is helpers. Without calling
192
- `isolate_namespace`, the engine's helpers would be included in an application's
193
- controllers.
194
-
195
- NOTE: It is **highly** recommended that the `isolate_namespace` line be left
196
- within the `Engine` class definition. Without it, classes generated in an engine
197
- **may** conflict with an application.
198
-
199
- What this isolation of the namespace means is that a model generated by a call
200
- to `bin/rails g model`, such as `bin/rails g model post`, won't be called `Post`, but
201
- instead be namespaced and called `Blorgh::Post`. In addition, the table for the
202
- model is namespaced, becoming `blorgh_posts`, rather than simply `posts`.
203
- Similar to the model namespacing, a controller called `PostsController` becomes
204
- `Blorgh::PostsController` and the views for that controller will not be at
205
- `app/views/posts`, but `app/views/blorgh/posts` instead. Mailers are namespaced
206
- as well.
207
-
208
- Finally, routes will also be isolated within the engine. This is one of the most
209
- important parts about namespacing, and is discussed later in the
210
- [Routes](#routes) section of this guide.
211
-
212
- #### `app` Directory
213
-
214
- Inside the `app` directory are the standard `assets`, `controllers`, `helpers`,
215
- `mailers`, `models` and `views` directories that you should be familiar with
216
- from an application. The `helpers`, `mailers` and `models` directories are
217
- empty, so they aren't described in this section. We'll look more into models in
218
- a future section, when we're writing the engine.
219
-
220
- Within the `app/assets` directory, there are the `images`, `javascripts` and
221
- `stylesheets` directories which, again, you should be familiar with due to their
222
- similarity to an application. One difference here, however, is that each
223
- directory contains a sub-directory with the engine name. Because this engine is
224
- going to be namespaced, its assets should be too.
225
-
226
- Within the `app/controllers` directory there is a `blorgh` directory that
227
- contains a file called `application_controller.rb`. This file will provide any
228
- common functionality for the controllers of the engine. The `blorgh` directory
229
- is where the other controllers for the engine will go. By placing them within
230
- this namespaced directory, you prevent them from possibly clashing with
231
- identically-named controllers within other engines or even within the
232
- application.
233
-
234
- NOTE: The `ApplicationController` class inside an engine is named just like a
235
- Rails application in order to make it easier for you to convert your
236
- applications into engines.
237
-
238
- Lastly, the `app/views` directory contains a `layouts` folder, which contains a
239
- file at `blorgh/application.html.erb`. This file allows you to specify a layout
240
- for the engine. If this engine is to be used as a stand-alone engine, then you
241
- would add any customization to its layout in this file, rather than the
242
- application's `app/views/layouts/application.html.erb` file.
243
-
244
- If you don't want to force a layout on to users of the engine, then you can
245
- delete this file and reference a different layout in the controllers of your
246
- engine.
247
-
248
- #### `bin` Directory
249
-
250
- This directory contains one file, `bin/rails`, which enables you to use the
251
- `rails` sub-commands and generators just like you would within an application.
252
- This means that you will be able to generate new controllers and models for this
253
- engine very easily by running commands like this:
254
-
255
- ```bash
256
- $ bin/rails g model
257
- ```
258
-
259
- Keep in mind, of course, that anything generated with these commands inside of
260
- an engine that has `isolate_namespace` in the `Engine` class will be namespaced.
261
-
262
- #### `test` Directory
263
-
264
- The `test` directory is where tests for the engine will go. To test the engine,
265
- there is a cut-down version of a Rails application embedded within it at
266
- `test/dummy`. This application will mount the engine in the
267
- `test/dummy/config/routes.rb` file:
268
-
269
- ```ruby
270
- Rails.application.routes.draw do
271
- mount Blorgh::Engine => "/blorgh"
272
- end
273
- ```
274
-
275
- This line mounts the engine at the path `/blorgh`, which will make it accessible
276
- through the application only at that path.
277
-
278
- Inside the test directory there is the `test/integration` directory, where
279
- integration tests for the engine should be placed. Other directories can be
280
- created in the `test` directory as well. For example, you may wish to create a
281
- `test/models` directory for your model tests.
282
-
283
- Providing engine functionality
284
- ------------------------------
285
-
286
- The engine that this guide covers provides posting and commenting functionality
287
- and follows a similar thread to the [Getting Started
288
- Guide](getting_started.html), with some new twists.
289
-
290
- ### Generating a Post Resource
291
-
292
- The first thing to generate for a blog engine is the `Post` model and related
293
- controller. To quickly generate this, you can use the Rails scaffold generator.
294
-
295
- ```bash
296
- $ bin/rails generate scaffold post title:string text:text
297
- ```
298
-
299
- This command will output this information:
300
-
301
- ```
302
- invoke active_record
303
- create db/migrate/[timestamp]_create_blorgh_posts.rb
304
- create app/models/blorgh/post.rb
305
- invoke test_unit
306
- create test/models/blorgh/post_test.rb
307
- create test/fixtures/blorgh/posts.yml
308
- invoke resource_route
309
- route resources :posts
310
- invoke scaffold_controller
311
- create app/controllers/blorgh/posts_controller.rb
312
- invoke erb
313
- create app/views/blorgh/posts
314
- create app/views/blorgh/posts/index.html.erb
315
- create app/views/blorgh/posts/edit.html.erb
316
- create app/views/blorgh/posts/show.html.erb
317
- create app/views/blorgh/posts/new.html.erb
318
- create app/views/blorgh/posts/_form.html.erb
319
- invoke test_unit
320
- create test/controllers/blorgh/posts_controller_test.rb
321
- invoke helper
322
- create app/helpers/blorgh/posts_helper.rb
323
- invoke test_unit
324
- create test/helpers/blorgh/posts_helper_test.rb
325
- invoke assets
326
- invoke js
327
- create app/assets/javascripts/blorgh/posts.js
328
- invoke css
329
- create app/assets/stylesheets/blorgh/posts.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_posts` rather than the
337
- usual `create_posts`. 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/post.rb` rather than `app/models/post.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/post_test.rb` (rather than
344
- `test/models/post_test.rb`) and a fixture at `test/fixtures/blorgh/posts.yml`
345
- (rather than `test/fixtures/posts.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 :posts`, turning the
349
- `config/routes.rb` file for the engine into this:
350
-
351
- ```ruby
352
- Blorgh::Engine.routes.draw do
353
- resources :posts
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::PostsController` (at
366
- `app/controllers/blorgh/posts_controller.rb`) and its related views at
367
- `app/views/blorgh/posts`. This generator also generates a test for the
368
- controller (`test/controllers/blorgh/posts_controller_test.rb`) and a helper
369
- (`app/helpers/blorgh/posts_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 PostsController < 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/posts_helper.rb` is also namespaced:
386
-
387
- ```ruby
388
- module Blorgh
389
- module PostsHelper
390
- ...
391
- end
392
- end
393
- ```
394
-
395
- This helps prevent conflicts with any other engine or application that may have
396
- a post resource as well.
397
-
398
- Finally, the assets for this resource are generated in two files:
399
- `app/assets/javascripts/blorgh/posts.js` and
400
- `app/assets/stylesheets/blorgh/posts.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/posts` 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 `Post` model is namespaced, so to
421
- reference it you must call it as `Blorgh::Post`.
422
-
423
- ```ruby
424
- >> Blorgh::Post.find(1)
425
- => #<Blorgh::Post id: 1 ...>
426
- ```
427
-
428
- One final thing is that the `posts` 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 posts. 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: "posts#index"
435
- ```
436
-
437
- Now people will only need to go to the root of the engine to see all the posts,
438
- rather than visiting `/posts`. This means that instead of
439
- `http://localhost:3000/blorgh/posts`, 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 blog posts, 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 posts 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 `post_id` integer
451
- and `text` text column.
452
-
453
- ```bash
454
- $ bin/rails generate model Comment post_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
- $ bin/rake db:migrate
475
- ```
476
-
477
- To show the comments on a post, edit `app/views/blorgh/posts/show.html.erb` and
478
- add this line before the "Edit" link:
479
-
480
- ```html+erb
481
- <h3>Comments</h3>
482
- <%= render @post.comments %>
483
- ```
484
-
485
- This line will require there to be a `has_many` association for comments defined
486
- on the `Blorgh::Post` model, which there isn't right now. To define one, open
487
- `app/models/blorgh/post.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 Post < 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 a post. To add
509
- this, put this line underneath the call to `render @post.comments` in
510
- `app/views/blorgh/posts/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 [@post, @post.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 `/posts/:post_id/comments` within the engine. This route doesn't
533
- exist at the moment, but can be created by changing the `resources :posts` line
534
- inside `config/routes.rb` into these lines:
535
-
536
- ```ruby
537
- resources :posts 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 test_unit
562
- create test/helpers/blorgh/comments_helper_test.rb
563
- invoke assets
564
- invoke js
565
- create app/assets/javascripts/blorgh/comments.js
566
- invoke css
567
- create app/assets/stylesheets/blorgh/comments.css
568
- ```
569
-
570
- The form will be making a `POST` request to `/posts/:post_id/comments`, which
571
- will correspond with the `create` action in `Blorgh::CommentsController`. This
572
- action needs to be created, which can be done by putting the following lines
573
- inside the class definition in `app/controllers/blorgh/comments_controller.rb`:
574
-
575
- ```ruby
576
- def create
577
- @post = Post.find(params[:post_id])
578
- @comment = @post.comments.create(comment_params)
579
- flash[:notice] = "Comment has been created!"
580
- redirect_to posts_path
581
- end
582
-
583
- private
584
- def comment_params
585
- params.require(:comment).permit(:text)
586
- end
587
- ```
588
-
589
- This is the final step required to get the new comment form working. Displaying
590
- the comments, however, is not quite right yet. If you were to create a comment
591
- right now, you would see this error:
592
-
593
- ```
594
- Missing partial blorgh/comments/comment with {:handlers=>[:erb, :builder],
595
- :formats=>[:html], :locale=>[:en, :en]}. Searched in: *
596
- "/Users/ryan/Sites/side_projects/blorgh/test/dummy/app/views" *
597
- "/Users/ryan/Sites/side_projects/blorgh/app/views"
598
- ```
599
-
600
- The engine is unable to find the partial required for rendering the comments.
601
- Rails looks first in the application's (`test/dummy`) `app/views` directory and
602
- then in the engine's `app/views` directory. When it can't find it, it will throw
603
- this error. The engine knows to look for `blorgh/comments/comment` because the
604
- model object it is receiving is from the `Blorgh::Comment` class.
605
-
606
- This partial will be responsible for rendering just the comment text, for now.
607
- Create a new file at `app/views/blorgh/comments/_comment.html.erb` and put this
608
- line inside it:
609
-
610
- ```erb
611
- <%= comment_counter + 1 %>. <%= comment.text %>
612
- ```
613
-
614
- The `comment_counter` local variable is given to us by the `<%= render
615
- @post.comments %>` call, which will define it automatically and increment the
616
- counter as it iterates through each comment. It's used in this example to
617
- display a small number next to each comment when it's created.
618
-
619
- That completes the comment function of the blogging engine. Now it's time to use
620
- it within an application.
621
-
622
- Hooking Into an Application
623
- ---------------------------
624
-
625
- Using an engine within an application is very easy. This section covers how to
626
- mount the engine into an application and the initial setup required, as well as
627
- linking the engine to a `User` class provided by the application to provide
628
- ownership for posts and comments within the engine.
629
-
630
- ### Mounting the Engine
631
-
632
- First, the engine needs to be specified inside the application's `Gemfile`. If
633
- there isn't an application handy to test this out in, generate one using the
634
- `rails new` command outside of the engine directory like this:
635
-
636
- ```bash
637
- $ rails new unicorn
638
- ```
639
-
640
- Usually, specifying the engine inside the Gemfile would be done by specifying it
641
- as a normal, everyday gem.
642
-
643
- ```ruby
644
- gem 'devise'
645
- ```
646
-
647
- However, because you are developing the `blorgh` engine on your local machine,
648
- you will need to specify the `:path` option in your `Gemfile`:
649
-
650
- ```ruby
651
- gem 'blorgh', path: "/path/to/blorgh"
652
- ```
653
-
654
- Then run `bundle` to install the gem.
655
-
656
- As described earlier, by placing the gem in the `Gemfile` it will be loaded when
657
- Rails is loaded. It will first require `lib/blorgh.rb` from the engine, then
658
- `lib/blorgh/engine.rb`, which is the file that defines the major pieces of
659
- functionality for the engine.
660
-
661
- To make the engine's functionality accessible from within an application, it
662
- needs to be mounted in that application's `config/routes.rb` file:
663
-
664
- ```ruby
665
- mount Blorgh::Engine, at: "/blog"
666
- ```
667
-
668
- This line will mount the engine at `/blog` in the application. Making it
669
- accessible at `http://localhost:3000/blog` when the application runs with `rails
670
- server`.
671
-
672
- NOTE: Other engines, such as Devise, handle this a little differently by making
673
- you specify custom helpers (such as `devise_for`) in the routes. These helpers
674
- do exactly the same thing, mounting pieces of the engines's functionality at a
675
- pre-defined path which may be customizable.
676
-
677
- ### Engine setup
678
-
679
- The engine contains migrations for the `blorgh_posts` and `blorgh_comments`
680
- table which need to be created in the application's database so that the
681
- engine's models can query them correctly. To copy these migrations into the
682
- application use this command:
683
-
684
- ```bash
685
- $ bin/rake blorgh:install:migrations
686
- ```
687
-
688
- If you have multiple engines that need migrations copied over, use
689
- `railties:install:migrations` instead:
690
-
691
- ```bash
692
- $ bin/rake railties:install:migrations
693
- ```
694
-
695
- This command, when run for the first time, will copy over all the migrations
696
- from the engine. When run the next time, it will only copy over migrations that
697
- haven't been copied over already. The first run for this command will output
698
- something such as this:
699
-
700
- ```bash
701
- Copied migration [timestamp_1]_create_blorgh_posts.rb from blorgh
702
- Copied migration [timestamp_2]_create_blorgh_comments.rb from blorgh
703
- ```
704
-
705
- The first timestamp (`[timestamp_1]`) will be the current time, and the second
706
- timestamp (`[timestamp_2]`) will be the current time plus a second. The reason
707
- for this is so that the migrations for the engine are run after any existing
708
- migrations in the application.
709
-
710
- To run these migrations within the context of the application, simply run `rake
711
- db:migrate`. When accessing the engine through `http://localhost:3000/blog`, the
712
- posts will be empty. This is because the table created inside the application is
713
- different from the one created within the engine. Go ahead, play around with the
714
- newly mounted engine. You'll find that it's the same as when it was only an
715
- engine.
716
-
717
- If you would like to run migrations only from one engine, you can do it by
718
- specifying `SCOPE`:
719
-
720
- ```bash
721
- rake db:migrate SCOPE=blorgh
722
- ```
723
-
724
- This may be useful if you want to revert engine's migrations before removing it.
725
- To revert all migrations from blorgh engine you can run code such as:
726
-
727
- ```bash
728
- rake db:migrate SCOPE=blorgh VERSION=0
729
- ```
730
-
731
- ### Using a Class Provided by the Application
732
-
733
- #### Using a Model Provided by the Application
734
-
735
- When an engine is created, it may want to use specific classes from an
736
- application to provide links between the pieces of the engine and the pieces of
737
- the application. In the case of the `blorgh` engine, making posts and comments
738
- have authors would make a lot of sense.
739
-
740
- A typical application might have a `User` class that would be used to represent
741
- authors for a post or a comment. But there could be a case where the application
742
- calls this class something different, such as `Person`. For this reason, the
743
- engine should not hardcode associations specifically for a `User` class.
744
-
745
- To keep it simple in this case, the application will have a class called `User`
746
- that represents the users of the application. It can be generated using this
747
- command inside the 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 posts 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 post 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/posts/_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::PostController#post_params` method to
774
- permit the new form parameter:
775
-
776
- ```ruby
777
- def post_params
778
- params.require(:post).permit(:title, :text, :author_name)
779
- end
780
- ```
781
-
782
- The `Blorgh::Post` model should then have some code to convert the `author_name`
783
- field into an actual `User` object and associate it as that post's `author`
784
- before the post 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/post.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_posts` 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_posts` 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_posts 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
- $ bin/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_posts.rb from blorgh has been
833
- skipped. Migration with the same name already exists. NOTE Migration
834
- [timestamp]_create_blorgh_comments.rb from blorgh has been skipped. Migration
835
- with the same name already exists. Copied migration
836
- [timestamp]_add_author_id_to_blorgh_posts.rb from blorgh
837
- ```
838
-
839
- Run the migration using:
840
-
841
- ```bash
842
- $ bin/rake db:migrate
843
- ```
844
-
845
- Now with all the pieces in place, an action will take place that will associate
846
- an author - represented by a record in the `users` table - with a post,
847
- represented by the `blorgh_posts` table from the engine.
848
-
849
- Finally, the author's name should be displayed on the post's page. Add this code
850
- above the "Title" output inside `app/views/blorgh/posts/show.html.erb`:
851
-
852
- ```html+erb
853
- <p>
854
- <b>Author:</b>
855
- <%= @post.author %>
856
- </p>
857
- ```
858
-
859
- By outputting `@post.author` using the `<%=` tag, the `to_s` method will be
860
- called on the object. By default, this will look quite ugly:
861
-
862
- ```
863
- #<User:0x00000100ccb3b0>
864
- ```
865
-
866
- This is undesirable. It would be much better to have the user's name there. To
867
- do this, add a `to_s` method to the `User` class within the application:
868
-
869
- ```ruby
870
- def to_s
871
- name
872
- end
873
- ```
874
-
875
- Now instead of the ugly Ruby object output, the author's name will be displayed.
876
-
877
- #### Using a Controller Provided by the Application
878
-
879
- Because Rails controllers generally share code for things like authentication
880
- and accessing session variables, they inherit from `ApplicationController` by
881
- default. Rails engines, however are scoped to run independently from the main
882
- application, so each engine gets a scoped `ApplicationController`. This
883
- namespace prevents code collisions, but often engine controllers need to access
884
- methods in the main application's `ApplicationController`. An easy way to
885
- provide this access is to change the engine's scoped `ApplicationController` to
886
- inherit from the main application's `ApplicationController`. For our Blorgh
887
- engine this would be done by changing
888
- `app/controllers/blorgh/application_controller.rb` to look like:
889
-
890
- ```ruby
891
- class Blorgh::ApplicationController < ApplicationController
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::Post` model over to this new setting.
929
- Change the `belongs_to` association inside this model
930
- (`app/models/blorgh/post.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::Post` 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::Post`
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 post. 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 a post 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
- get :index
1040
- ```
1041
-
1042
- It may not function correctly. This is because the application doesn't know how
1043
- to route these requests to the engine unless you explicitly tell it **how**. To
1044
- do this, you must also pass the `:use_route` option as a parameter on these
1045
- requests:
1046
-
1047
- ```ruby
1048
- get :index, use_route: :blorgh
1049
- ```
1050
-
1051
- This tells the application that you still want to perform a `GET` request to the
1052
- `index` action of this controller, but you want to use the engine's route to get
1053
- there, rather than the application's one.
1054
-
1055
- Improving engine functionality
1056
- ------------------------------
1057
-
1058
- This section explains how to add and/or override engine MVC functionality in the
1059
- main Rails application.
1060
-
1061
- ### Overriding Models and Controllers
1062
-
1063
- Engine model and controller classes can be extended by open classing them in the
1064
- main Rails application (since model and controller classes are just Ruby classes
1065
- that inherit Rails specific functionality). Open classing an Engine class
1066
- redefines it for use in the main application. This is usually implemented by
1067
- using the decorator pattern.
1068
-
1069
- For simple class modifications, use `Class#class_eval`. For complex class
1070
- modifications, consider using `ActiveSupport::Concern`.
1071
-
1072
- #### A note on Decorators and Loading Code
1073
-
1074
- Because these decorators are not referenced by your Rails application itself,
1075
- Rails' autoloading system will not kick in and load your decorators. This means
1076
- that you need to require them yourself.
1077
-
1078
- Here is some sample code to do this:
1079
-
1080
- ```ruby
1081
- # lib/blorgh/engine.rb
1082
- module Blorgh
1083
- class Engine < ::Rails::Engine
1084
- isolate_namespace Blorgh
1085
-
1086
- config.to_prepare do
1087
- Dir.glob(Rails.root + "app/decorators/**/*_decorator*.rb").each do |c|
1088
- require_dependency(c)
1089
- end
1090
- end
1091
- end
1092
- end
1093
- ```
1094
-
1095
- This doesn't apply to just Decorators, but anything that you add in an engine
1096
- that isn't referenced by your main application.
1097
-
1098
- #### Implementing Decorator Pattern Using Class#class_eval
1099
-
1100
- **Adding** `Post#time_since_created`:
1101
-
1102
- ```ruby
1103
- # MyApp/app/decorators/models/blorgh/post_decorator.rb
1104
-
1105
- Blorgh::Post.class_eval do
1106
- def time_since_created
1107
- Time.current - created_at
1108
- end
1109
- end
1110
- ```
1111
-
1112
- ```ruby
1113
- # Blorgh/app/models/post.rb
1114
-
1115
- class Post < ActiveRecord::Base
1116
- has_many :comments
1117
- end
1118
- ```
1119
-
1120
-
1121
- **Overriding** `Post#summary`:
1122
-
1123
- ```ruby
1124
- # MyApp/app/decorators/models/blorgh/post_decorator.rb
1125
-
1126
- Blorgh::Post.class_eval do
1127
- def summary
1128
- "#{title} - #{truncate(text)}"
1129
- end
1130
- end
1131
- ```
1132
-
1133
- ```ruby
1134
- # Blorgh/app/models/post.rb
1135
-
1136
- class Post < ActiveRecord::Base
1137
- has_many :comments
1138
- def summary
1139
- "#{title}"
1140
- end
1141
- end
1142
- ```
1143
-
1144
- #### Implementing Decorator Pattern Using ActiveSupport::Concern
1145
-
1146
- Using `Class#class_eval` is great for simple adjustments, but for more complex
1147
- class modifications, you might want to consider using [`ActiveSupport::Concern`]
1148
- (http://edgeapi.rubyonrails.org/classes/ActiveSupport/Concern.html).
1149
- ActiveSupport::Concern manages load order of interlinked dependent modules and
1150
- classes at run time allowing you to significantly modularize your code.
1151
-
1152
- **Adding** `Post#time_since_created` and **Overriding** `Post#summary`:
1153
-
1154
- ```ruby
1155
- # MyApp/app/models/blorgh/post.rb
1156
-
1157
- class Blorgh::Post < ActiveRecord::Base
1158
- include Blorgh::Concerns::Models::Post
1159
-
1160
- def time_since_created
1161
- Time.current - created_at
1162
- end
1163
-
1164
- def summary
1165
- "#{title} - #{truncate(text)}"
1166
- end
1167
- end
1168
- ```
1169
-
1170
- ```ruby
1171
- # Blorgh/app/models/post.rb
1172
-
1173
- class Post < ActiveRecord::Base
1174
- include Blorgh::Concerns::Models::Post
1175
- end
1176
- ```
1177
-
1178
- ```ruby
1179
- # Blorgh/lib/concerns/models/post
1180
-
1181
- module Blorgh::Concerns::Models::Post
1182
- extend ActiveSupport::Concern
1183
-
1184
- # 'included do' causes the included code to be evaluated in the
1185
- # context where it is included (post.rb), rather than being
1186
- # executed in the module's context (blorgh/concerns/models/post).
1187
- included do
1188
- attr_accessor :author_name
1189
- belongs_to :author, class_name: "User"
1190
-
1191
- before_save :set_author
1192
-
1193
- private
1194
- def set_author
1195
- self.author = User.find_or_create_by(name: author_name)
1196
- end
1197
- end
1198
-
1199
- def summary
1200
- "#{title}"
1201
- end
1202
-
1203
- module ClassMethods
1204
- def some_class_method
1205
- 'some class method string'
1206
- end
1207
- end
1208
- end
1209
- ```
1210
-
1211
- ### Overriding Views
1212
-
1213
- When Rails looks for a view to render, it will first look in the `app/views`
1214
- directory of the application. If it cannot find the view there, it will check in
1215
- the `app/views` directories of all engines that have this directory.
1216
-
1217
- When the application is asked to render the view for `Blorgh::PostsController`'s
1218
- index action, it will first look for the path
1219
- `app/views/blorgh/posts/index.html.erb` within the application. If it cannot
1220
- find it, it will look inside the engine.
1221
-
1222
- You can override this view in the application by simply creating a new file at
1223
- `app/views/blorgh/posts/index.html.erb`. Then you can completely change what
1224
- this view would normally output.
1225
-
1226
- Try this now by creating a new file at `app/views/blorgh/posts/index.html.erb`
1227
- and put this content in it:
1228
-
1229
- ```html+erb
1230
- <h1>Posts</h1>
1231
- <%= link_to "New Post", new_post_path %>
1232
- <% @posts.each do |post| %>
1233
- <h2><%= post.title %></h2>
1234
- <small>By <%= post.author %></small>
1235
- <%= simple_format(post.text) %>
1236
- <hr>
1237
- <% end %>
1238
- ```
1239
-
1240
- ### Routes
1241
-
1242
- Routes inside an engine are isolated from the application by default. This is
1243
- done by the `isolate_namespace` call inside the `Engine` class. This essentially
1244
- means that the application and its engines can have identically named routes and
1245
- they will not clash.
1246
-
1247
- Routes inside an engine are drawn on the `Engine` class within
1248
- `config/routes.rb`, like this:
1249
-
1250
- ```ruby
1251
- Blorgh::Engine.routes.draw do
1252
- resources :posts
1253
- end
1254
- ```
1255
-
1256
- By having isolated routes such as this, if you wish to link to an area of an
1257
- engine from within an application, you will need to use the engine's routing
1258
- proxy method. Calls to normal routing methods such as `posts_path` may end up
1259
- going to undesired locations if both the application and the engine have such a
1260
- helper defined.
1261
-
1262
- For instance, the following example would go to the application's `posts_path`
1263
- if that template was rendered from the application, or the engine's `posts_path`
1264
- if it was rendered from the engine:
1265
-
1266
- ```erb
1267
- <%= link_to "Blog posts", posts_path %>
1268
- ```
1269
-
1270
- To make this route always use the engine's `posts_path` routing helper method,
1271
- we must call the method on the routing proxy method that shares the same name as
1272
- the engine.
1273
-
1274
- ```erb
1275
- <%= link_to "Blog posts", blorgh.posts_path %>
1276
- ```
1277
-
1278
- If you wish to reference the application inside the engine in a similar way, use
1279
- the `main_app` helper:
1280
-
1281
- ```erb
1282
- <%= link_to "Home", main_app.root_path %>
1283
- ```
1284
-
1285
- If you were to use this inside an engine, it would **always** go to the
1286
- application's root. If you were to leave off the `main_app` "routing proxy"
1287
- method call, it could potentially go to the engine's or application's root,
1288
- depending on where it was called from.
1289
-
1290
- If a template rendered from within an engine attempts to use one of the
1291
- application's routing helper methods, it may result in an undefined method call.
1292
- If you encounter such an issue, ensure that you're not attempting to call the
1293
- application's routing methods without the `main_app` prefix from within the
1294
- engine.
1295
-
1296
- ### Assets
1297
-
1298
- Assets within an engine work in an identical way to a full application. Because
1299
- the engine class inherits from `Rails::Engine`, the application will know to
1300
- look up assets in the engine's 'app/assets' and 'lib/assets' directories.
1301
-
1302
- Like all of the other components of an engine, the assets should be namespaced.
1303
- This means that if you have an asset called `style.css`, it should be placed at
1304
- `app/assets/stylesheets/[engine name]/style.css`, rather than
1305
- `app/assets/stylesheets/style.css`. If this asset isn't namespaced, there is a
1306
- possibility that the host application could have an asset named identically, in
1307
- which case the application's asset would take precedence and the engine's one
1308
- would be ignored.
1309
-
1310
- Imagine that you did have an asset located at
1311
- `app/assets/stylesheets/blorgh/style.css` To include this asset inside an
1312
- application, just use `stylesheet_link_tag` and reference the asset as if it
1313
- were inside the engine:
1314
-
1315
- ```erb
1316
- <%= stylesheet_link_tag "blorgh/style.css" %>
1317
- ```
1318
-
1319
- You can also specify these assets as dependencies of other assets using Asset
1320
- Pipeline require statements in processed files:
1321
-
1322
- ```
1323
- /*
1324
- *= require blorgh/style
1325
- */
1326
- ```
1327
-
1328
- INFO. Remember that in order to use languages like Sass or CoffeeScript, you
1329
- should add the relevant library to your engine's `.gemspec`.
1330
-
1331
- ### Separate Assets & Precompiling
1332
-
1333
- There are some situations where your engine's assets are not required by the
1334
- host application. For example, say that you've created an admin functionality
1335
- that only exists for your engine. In this case, the host application doesn't
1336
- need to require `admin.css` or `admin.js`. Only the gem's admin layout needs
1337
- these assets. It doesn't make sense for the host app to include
1338
- `"blorgh/admin.css"` in its stylesheets. In this situation, you should
1339
- explicitly define these assets for precompilation. This tells sprockets to add
1340
- your engine assets when `rake assets:precompile` is triggered.
1341
-
1342
- You can define assets for precompilation in `engine.rb`:
1343
-
1344
- ```ruby
1345
- initializer "blorgh.assets.precompile" do |app|
1346
- app.config.assets.precompile += %w(admin.css admin.js)
1347
- end
1348
- ```
1349
-
1350
- For more information, read the [Asset Pipeline guide](asset_pipeline.html).
1351
-
1352
- ### Other Gem Dependencies
1353
-
1354
- Gem dependencies inside an engine should be specified inside the `.gemspec` file
1355
- at the root of the engine. The reason is that the engine may be installed as a
1356
- gem. If dependencies were to be specified inside the `Gemfile`, these would not
1357
- be recognized by a traditional gem install and so they would not be installed,
1358
- causing the engine to malfunction.
1359
-
1360
- To specify a dependency that should be installed with the engine during a
1361
- traditional `gem install`, specify it inside the `Gem::Specification` block
1362
- inside the `.gemspec` file in the engine:
1363
-
1364
- ```ruby
1365
- s.add_dependency "moo"
1366
- ```
1367
-
1368
- To specify a dependency that should only be installed as a development
1369
- dependency of the application, specify it like this:
1370
-
1371
- ```ruby
1372
- s.add_development_dependency "moo"
1373
- ```
1374
-
1375
- Both kinds of dependencies will be installed when `bundle install` is run inside
1376
- of the application. The development dependencies for the gem will only be used
1377
- when the tests for the engine are running.
1378
-
1379
- Note that if you want to immediately require dependencies when the engine is
1380
- required, you should require them before the engine's initialization. For
1381
- example:
1382
-
1383
- ```ruby
1384
- require 'other_engine/engine'
1385
- require 'yet_another_engine/engine'
1386
-
1387
- module MyEngine
1388
- class Engine < ::Rails::Engine
1389
- end
1390
- end
1391
- ```