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