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