rails 4.0.13 → 4.1.16
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +22 -17
- data/guides/CHANGELOG.md +68 -34
- 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 +30 -34
- data/guides/assets/stylesheets/main.css +2 -1
- data/guides/assets/stylesheets/print.css +1 -1
- data/guides/bug_report_templates/action_controller_gem.rb +9 -4
- data/guides/bug_report_templates/action_controller_master.rb +4 -2
- data/guides/bug_report_templates/active_record_gem.rb +5 -2
- data/guides/bug_report_templates/active_record_master.rb +2 -1
- data/guides/bug_report_templates/generic_gem.rb +15 -0
- data/guides/bug_report_templates/generic_master.rb +26 -0
- data/guides/code/getting_started/Gemfile +21 -24
- data/guides/code/getting_started/Gemfile.lock +78 -73
- data/guides/code/getting_started/Rakefile +1 -1
- data/guides/code/getting_started/app/assets/javascripts/application.js +1 -2
- data/guides/code/getting_started/app/views/layouts/application.html.erb +2 -2
- data/guides/code/getting_started/config/environment.rb +1 -1
- data/guides/code/getting_started/config/environments/development.rb +2 -2
- data/guides/code/getting_started/config/environments/production.rb +3 -3
- data/guides/code/getting_started/config/environments/test.rb +2 -2
- data/guides/code/getting_started/config/initializers/secret_token.rb +1 -1
- data/guides/code/getting_started/config/initializers/session_store.rb +1 -1
- data/guides/code/getting_started/config/routes.rb +1 -1
- data/guides/code/getting_started/config.ru +1 -1
- data/guides/code/getting_started/public/404.html +2 -0
- data/guides/code/getting_started/public/422.html +2 -0
- data/guides/code/getting_started/public/500.html +2 -0
- data/guides/code/getting_started/test/test_helper.rb +0 -3
- data/guides/rails_guides/helpers.rb +3 -1
- data/guides/source/2_2_release_notes.md +2 -2
- data/guides/source/2_3_release_notes.md +8 -8
- data/guides/source/3_0_release_notes.md +2 -3
- data/guides/source/3_1_release_notes.md +2 -2
- data/guides/source/3_2_release_notes.md +12 -12
- data/guides/source/4_0_release_notes.md +79 -46
- data/guides/source/4_1_release_notes.md +731 -0
- data/guides/source/_welcome.html.erb +5 -2
- data/guides/source/action_controller_overview.md +189 -40
- data/guides/source/action_mailer_basics.md +27 -27
- data/guides/source/action_view_overview.md +131 -20
- data/guides/source/active_model_basics.md +6 -6
- data/guides/source/active_record_basics.md +15 -15
- data/guides/source/active_record_callbacks.md +18 -16
- data/guides/source/active_record_querying.md +93 -51
- data/guides/source/active_record_validations.md +26 -24
- data/guides/source/active_support_core_extensions.md +72 -118
- data/guides/source/active_support_instrumentation.md +13 -4
- data/guides/source/api_documentation_guidelines.md +104 -6
- data/guides/source/asset_pipeline.md +573 -244
- data/guides/source/association_basics.md +94 -22
- data/guides/source/caching_with_rails.md +15 -6
- data/guides/source/command_line.md +55 -46
- data/guides/source/configuring.md +248 -52
- data/guides/source/contributing_to_ruby_on_rails.md +18 -17
- data/guides/source/credits.html.erb +2 -2
- data/guides/source/debugging_rails_applications.md +39 -8
- data/guides/source/development_dependencies_install.md +91 -8
- data/guides/source/documents.yaml +4 -0
- data/guides/source/engines.md +678 -232
- data/guides/source/form_helpers.md +53 -35
- data/guides/source/generators.md +19 -15
- data/guides/source/getting_started.md +758 -497
- data/guides/source/i18n.md +64 -28
- data/guides/source/index.html.erb +1 -1
- data/guides/source/initialization.md +155 -58
- data/guides/source/kindle/toc.html.erb +1 -1
- data/guides/source/layout.html.erb +2 -2
- data/guides/source/layouts_and_rendering.md +59 -26
- data/guides/source/maintenance_policy.md +3 -3
- data/guides/source/migrations.md +101 -62
- data/guides/source/nested_model_forms.md +3 -3
- data/guides/source/plugins.md +34 -31
- data/guides/source/rails_application_templates.md +27 -8
- data/guides/source/rails_on_rack.md +41 -58
- data/guides/source/routing.md +115 -104
- data/guides/source/ruby_on_rails_guides_guidelines.md +2 -2
- data/guides/source/security.md +81 -36
- data/guides/source/testing.md +56 -79
- data/guides/source/upgrading_ruby_on_rails.md +531 -21
- data/guides/source/working_with_javascript_in_rails.md +19 -11
- metadata +51 -23
- 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/source/kindle/KINDLE.md +0 -26
@@ -21,19 +21,22 @@ application from scratch. It does not assume that you have any prior experience
|
|
21
21
|
with Rails. However, to get the most out of it, you need to have some
|
22
22
|
prerequisites installed:
|
23
23
|
|
24
|
-
* The [Ruby](http://www.ruby-lang.org/en/downloads) language version 1.9.3 or newer
|
25
|
-
* The [RubyGems](http://rubygems.org
|
26
|
-
|
27
|
-
* A working installation of the [SQLite3 Database](http://www.sqlite.org)
|
24
|
+
* The [Ruby](http://www.ruby-lang.org/en/downloads) language version 1.9.3 or newer.
|
25
|
+
* The [RubyGems](http://rubygems.org) packaging system, which is installed with Ruby
|
26
|
+
versions 1.9 and later. To learn more about RubyGems, please read the [RubyGems Guides](http://guides.rubygems.org).
|
27
|
+
* A working installation of the [SQLite3 Database](http://www.sqlite.org).
|
28
28
|
|
29
29
|
Rails is a web application framework running on the Ruby programming language.
|
30
30
|
If you have no prior experience with Ruby, you will find a very steep learning
|
31
|
-
curve diving straight into Rails. There are
|
32
|
-
|
31
|
+
curve diving straight into Rails. There are several curated lists of online resources
|
32
|
+
for learning Ruby:
|
33
33
|
|
34
|
-
* [
|
35
|
-
* [Programming
|
36
|
-
|
34
|
+
* [Official Ruby Programming Language website](https://www.ruby-lang.org/en/documentation/)
|
35
|
+
* [reSRC's List of Free Programming Books](http://resrc.io/list/10/list-of-free-programming-books/#ruby)
|
36
|
+
|
37
|
+
Be aware that some resources, while still excellent, cover versions of Ruby as old as
|
38
|
+
1.6, and commonly 1.8, and will not include some syntax that you will see in day-to-day
|
39
|
+
development with Rails.
|
37
40
|
|
38
41
|
What is Rails?
|
39
42
|
--------------
|
@@ -54,9 +57,13 @@ learned elsewhere, you may have a less happy experience.
|
|
54
57
|
|
55
58
|
The Rails philosophy includes two major guiding principles:
|
56
59
|
|
57
|
-
*
|
58
|
-
|
59
|
-
|
60
|
+
* **Don't Repeat Yourself:** DRY is a principle of software development which
|
61
|
+
states that "Every piece of knowledge must have a single, unambiguous, authoritative
|
62
|
+
representation within a system." By not writing the same information over and over
|
63
|
+
again, our code is more maintainable, more extensible, and less buggy.
|
64
|
+
* **Convention Over Configuration:** Rails has opinions about the best way to do many
|
65
|
+
things in a web application, and defaults to this set of conventions, rather than
|
66
|
+
require that you specify every minutiae through endless configuration files.
|
60
67
|
|
61
68
|
Creating a New Rails Project
|
62
69
|
----------------------------
|
@@ -70,9 +77,9 @@ By following along with this guide, you'll create a Rails project called
|
|
70
77
|
(very) simple weblog. Before you can start building the application, you need to
|
71
78
|
make sure that you have Rails itself installed.
|
72
79
|
|
73
|
-
TIP: The examples below use
|
74
|
-
|
75
|
-
|
80
|
+
TIP: The examples below use `$` to represent your terminal prompt in a UNIX-like OS,
|
81
|
+
though it may have been customized to appear differently. If you are using Windows,
|
82
|
+
your prompt will look something like `c:\source_code>`
|
76
83
|
|
77
84
|
### Installing Rails
|
78
85
|
|
@@ -81,114 +88,168 @@ Open up a command line prompt. On Mac OS X open Terminal.app, on Windows choose
|
|
81
88
|
dollar sign `$` should be run in the command line. Verify that you have a
|
82
89
|
current version of Ruby installed:
|
83
90
|
|
91
|
+
TIP. A number of tools exist to help you quickly install Ruby and Ruby
|
92
|
+
on Rails on your system. Windows users can use [Rails Installer](http://railsinstaller.org),
|
93
|
+
while Mac OS X users can use [Tokaido](https://github.com/tokaido/tokaidoapp).
|
94
|
+
|
84
95
|
```bash
|
85
96
|
$ ruby -v
|
86
|
-
ruby
|
97
|
+
ruby 2.0.0p353
|
87
98
|
```
|
88
99
|
|
100
|
+
If you don't have Ruby installed have a look at
|
101
|
+
[ruby-lang.org](https://www.ruby-lang.org/en/downloads/) for possible ways to
|
102
|
+
install Ruby on your platform.
|
103
|
+
|
104
|
+
Many popular UNIX-like OSes ship with an acceptable version of SQLite3. Windows
|
105
|
+
users and others can find installation instructions at [the SQLite3 website](http://www.sqlite.org).
|
106
|
+
Verify that it is correctly installed and in your PATH:
|
107
|
+
|
108
|
+
```bash
|
109
|
+
$ sqlite3 --version
|
110
|
+
```
|
111
|
+
|
112
|
+
The program should report its version.
|
113
|
+
|
89
114
|
To install Rails, use the `gem install` command provided by RubyGems:
|
90
115
|
|
91
116
|
```bash
|
92
117
|
$ gem install rails
|
93
118
|
```
|
94
119
|
|
95
|
-
|
96
|
-
|
97
|
-
[Rails One Click](http://railsoneclick.com).
|
98
|
-
|
99
|
-
To verify that you have everything installed correctly, you should be able to run the following:
|
120
|
+
To verify that you have everything installed correctly, you should be able to
|
121
|
+
run the following:
|
100
122
|
|
101
123
|
```bash
|
102
|
-
$ rails --version
|
124
|
+
$ bin/rails --version
|
103
125
|
```
|
104
126
|
|
105
|
-
If it says something like "Rails 4.
|
127
|
+
If it says something like "Rails 4.1.1", you are ready to continue.
|
106
128
|
|
107
129
|
### Creating the Blog Application
|
108
130
|
|
109
|
-
Rails comes with a number of scripts called generators that are designed to make
|
131
|
+
Rails comes with a number of scripts called generators that are designed to make
|
132
|
+
your development life easier by creating everything that's necessary to start
|
133
|
+
working on a particular task. One of these is the new application generator,
|
134
|
+
which will provide you with the foundation of a fresh Rails application so that
|
135
|
+
you don't have to write it yourself.
|
110
136
|
|
111
|
-
To use this generator, open a terminal, navigate to a directory where you have
|
137
|
+
To use this generator, open a terminal, navigate to a directory where you have
|
138
|
+
rights to create files, and type:
|
112
139
|
|
113
140
|
```bash
|
114
141
|
$ rails new blog
|
115
142
|
```
|
116
143
|
|
117
|
-
This will create a Rails application called Blog in a
|
144
|
+
This will create a Rails application called Blog in a `blog` directory and
|
145
|
+
install the gem dependencies that are already mentioned in `Gemfile` using
|
146
|
+
`bundle install`.
|
118
147
|
|
119
|
-
TIP: You can see all of the command line options that the Rails
|
120
|
-
|
148
|
+
TIP: You can see all of the command line options that the Rails application
|
149
|
+
builder accepts by running `rails new -h`.
|
121
150
|
|
122
|
-
After you create the blog application, switch to its folder
|
151
|
+
After you create the blog application, switch to its folder:
|
123
152
|
|
124
153
|
```bash
|
125
154
|
$ cd blog
|
126
155
|
```
|
127
156
|
|
128
|
-
The `
|
129
|
-
|
130
|
-
|
131
|
-
|
157
|
+
The `blog` directory has a number of auto-generated files and folders that make
|
158
|
+
up the structure of a Rails application. Most of the work in this tutorial will
|
159
|
+
happen in the `app` folder, but here's a basic rundown on the function of each
|
160
|
+
of the files and folders that Rails created by default:
|
132
161
|
|
133
162
|
| File/Folder | Purpose |
|
134
163
|
| ----------- | ------- |
|
135
164
|
|app/|Contains the controllers, models, views, helpers, mailers and assets for your application. You'll focus on this folder for the remainder of this guide.|
|
136
165
|
|bin/|Contains the rails script that starts your app and can contain other scripts you use to deploy or run your application.|
|
137
|
-
|config/|Configure your application's
|
166
|
+
|config/|Configure your application's routes, database, and more. This is covered in more detail in [Configuring Rails Applications](configuring.html).|
|
138
167
|
|config.ru|Rack configuration for Rack based servers used to start the application.|
|
139
168
|
|db/|Contains your current database schema, as well as the database migrations.|
|
140
|
-
|Gemfile<br
|
169
|
+
|Gemfile<br>Gemfile.lock|These files allow you to specify what gem dependencies are needed for your Rails application. These files are used by the Bundler gem. For more information about Bundler, see [the Bundler website](http://gembundler.com).|
|
141
170
|
|lib/|Extended modules for your application.|
|
142
171
|
|log/|Application log files.|
|
143
|
-
|public/|The only folder seen
|
172
|
+
|public/|The only folder seen by the world as-is. Contains static files and compiled assets.|
|
144
173
|
|Rakefile|This file locates and loads tasks that can be run from the command line. The task definitions are defined throughout the components of Rails. Rather than changing Rakefile, you should add your own tasks by adding files to the lib/tasks directory of your application.|
|
145
174
|
|README.rdoc|This is a brief instruction manual for your application. You should edit this file to tell others what your application does, how to set it up, and so on.|
|
146
|
-
|test/|Unit tests, fixtures, and other test apparatus. These are covered in [Testing Rails Applications](testing.html)
|
147
|
-
|tmp/|Temporary files (like cache, pid and session files)
|
148
|
-
|vendor/|A place for all third-party code. In a typical Rails application
|
175
|
+
|test/|Unit tests, fixtures, and other test apparatus. These are covered in [Testing Rails Applications](testing.html).|
|
176
|
+
|tmp/|Temporary files (like cache, pid, and session files).|
|
177
|
+
|vendor/|A place for all third-party code. In a typical Rails application this includes vendored gems.|
|
149
178
|
|
150
179
|
Hello, Rails!
|
151
180
|
-------------
|
152
181
|
|
153
|
-
To begin with, let's get some text up on screen quickly. To do this, you need to
|
182
|
+
To begin with, let's get some text up on screen quickly. To do this, you need to
|
183
|
+
get your Rails application server running.
|
154
184
|
|
155
185
|
### Starting up the Web Server
|
156
186
|
|
157
|
-
You actually have a functional Rails application already. To see it, you need to
|
187
|
+
You actually have a functional Rails application already. To see it, you need to
|
188
|
+
start a web server on your development machine. You can do this by running the
|
189
|
+
following in the `blog` directory:
|
158
190
|
|
159
191
|
```bash
|
160
|
-
$ rails server
|
192
|
+
$ bin/rails server
|
161
193
|
```
|
162
194
|
|
163
|
-
TIP: Compiling CoffeeScript to JavaScript requires a JavaScript runtime and the
|
195
|
+
TIP: Compiling CoffeeScript to JavaScript requires a JavaScript runtime and the
|
196
|
+
absence of a runtime will give you an `execjs` error. Usually Mac OS X and
|
197
|
+
Windows come with a JavaScript runtime installed. Rails adds the `therubyracer`
|
198
|
+
gem to the generated `Gemfile` in a commented line for new apps and you can
|
199
|
+
uncomment if you need it. `therubyrhino` is the recommended runtime for JRuby
|
200
|
+
users and is added by default to the `Gemfile` in apps generated under JRuby.
|
201
|
+
You can investigate about all the supported runtimes at
|
202
|
+
[ExecJS](https://github.com/rails/execjs#readme).
|
164
203
|
|
165
|
-
This will fire up WEBrick, a
|
204
|
+
This will fire up WEBrick, a web server distributed with Ruby by default. To see
|
205
|
+
your application in action, open a browser window and navigate to
|
206
|
+
<http://localhost:3000>. You should see the Rails default information page:
|
166
207
|
|
167
|
-
![Welcome
|
208
|
+
![Welcome aboard screenshot](images/getting_started/rails_welcome.png)
|
168
209
|
|
169
|
-
TIP: To stop the web server, hit Ctrl+C in the terminal window where it's
|
210
|
+
TIP: To stop the web server, hit Ctrl+C in the terminal window where it's
|
211
|
+
running. To verify the server has stopped you should see your command prompt
|
212
|
+
cursor again. For most UNIX-like systems including Mac OS X this will be a
|
213
|
+
dollar sign `$`. In development mode, Rails does not generally require you to
|
214
|
+
restart the server; changes you make in files will be automatically picked up by
|
215
|
+
the server.
|
170
216
|
|
171
|
-
The "Welcome
|
217
|
+
The "Welcome aboard" page is the _smoke test_ for a new Rails application: it
|
218
|
+
makes sure that you have your software configured correctly enough to serve a
|
219
|
+
page. You can also click on the _About your application's environment_ link to
|
220
|
+
see a summary of your application's environment.
|
172
221
|
|
173
222
|
### Say "Hello", Rails
|
174
223
|
|
175
|
-
To get Rails saying "Hello", you need to create at minimum a _controller_ and a
|
224
|
+
To get Rails saying "Hello", you need to create at minimum a _controller_ and a
|
225
|
+
_view_.
|
176
226
|
|
177
|
-
A controller's purpose is to receive specific requests for the application.
|
227
|
+
A controller's purpose is to receive specific requests for the application.
|
228
|
+
_Routing_ decides which controller receives which requests. Often, there is more
|
229
|
+
than one route to each controller, and different routes can be served by
|
230
|
+
different _actions_. Each action's purpose is to collect information to provide
|
231
|
+
it to a view.
|
178
232
|
|
179
|
-
A view's purpose is to display this information in a human readable format. An
|
233
|
+
A view's purpose is to display this information in a human readable format. An
|
234
|
+
important distinction to make is that it is the _controller_, not the view,
|
235
|
+
where information is collected. The view should just display that information.
|
236
|
+
By default, view templates are written in a language called eRuby (Embedded
|
237
|
+
Ruby) which is processed by the request cycle in Rails before being sent to the
|
238
|
+
user.
|
180
239
|
|
181
|
-
To create a new controller, you will need to run the "controller" generator and
|
240
|
+
To create a new controller, you will need to run the "controller" generator and
|
241
|
+
tell it you want a controller called "welcome" with an action called "index",
|
242
|
+
just like this:
|
182
243
|
|
183
244
|
```bash
|
184
|
-
$ rails generate controller welcome index
|
245
|
+
$ bin/rails generate controller welcome index
|
185
246
|
```
|
186
247
|
|
187
248
|
Rails will create several files and a route for you.
|
188
249
|
|
189
250
|
```bash
|
190
251
|
create app/controllers/welcome_controller.rb
|
191
|
-
route get
|
252
|
+
route get 'welcome/index'
|
192
253
|
invoke erb
|
193
254
|
create app/views/welcome
|
194
255
|
create app/views/welcome/index.html.erb
|
@@ -205,9 +266,12 @@ invoke scss
|
|
205
266
|
create app/assets/stylesheets/welcome.css.scss
|
206
267
|
```
|
207
268
|
|
208
|
-
Most important of these are of course the controller, located at `app/controllers/welcome_controller.rb`
|
269
|
+
Most important of these are of course the controller, located at `app/controllers/welcome_controller.rb`
|
270
|
+
and the view, located at `app/views/welcome/index.html.erb`.
|
209
271
|
|
210
|
-
Open the `app/views/welcome/index.html.erb` file in your text editor. Delete all
|
272
|
+
Open the `app/views/welcome/index.html.erb` file in your text editor. Delete all
|
273
|
+
of the existing code in the file, and replace it with the following single line
|
274
|
+
of code:
|
211
275
|
|
212
276
|
```html
|
213
277
|
<h1>Hello, Rails!</h1>
|
@@ -215,152 +279,229 @@ Open the `app/views/welcome/index.html.erb` file in your text editor. Delete all
|
|
215
279
|
|
216
280
|
### Setting the Application Home Page
|
217
281
|
|
218
|
-
Now that we have made the controller and view, we need to tell Rails when we
|
282
|
+
Now that we have made the controller and view, we need to tell Rails when we
|
283
|
+
want "Hello, Rails!" to show up. In our case, we want it to show up when we
|
284
|
+
navigate to the root URL of our site, <http://localhost:3000>. At the moment,
|
285
|
+
"Welcome aboard" is occupying that spot.
|
219
286
|
|
220
287
|
Next, you have to tell Rails where your actual home page is located.
|
221
288
|
|
222
289
|
Open the file `config/routes.rb` in your editor.
|
223
290
|
|
224
291
|
```ruby
|
225
|
-
|
226
|
-
get
|
292
|
+
Rails.application.routes.draw do
|
293
|
+
get 'welcome/index'
|
227
294
|
|
228
295
|
# The priority is based upon order of creation:
|
229
296
|
# first created -> highest priority.
|
230
|
-
#
|
297
|
+
#
|
231
298
|
# You can have the root of your site routed with "root"
|
232
|
-
# root
|
299
|
+
# root 'welcome#index'
|
300
|
+
#
|
301
|
+
# ...
|
233
302
|
```
|
234
303
|
|
235
|
-
This is your application's _routing file_ which holds entries in a special DSL
|
304
|
+
This is your application's _routing file_ which holds entries in a special DSL
|
305
|
+
(domain-specific language) that tells Rails how to connect incoming requests to
|
306
|
+
controllers and actions. This file contains many sample routes on commented
|
307
|
+
lines, and one of them actually shows you how to connect the root of your site
|
308
|
+
to a specific controller and action. Find the line beginning with `root` and
|
309
|
+
uncomment it. It should look something like the following:
|
236
310
|
|
237
311
|
```ruby
|
238
|
-
root
|
312
|
+
root 'welcome#index'
|
239
313
|
```
|
240
314
|
|
241
|
-
|
315
|
+
`root 'welcome#index'` tells Rails to map requests to the root of the
|
316
|
+
application to the welcome controller's index action and `get 'welcome/index'`
|
317
|
+
tells Rails to map requests to <http://localhost:3000/welcome/index> to the
|
318
|
+
welcome controller's index action. This was created earlier when you ran the
|
319
|
+
controller generator (`rails generate controller welcome index`).
|
242
320
|
|
243
|
-
|
321
|
+
Launch the web server again if you stopped it to generate the controller (`rails
|
322
|
+
server`) and navigate to <http://localhost:3000> in your browser. You'll see the
|
323
|
+
"Hello, Rails!" message you put into `app/views/welcome/index.html.erb`,
|
324
|
+
indicating that this new route is indeed going to `WelcomeController`'s `index`
|
325
|
+
action and is rendering the view correctly.
|
244
326
|
|
245
327
|
TIP: For more information about routing, refer to [Rails Routing from the Outside In](routing.html).
|
246
328
|
|
247
329
|
Getting Up and Running
|
248
330
|
----------------------
|
249
331
|
|
250
|
-
Now that you've seen how to create a controller, an action and a view, let's
|
332
|
+
Now that you've seen how to create a controller, an action and a view, let's
|
333
|
+
create something with a bit more substance.
|
251
334
|
|
252
|
-
In the Blog application, you will now create a new _resource_. A resource is the
|
335
|
+
In the Blog application, you will now create a new _resource_. A resource is the
|
336
|
+
term used for a collection of similar objects, such as articles, people or
|
337
|
+
animals.
|
338
|
+
You can create, read, update and destroy items for a resource and these
|
339
|
+
operations are referred to as _CRUD_ operations.
|
253
340
|
|
254
|
-
Rails provides a `resources` method which can be used to declare a
|
255
|
-
|
341
|
+
Rails provides a `resources` method which can be used to declare a standard REST
|
342
|
+
resource. Here's what `config/routes.rb` should look like after the
|
343
|
+
_article resource_ is declared.
|
256
344
|
|
257
345
|
```ruby
|
258
|
-
|
346
|
+
Rails.application.routes.draw do
|
259
347
|
|
260
|
-
resources :
|
348
|
+
resources :articles
|
261
349
|
|
262
|
-
root
|
350
|
+
root 'welcome#index'
|
263
351
|
end
|
264
352
|
```
|
265
353
|
|
266
|
-
If you run `rake routes`, you'll see that
|
267
|
-
standard RESTful actions.
|
354
|
+
If you run `rake routes`, you'll see that it has defined routes for all the
|
355
|
+
standard RESTful actions. The meaning of the prefix column (and other columns)
|
356
|
+
will be seen later, but for now notice that Rails has inferred the
|
357
|
+
singular form `article` and makes meaningful use of the distinction.
|
268
358
|
|
269
359
|
```bash
|
270
|
-
$ rake routes
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
360
|
+
$ bin/rake routes
|
361
|
+
Prefix Verb URI Pattern Controller#Action
|
362
|
+
articles GET /articles(.:format) articles#index
|
363
|
+
POST /articles(.:format) articles#create
|
364
|
+
new_article GET /articles/new(.:format) articles#new
|
365
|
+
edit_article GET /articles/:id/edit(.:format) articles#edit
|
366
|
+
article GET /articles/:id(.:format) articles#show
|
367
|
+
PATCH /articles/:id(.:format) articles#update
|
368
|
+
PUT /articles/:id(.:format) articles#update
|
369
|
+
DELETE /articles/:id(.:format) articles#destroy
|
370
|
+
root GET / welcome#index
|
280
371
|
```
|
281
372
|
|
282
|
-
In the next section, you will add the ability to create new
|
373
|
+
In the next section, you will add the ability to create new articles in your
|
374
|
+
application and be able to view them. This is the "C" and the "R" from CRUD:
|
375
|
+
creation and reading. The form for doing this will look like this:
|
283
376
|
|
284
|
-
![The new
|
377
|
+
![The new article form](images/getting_started/new_article.png)
|
285
378
|
|
286
|
-
It will look a little basic for now, but that's ok. We'll look at improving the
|
379
|
+
It will look a little basic for now, but that's ok. We'll look at improving the
|
380
|
+
styling for it afterwards.
|
287
381
|
|
288
382
|
### Laying down the ground work
|
289
383
|
|
290
|
-
|
384
|
+
Firstly, you need a place within the application to create a new article. A
|
385
|
+
great place for that would be at `/articles/new`. With the route already
|
386
|
+
defined, requests can now be made to `/articles/new` in the application.
|
387
|
+
Navigate to <http://localhost:3000/articles/new> and you'll see a routing
|
388
|
+
error:
|
291
389
|
|
292
|
-
![Another routing error, uninitialized constant
|
390
|
+
![Another routing error, uninitialized constant ArticlesController](images/getting_started/routing_error_no_controller.png)
|
293
391
|
|
294
|
-
This error occurs because the route needs to have a controller defined in order
|
392
|
+
This error occurs because the route needs to have a controller defined in order
|
393
|
+
to serve the request. The solution to this particular problem is simple: create
|
394
|
+
a controller called `ArticlesController`. You can do this by running this
|
395
|
+
command:
|
295
396
|
|
296
397
|
```bash
|
297
|
-
$ rails g controller
|
398
|
+
$ bin/rails g controller articles
|
298
399
|
```
|
299
400
|
|
300
|
-
If you open up the newly generated `app/controllers/
|
401
|
+
If you open up the newly generated `app/controllers/articles_controller.rb`
|
402
|
+
you'll see a fairly empty controller:
|
301
403
|
|
302
404
|
```ruby
|
303
|
-
class
|
405
|
+
class ArticlesController < ApplicationController
|
304
406
|
end
|
305
407
|
```
|
306
408
|
|
307
|
-
A controller is simply a class that is defined to inherit from
|
409
|
+
A controller is simply a class that is defined to inherit from
|
410
|
+
`ApplicationController`.
|
411
|
+
It's inside this class that you'll define methods that will become the actions
|
412
|
+
for this controller. These actions will perform CRUD operations on the articles
|
413
|
+
within our system.
|
308
414
|
|
309
|
-
NOTE: There are `public`, `private` and `protected` methods in
|
310
|
-
|
311
|
-
|
415
|
+
NOTE: There are `public`, `private` and `protected` methods in Ruby,
|
416
|
+
but only `public` methods can be actions for controllers.
|
417
|
+
For more details check out [Programming Ruby](http://www.ruby-doc.org/docs/ProgrammingRuby/).
|
312
418
|
|
313
|
-
If you refresh <http://localhost:3000/
|
419
|
+
If you refresh <http://localhost:3000/articles/new> now, you'll get a new error:
|
314
420
|
|
315
|
-
![Unknown action new for
|
421
|
+
![Unknown action new for ArticlesController!](images/getting_started/unknown_action_new_for_articles.png)
|
316
422
|
|
317
|
-
This error indicates that Rails cannot find the `new` action inside the
|
423
|
+
This error indicates that Rails cannot find the `new` action inside the
|
424
|
+
`ArticlesController` that you just generated. This is because when controllers
|
425
|
+
are generated in Rails they are empty by default, unless you tell it
|
426
|
+
your wanted actions during the generation process.
|
318
427
|
|
319
|
-
To manually define an action inside a controller, all you need to do is to
|
428
|
+
To manually define an action inside a controller, all you need to do is to
|
429
|
+
define a new method inside the controller.
|
430
|
+
Open `app/controllers/articles_controller.rb` and inside the `ArticlesController`
|
431
|
+
class, define a `new` method like this:
|
320
432
|
|
321
433
|
```ruby
|
322
434
|
def new
|
323
435
|
end
|
324
436
|
```
|
325
437
|
|
326
|
-
With the `new` method defined in `
|
438
|
+
With the `new` method defined in `ArticlesController`, if you refresh
|
439
|
+
<http://localhost:3000/articles/new> you'll see another error:
|
327
440
|
|
328
|
-
![Template is missing for
|
441
|
+
![Template is missing for articles/new](images/getting_started/template_is_missing_articles_new.png)
|
329
442
|
|
330
|
-
You're getting this error now because Rails expects plain actions like this one
|
443
|
+
You're getting this error now because Rails expects plain actions like this one
|
444
|
+
to have views associated with them to display their information. With no view
|
445
|
+
available, Rails errors out.
|
331
446
|
|
332
|
-
In the above image, the bottom line has been truncated. Let's see what the full
|
447
|
+
In the above image, the bottom line has been truncated. Let's see what the full
|
448
|
+
thing looks like:
|
333
449
|
|
334
450
|
<blockquote>
|
335
|
-
Missing template
|
451
|
+
Missing template articles/new, application/new with {locale:[:en], formats:[:html], handlers:[:erb, :builder, :coffee]}. Searched in: * "/path/to/blog/app/views"
|
336
452
|
</blockquote>
|
337
453
|
|
338
|
-
That's quite a lot of text! Let's quickly go through and understand what each
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
The
|
347
|
-
|
348
|
-
|
454
|
+
That's quite a lot of text! Let's quickly go through and understand what each
|
455
|
+
part of it does.
|
456
|
+
|
457
|
+
The first part identifies what template is missing. In this case, it's the
|
458
|
+
`articles/new` template. Rails will first look for this template. If not found,
|
459
|
+
then it will attempt to load a template called `application/new`. It looks for
|
460
|
+
one here because the `ArticlesController` inherits from `ApplicationController`.
|
461
|
+
|
462
|
+
The next part of the message contains a hash. The `:locale` key in this hash
|
463
|
+
simply indicates what spoken language template should be retrieved. By default,
|
464
|
+
this is the English - or "en" - template. The next key, `:formats` specifies the
|
465
|
+
format of template to be served in response. The default format is `:html`, and
|
466
|
+
so Rails is looking for an HTML template. The final key, `:handlers`, is telling
|
467
|
+
us what _template handlers_ could be used to render our template. `:erb` is most
|
468
|
+
commonly used for HTML templates, `:builder` is used for XML templates, and
|
469
|
+
`:coffee` uses CoffeeScript to build JavaScript templates.
|
470
|
+
|
471
|
+
The final part of this message tells us where Rails has looked for the templates.
|
472
|
+
Templates within a basic Rails application like this are kept in a single
|
473
|
+
location, but in more complex applications it could be many different paths.
|
474
|
+
|
475
|
+
The simplest template that would work in this case would be one located at
|
476
|
+
`app/views/articles/new.html.erb`. The extension of this file name is key: the
|
477
|
+
first extension is the _format_ of the template, and the second extension is the
|
478
|
+
_handler_ that will be used. Rails is attempting to find a template called
|
479
|
+
`articles/new` within `app/views` for the application. The format for this
|
480
|
+
template can only be `html` and the handler must be one of `erb`, `builder` or
|
481
|
+
`coffee`. Because you want to create a new HTML form, you will be using the `ERB`
|
482
|
+
language. Therefore the file should be called `articles/new.html.erb` and needs
|
483
|
+
to be located inside the `app/views` directory of the application.
|
484
|
+
|
485
|
+
Go ahead now and create a new file at `app/views/articles/new.html.erb` and
|
486
|
+
write this content in it:
|
349
487
|
|
350
488
|
```html
|
351
|
-
<h1>New
|
489
|
+
<h1>New Article</h1>
|
352
490
|
```
|
353
491
|
|
354
|
-
When you refresh <http://localhost:3000/
|
492
|
+
When you refresh <http://localhost:3000/articles/new> you'll now see that the
|
493
|
+
page has a title. The route, controller, action and view are now working
|
494
|
+
harmoniously! It's time to create the form for a new article.
|
355
495
|
|
356
496
|
### The first form
|
357
497
|
|
358
498
|
To create a form within this template, you will use a <em>form
|
359
499
|
builder</em>. The primary form builder for Rails is provided by a helper
|
360
|
-
method called `form_for`. To use this method, add this code into
|
500
|
+
method called `form_for`. To use this method, add this code into
|
501
|
+
`app/views/articles/new.html.erb`:
|
361
502
|
|
362
503
|
```html+erb
|
363
|
-
<%= form_for :
|
504
|
+
<%= form_for :article do |f| %>
|
364
505
|
<p>
|
365
506
|
<%= f.label :title %><br>
|
366
507
|
<%= f.text_field :title %>
|
@@ -377,42 +518,76 @@ method called `form_for`. To use this method, add this code into `app/views/post
|
|
377
518
|
<% end %>
|
378
519
|
```
|
379
520
|
|
380
|
-
If you refresh the page now, you'll see the exact same form as in the example.
|
521
|
+
If you refresh the page now, you'll see the exact same form as in the example.
|
522
|
+
Building forms in Rails is really just that easy!
|
381
523
|
|
382
524
|
When you call `form_for`, you pass it an identifying object for this
|
383
|
-
form. In this case, it's the symbol `:
|
525
|
+
form. In this case, it's the symbol `:article`. This tells the `form_for`
|
384
526
|
helper what this form is for. Inside the block for this method, the
|
385
|
-
`FormBuilder` object
|
527
|
+
`FormBuilder` object - represented by `f` - is used to build two labels and two
|
528
|
+
text fields, one each for the title and text of an article. Finally, a call to
|
529
|
+
`submit` on the `f` object will create a submit button for the form.
|
386
530
|
|
387
|
-
There's one problem with this form though. If you inspect the HTML that is
|
531
|
+
There's one problem with this form though. If you inspect the HTML that is
|
532
|
+
generated, by viewing the source of the page, you will see that the `action`
|
533
|
+
attribute for the form is pointing at `/articles/new`. This is a problem because
|
534
|
+
this route goes to the very page that you're on right at the moment, and that
|
535
|
+
route should only be used to display the form for a new article.
|
388
536
|
|
389
537
|
The form needs to use a different URL in order to go somewhere else.
|
390
538
|
This can be done quite simply with the `:url` option of `form_for`.
|
391
539
|
Typically in Rails, the action that is used for new form submissions
|
392
540
|
like this is called "create", and so the form should be pointed to that action.
|
393
541
|
|
394
|
-
Edit the `form_for` line inside `app/views/
|
542
|
+
Edit the `form_for` line inside `app/views/articles/new.html.erb` to look like
|
543
|
+
this:
|
395
544
|
|
396
545
|
```html+erb
|
397
|
-
<%= form_for :
|
546
|
+
<%= form_for :article, url: articles_path do |f| %>
|
398
547
|
```
|
399
548
|
|
400
|
-
In this example, the `
|
549
|
+
In this example, the `articles_path` helper is passed to the `:url` option.
|
550
|
+
To see what Rails will do with this, we look back at the output of
|
551
|
+
`rake routes`:
|
401
552
|
|
402
|
-
|
553
|
+
```bash
|
554
|
+
$ bin/rake routes
|
555
|
+
Prefix Verb URI Pattern Controller#Action
|
556
|
+
articles GET /articles(.:format) articles#index
|
557
|
+
POST /articles(.:format) articles#create
|
558
|
+
new_article GET /articles/new(.:format) articles#new
|
559
|
+
edit_article GET /articles/:id/edit(.:format) articles#edit
|
560
|
+
article GET /articles/:id(.:format) articles#show
|
561
|
+
PATCH /articles/:id(.:format) articles#update
|
562
|
+
PUT /articles/:id(.:format) articles#update
|
563
|
+
DELETE /articles/:id(.:format) articles#destroy
|
564
|
+
root GET / welcome#index
|
565
|
+
```
|
403
566
|
|
404
|
-
|
567
|
+
The `articles_path` helper tells Rails to point the form
|
568
|
+
to the URI Pattern associated with the `articles` prefix; and
|
569
|
+
the form will (by default) send a `POST` request
|
570
|
+
to that route. This is associated with the
|
571
|
+
`create` action of the current controller, the `ArticlesController`.
|
405
572
|
|
406
|
-
|
573
|
+
With the form and its associated route defined, you will be able to fill in the
|
574
|
+
form and then click the submit button to begin the process of creating a new
|
575
|
+
article, so go ahead and do that. When you submit the form, you should see a
|
576
|
+
familiar error:
|
407
577
|
|
408
|
-
|
578
|
+
![Unknown action create for ArticlesController](images/getting_started/unknown_action_create_for_articles.png)
|
409
579
|
|
410
|
-
|
580
|
+
You now need to create the `create` action within the `ArticlesController` for
|
581
|
+
this to work.
|
411
582
|
|
412
|
-
|
583
|
+
### Creating articles
|
584
|
+
|
585
|
+
To make the "Unknown action" go away, you can define a `create` action within
|
586
|
+
the `ArticlesController` class in `app/controllers/articles_controller.rb`,
|
587
|
+
underneath the `new` action:
|
413
588
|
|
414
589
|
```ruby
|
415
|
-
class
|
590
|
+
class ArticlesController < ApplicationController
|
416
591
|
def new
|
417
592
|
end
|
418
593
|
|
@@ -421,27 +596,40 @@ class PostsController < ApplicationController
|
|
421
596
|
end
|
422
597
|
```
|
423
598
|
|
424
|
-
If you re-submit the form now, you'll see another familiar error: a template is
|
599
|
+
If you re-submit the form now, you'll see another familiar error: a template is
|
600
|
+
missing. That's ok, we can ignore that for now. What the `create` action should
|
601
|
+
be doing is saving our new article to the database.
|
425
602
|
|
426
|
-
When a form is submitted, the fields of the form are sent to Rails as
|
603
|
+
When a form is submitted, the fields of the form are sent to Rails as
|
604
|
+
_parameters_. These parameters can then be referenced inside the controller
|
605
|
+
actions, typically to perform a particular task. To see what these parameters
|
606
|
+
look like, change the `create` action to this:
|
427
607
|
|
428
608
|
```ruby
|
429
609
|
def create
|
430
|
-
render
|
610
|
+
render plain: params[:article].inspect
|
431
611
|
end
|
432
612
|
```
|
433
613
|
|
434
|
-
The `render` method here is taking a very simple hash with a key of `
|
614
|
+
The `render` method here is taking a very simple hash with a key of `plain` and
|
615
|
+
value of `params[:article].inspect`. The `params` method is the object which
|
616
|
+
represents the parameters (or fields) coming in from the form. The `params`
|
617
|
+
method returns an `ActiveSupport::HashWithIndifferentAccess` object, which
|
618
|
+
allows you to access the keys of the hash using either strings or symbols. In
|
619
|
+
this situation, the only parameters that matter are the ones from the form.
|
435
620
|
|
436
|
-
If you re-submit the form one more time you'll now no longer get the missing
|
621
|
+
If you re-submit the form one more time you'll now no longer get the missing
|
622
|
+
template error. Instead, you'll see something that looks like the following:
|
437
623
|
|
438
624
|
```ruby
|
439
|
-
{"title"=>"First
|
625
|
+
{"title"=>"First article!", "text"=>"This is my first article."}
|
440
626
|
```
|
441
627
|
|
442
|
-
This action is now displaying the parameters for the
|
628
|
+
This action is now displaying the parameters for the article that are coming in
|
629
|
+
from the form. However, this isn't really all that helpful. Yes, you can see the
|
630
|
+
parameters but nothing in particular is being done with them.
|
443
631
|
|
444
|
-
### Creating the
|
632
|
+
### Creating the Article model
|
445
633
|
|
446
634
|
Models in Rails use a singular name, and their corresponding database tables use
|
447
635
|
a plural name. Rails provides a generator for creating models, which
|
@@ -449,17 +637,17 @@ most Rails developers tend to use when creating new models.
|
|
449
637
|
To create the new model, run this command in your terminal:
|
450
638
|
|
451
639
|
```bash
|
452
|
-
$ rails generate model
|
640
|
+
$ bin/rails generate model Article title:string text:text
|
453
641
|
```
|
454
642
|
|
455
|
-
With that command we told Rails that we want a `
|
643
|
+
With that command we told Rails that we want a `Article` model, together
|
456
644
|
with a _title_ attribute of type string, and a _text_ attribute
|
457
|
-
of type text. Those attributes are automatically added to the `
|
458
|
-
table in the database and mapped to the `
|
645
|
+
of type text. Those attributes are automatically added to the `articles`
|
646
|
+
table in the database and mapped to the `Article` model.
|
459
647
|
|
460
648
|
Rails responded by creating a bunch of files. For
|
461
|
-
now, we're only interested in `app/models/
|
462
|
-
`db/migrate/
|
649
|
+
now, we're only interested in `app/models/article.rb` and
|
650
|
+
`db/migrate/20140120191729_create_articles.rb` (your name could be a bit
|
463
651
|
different). The latter is responsible
|
464
652
|
for creating the database structure, which is what we'll look at next.
|
465
653
|
|
@@ -478,13 +666,13 @@ and it's possible to undo a migration after it's been applied to your database.
|
|
478
666
|
Migration filenames include a timestamp to ensure that they're processed in the
|
479
667
|
order that they were created.
|
480
668
|
|
481
|
-
If you look in the `db/migrate/
|
669
|
+
If you look in the `db/migrate/20140120191729_create_articles.rb` file (remember,
|
482
670
|
yours will have a slightly different name), here's what you'll find:
|
483
671
|
|
484
672
|
```ruby
|
485
|
-
class
|
673
|
+
class CreateArticles < ActiveRecord::Migration
|
486
674
|
def change
|
487
|
-
create_table :
|
675
|
+
create_table :articles do |t|
|
488
676
|
t.string :title
|
489
677
|
t.text :text
|
490
678
|
|
@@ -494,12 +682,12 @@ class CreatePosts < ActiveRecord::Migration
|
|
494
682
|
end
|
495
683
|
```
|
496
684
|
|
497
|
-
The above migration creates a method named `change` which will be called when
|
498
|
-
run this migration. The action defined in this method is also reversible,
|
499
|
-
means Rails knows how to reverse the change made by this migration,
|
500
|
-
want to reverse it later. When you run this migration it will create
|
501
|
-
`
|
502
|
-
timestamp fields to allow Rails to track
|
685
|
+
The above migration creates a method named `change` which will be called when
|
686
|
+
you run this migration. The action defined in this method is also reversible,
|
687
|
+
which means Rails knows how to reverse the change made by this migration,
|
688
|
+
in case you want to reverse it later. When you run this migration it will create
|
689
|
+
an `articles` table with one string column and a text column. It also creates
|
690
|
+
two timestamp fields to allow Rails to track article creation and update times.
|
503
691
|
|
504
692
|
TIP: For more information about migrations, refer to [Rails Database
|
505
693
|
Migrations](migrations.html).
|
@@ -507,17 +695,17 @@ Migrations](migrations.html).
|
|
507
695
|
At this point, you can use a rake command to run the migration:
|
508
696
|
|
509
697
|
```bash
|
510
|
-
$ rake db:migrate
|
698
|
+
$ bin/rake db:migrate
|
511
699
|
```
|
512
700
|
|
513
|
-
Rails will execute this migration command and tell you it created the
|
701
|
+
Rails will execute this migration command and tell you it created the Articles
|
514
702
|
table.
|
515
703
|
|
516
704
|
```bash
|
517
|
-
==
|
518
|
-
-- create_table(:
|
705
|
+
== CreateArticles: migrating ==================================================
|
706
|
+
-- create_table(:articles)
|
519
707
|
-> 0.0019s
|
520
|
-
==
|
708
|
+
== CreateArticles: migrated (0.0020s) =========================================
|
521
709
|
```
|
522
710
|
|
523
711
|
NOTE. Because you're working in the development environment by default, this
|
@@ -528,65 +716,67 @@ invoking the command: `rake db:migrate RAILS_ENV=production`.
|
|
528
716
|
|
529
717
|
### Saving data in the controller
|
530
718
|
|
531
|
-
Back in `
|
532
|
-
to use the new `
|
533
|
-
and change the `create` action to
|
719
|
+
Back in `ArticlesController`, we need to change the `create` action
|
720
|
+
to use the new `Article` model to save the data in the database.
|
721
|
+
Open `app/controllers/articles_controller.rb` and change the `create` action to
|
722
|
+
look like this:
|
534
723
|
|
535
724
|
```ruby
|
536
725
|
def create
|
537
|
-
@
|
538
|
-
|
539
|
-
|
726
|
+
@article = Article.new(params[:article])
|
727
|
+
|
728
|
+
@article.save
|
729
|
+
redirect_to @article
|
540
730
|
end
|
541
731
|
```
|
542
732
|
|
543
733
|
Here's what's going on: every Rails model can be initialized with its
|
544
734
|
respective attributes, which are automatically mapped to the respective
|
545
|
-
database columns. In the first line we do just that
|
546
|
-
`params[:
|
547
|
-
`@
|
548
|
-
Finally, we redirect the user to the `show` action,
|
549
|
-
which we'll define later.
|
735
|
+
database columns. In the first line we do just that
|
736
|
+
(remember that `params[:article]` contains the attributes we're interested in).
|
737
|
+
Then, `@article.save` is responsible for saving the model in the database.
|
738
|
+
Finally, we redirect the user to the `show` action, which we'll define later.
|
550
739
|
|
551
|
-
TIP: As we'll see later, `@
|
552
|
-
whether the
|
740
|
+
TIP: As we'll see later, `@article.save` returns a boolean indicating
|
741
|
+
whether the article was saved or not.
|
553
742
|
|
554
743
|
If you now go to
|
555
|
-
<http://localhost:3000/
|
556
|
-
it! You should get an error that looks like this:
|
744
|
+
<http://localhost:3000/articles/new> you'll *almost* be able to create an
|
745
|
+
article. Try it! You should get an error that looks like this:
|
557
746
|
|
558
|
-
![Forbidden attributes for new
|
747
|
+
![Forbidden attributes for new article](images/getting_started/forbidden_attributes_for_new_article.png)
|
559
748
|
|
560
749
|
Rails has several security features that help you write secure applications,
|
561
750
|
and you're running into one of them now. This one is called
|
562
751
|
`strong_parameters`, which requires us to tell Rails exactly which parameters
|
563
752
|
we want to accept in our controllers. In this case, we want to allow the
|
564
|
-
`title` and `text` parameters, so
|
565
|
-
|
753
|
+
`title` and `text` parameters, so add the new `article_params` method, and
|
754
|
+
change your `create` controller action to use it, like this:
|
566
755
|
|
567
756
|
```ruby
|
568
757
|
def create
|
569
|
-
@
|
758
|
+
@article = Article.new(article_params)
|
570
759
|
|
571
|
-
@
|
572
|
-
redirect_to @
|
760
|
+
@article.save
|
761
|
+
redirect_to @article
|
573
762
|
end
|
574
763
|
|
575
764
|
private
|
576
|
-
def
|
577
|
-
params.require(:
|
765
|
+
def article_params
|
766
|
+
params.require(:article).permit(:title, :text)
|
578
767
|
end
|
579
768
|
```
|
580
769
|
|
581
770
|
See the `permit`? It allows us to accept both `title` and `text` in this
|
582
771
|
action.
|
583
772
|
|
584
|
-
TIP: Note that `def
|
585
|
-
setting the model's attributes by manipulating the hash passed to
|
773
|
+
TIP: Note that `def article_params` is private. This new approach prevents an
|
774
|
+
attacker from setting the model's attributes by manipulating the hash passed to
|
775
|
+
the model.
|
586
776
|
For more information, refer to
|
587
|
-
[this blog
|
777
|
+
[this blog article about Strong Parameters](http://weblog.rubyonrails.org/2012/3/21/strong-parameters/).
|
588
778
|
|
589
|
-
### Showing
|
779
|
+
### Showing Articles
|
590
780
|
|
591
781
|
If you submit the form again now, Rails will complain about not finding
|
592
782
|
the `show` action. That's not very useful though, so let's add the
|
@@ -596,67 +786,70 @@ As we have seen in the output of `rake routes`, the route for `show` action is
|
|
596
786
|
as follows:
|
597
787
|
|
598
788
|
```
|
599
|
-
|
789
|
+
article GET /articles/:id(.:format) articles#show
|
600
790
|
```
|
601
791
|
|
602
792
|
The special syntax `:id` tells rails that this route expects an `:id`
|
603
|
-
parameter, which in our case will be the id of the
|
793
|
+
parameter, which in our case will be the id of the article.
|
604
794
|
|
605
795
|
As we did before, we need to add the `show` action in
|
606
|
-
`app/controllers/
|
796
|
+
`app/controllers/articles_controller.rb` and its respective view.
|
607
797
|
|
608
798
|
```ruby
|
609
799
|
def show
|
610
|
-
@
|
800
|
+
@article = Article.find(params[:id])
|
611
801
|
end
|
612
802
|
```
|
613
803
|
|
614
|
-
A couple of things to note. We use `
|
615
|
-
interested in
|
616
|
-
|
804
|
+
A couple of things to note. We use `Article.find` to find the article we're
|
805
|
+
interested in, passing in `params[:id]` to get the `:id` parameter from the
|
806
|
+
request. We also use an instance variable (prefixed by `@`) to hold a
|
807
|
+
reference to the article object. We do this because Rails will pass all instance
|
617
808
|
variables to the view.
|
618
809
|
|
619
|
-
Now, create a new file `app/views/
|
810
|
+
Now, create a new file `app/views/articles/show.html.erb` with the following
|
620
811
|
content:
|
621
812
|
|
622
813
|
```html+erb
|
623
814
|
<p>
|
624
815
|
<strong>Title:</strong>
|
625
|
-
<%= @
|
816
|
+
<%= @article.title %>
|
626
817
|
</p>
|
627
818
|
|
628
819
|
<p>
|
629
820
|
<strong>Text:</strong>
|
630
|
-
<%= @
|
821
|
+
<%= @article.text %>
|
631
822
|
</p>
|
632
823
|
```
|
633
824
|
|
634
|
-
With this change, you should finally be able to create new
|
635
|
-
Visit <http://localhost:3000/
|
825
|
+
With this change, you should finally be able to create new articles.
|
826
|
+
Visit <http://localhost:3000/articles/new> and give it a try!
|
636
827
|
|
637
|
-
![Show action for
|
828
|
+
![Show action for articles](images/getting_started/show_action_for_articles.png)
|
638
829
|
|
639
|
-
### Listing all
|
830
|
+
### Listing all articles
|
640
831
|
|
641
|
-
We still need a way to list all our
|
642
|
-
|
832
|
+
We still need a way to list all our articles, so let's do that.
|
833
|
+
The route for this as per output of `rake routes` is:
|
643
834
|
|
644
|
-
```
|
645
|
-
|
835
|
+
```
|
836
|
+
articles GET /articles(.:format) articles#index
|
646
837
|
```
|
647
838
|
|
648
|
-
|
839
|
+
Add the corresponding `index` action for that route inside the
|
840
|
+
`ArticlesController` in the `app/controllers/articles_controller.rb` file:
|
649
841
|
|
650
842
|
```ruby
|
651
843
|
def index
|
652
|
-
@
|
844
|
+
@articles = Article.all
|
653
845
|
end
|
654
846
|
```
|
655
847
|
|
656
|
-
And then finally
|
848
|
+
And then finally, add view for this action, located at
|
849
|
+
`app/views/articles/index.html.erb`:
|
657
850
|
|
658
851
|
```html+erb
|
659
|
-
<h1>Listing
|
852
|
+
<h1>Listing articles</h1>
|
660
853
|
|
661
854
|
<table>
|
662
855
|
<tr>
|
@@ -664,63 +857,71 @@ And then finally a view for this action, located at `app/views/posts/index.html.
|
|
664
857
|
<th>Text</th>
|
665
858
|
</tr>
|
666
859
|
|
667
|
-
<% @
|
860
|
+
<% @articles.each do |article| %>
|
668
861
|
<tr>
|
669
|
-
<td><%=
|
670
|
-
<td><%=
|
862
|
+
<td><%= article.title %></td>
|
863
|
+
<td><%= article.text %></td>
|
671
864
|
</tr>
|
672
865
|
<% end %>
|
673
866
|
</table>
|
674
867
|
```
|
675
868
|
|
676
|
-
Now if you go to `http://localhost:3000/
|
869
|
+
Now if you go to `http://localhost:3000/articles` you will see a list of all the
|
870
|
+
articles that you have created.
|
677
871
|
|
678
872
|
### Adding links
|
679
873
|
|
680
|
-
You can now create, show, and list
|
874
|
+
You can now create, show, and list articles. Now let's add some links to
|
681
875
|
navigate through pages.
|
682
876
|
|
683
877
|
Open `app/views/welcome/index.html.erb` and modify it as follows:
|
684
878
|
|
685
879
|
```html+erb
|
686
880
|
<h1>Hello, Rails!</h1>
|
687
|
-
<%= link_to
|
881
|
+
<%= link_to 'My Blog', controller: 'articles' %>
|
688
882
|
```
|
689
883
|
|
690
884
|
The `link_to` method is one of Rails' built-in view helpers. It creates a
|
691
885
|
hyperlink based on text to display and where to go - in this case, to the path
|
692
|
-
for
|
886
|
+
for articles.
|
693
887
|
|
694
|
-
Let's add links to the other views as well, starting with adding this
|
888
|
+
Let's add links to the other views as well, starting with adding this
|
889
|
+
"New Article" link to `app/views/articles/index.html.erb`, placing it above the
|
890
|
+
`<table>` tag:
|
695
891
|
|
696
892
|
```erb
|
697
|
-
<%= link_to 'New
|
893
|
+
<%= link_to 'New article', new_article_path %>
|
698
894
|
```
|
699
895
|
|
700
|
-
This link will allow you to bring up the form that lets you create a new
|
896
|
+
This link will allow you to bring up the form that lets you create a new article.
|
897
|
+
|
898
|
+
Also add a link in `app/views/articles/new.html.erb`, underneath the form, to
|
899
|
+
go back to the `index` action:
|
701
900
|
|
702
901
|
```erb
|
703
|
-
<%= form_for :
|
902
|
+
<%= form_for :article, url: articles_path do |f| %>
|
704
903
|
...
|
705
904
|
<% end %>
|
706
905
|
|
707
|
-
<%= link_to 'Back',
|
906
|
+
<%= link_to 'Back', articles_path %>
|
708
907
|
```
|
709
908
|
|
710
|
-
Finally, add another link to the `app/views/
|
909
|
+
Finally, add another link to the `app/views/articles/show.html.erb` template to
|
910
|
+
go back to the `index` action as well, so that people who are viewing a single
|
911
|
+
article can go back and view the whole list again:
|
711
912
|
|
712
913
|
```html+erb
|
713
914
|
<p>
|
714
915
|
<strong>Title:</strong>
|
715
|
-
<%= @
|
916
|
+
<%= @article.title %>
|
716
917
|
</p>
|
717
918
|
|
718
919
|
<p>
|
719
920
|
<strong>Text:</strong>
|
720
|
-
<%= @
|
921
|
+
<%= @article.text %>
|
721
922
|
</p>
|
722
923
|
|
723
|
-
<%= link_to 'Back',
|
924
|
+
<%= link_to 'Back', articles_path %>
|
724
925
|
```
|
725
926
|
|
726
927
|
TIP: If you want to link to an action in the same controller, you don't
|
@@ -731,83 +932,90 @@ TIP: In development mode (which is what you're working in by default), Rails
|
|
731
932
|
reloads your application with every browser request, so there's no need to stop
|
732
933
|
and restart the web server when a change is made.
|
733
934
|
|
734
|
-
###
|
935
|
+
### Adding Some Validation
|
735
936
|
|
736
|
-
The model file, `app/models/
|
937
|
+
The model file, `app/models/article.rb` is about as simple as it can get:
|
737
938
|
|
738
939
|
```ruby
|
739
|
-
class
|
940
|
+
class Article < ActiveRecord::Base
|
740
941
|
end
|
741
942
|
```
|
742
943
|
|
743
|
-
There isn't much to this file - but note that the `
|
944
|
+
There isn't much to this file - but note that the `Article` class inherits from
|
744
945
|
`ActiveRecord::Base`. Active Record supplies a great deal of functionality to
|
745
946
|
your Rails models for free, including basic database CRUD (Create, Read, Update,
|
746
947
|
Destroy) operations, data validation, as well as sophisticated search support
|
747
948
|
and the ability to relate multiple models to one another.
|
748
949
|
|
749
|
-
### Adding Some Validation
|
750
|
-
|
751
950
|
Rails includes methods to help you validate the data that you send to models.
|
752
|
-
Open the `app/models/
|
951
|
+
Open the `app/models/article.rb` file and edit it:
|
753
952
|
|
754
953
|
```ruby
|
755
|
-
class
|
954
|
+
class Article < ActiveRecord::Base
|
756
955
|
validates :title, presence: true,
|
757
956
|
length: { minimum: 5 }
|
758
957
|
end
|
759
958
|
```
|
760
959
|
|
761
|
-
These changes will ensure that all
|
762
|
-
characters long.
|
960
|
+
These changes will ensure that all articles have a title that is at least five
|
961
|
+
characters long. Rails can validate a variety of conditions in a model,
|
763
962
|
including the presence or uniqueness of columns, their format, and the
|
764
963
|
existence of associated objects. Validations are covered in detail in [Active
|
765
964
|
Record Validations](active_record_validations.html)
|
766
965
|
|
767
|
-
With the validation now in place, when you call `@
|
768
|
-
|
769
|
-
again, you'll notice that we don't
|
770
|
-
|
771
|
-
|
772
|
-
|
966
|
+
With the validation now in place, when you call `@article.save` on an invalid
|
967
|
+
article, it will return `false`. If you open
|
968
|
+
`app/controllers/articles_controller.rb` again, you'll notice that we don't
|
969
|
+
check the result of calling `@article.save` inside the `create` action.
|
970
|
+
If `@article.save` fails in this situation, we need to show the form back to the
|
971
|
+
user. To do this, change the `new` and `create` actions inside
|
972
|
+
`app/controllers/articles_controller.rb` to these:
|
773
973
|
|
774
974
|
```ruby
|
775
975
|
def new
|
776
|
-
@
|
976
|
+
@article = Article.new
|
777
977
|
end
|
778
978
|
|
779
979
|
def create
|
780
|
-
@
|
980
|
+
@article = Article.new(article_params)
|
781
981
|
|
782
|
-
if @
|
783
|
-
redirect_to @
|
982
|
+
if @article.save
|
983
|
+
redirect_to @article
|
784
984
|
else
|
785
985
|
render 'new'
|
786
986
|
end
|
787
987
|
end
|
988
|
+
|
989
|
+
private
|
990
|
+
def article_params
|
991
|
+
params.require(:article).permit(:title, :text)
|
992
|
+
end
|
788
993
|
```
|
789
994
|
|
790
|
-
The `new` action is now creating a new instance variable called `@
|
995
|
+
The `new` action is now creating a new instance variable called `@article`, and
|
791
996
|
you'll see why that is in just a few moments.
|
792
997
|
|
793
|
-
Notice that inside the `create` action we use `render` instead of `redirect_to`
|
794
|
-
returns `false`. The `render` method is used so that the `@
|
998
|
+
Notice that inside the `create` action we use `render` instead of `redirect_to`
|
999
|
+
when `save` returns `false`. The `render` method is used so that the `@article`
|
1000
|
+
object is passed back to the `new` template when it is rendered. This rendering
|
1001
|
+
is done within the same request as the form submission, whereas the
|
1002
|
+
`redirect_to` will tell the browser to issue another request.
|
795
1003
|
|
796
1004
|
If you reload
|
797
|
-
<http://localhost:3000/
|
798
|
-
try to save
|
1005
|
+
<http://localhost:3000/articles/new> and
|
1006
|
+
try to save an article without a title, Rails will send you back to the
|
799
1007
|
form, but that's not very useful. You need to tell the user that
|
800
1008
|
something went wrong. To do that, you'll modify
|
801
|
-
`app/views/
|
1009
|
+
`app/views/articles/new.html.erb` to check for error messages:
|
802
1010
|
|
803
1011
|
```html+erb
|
804
|
-
<%= form_for :
|
805
|
-
<% if @
|
1012
|
+
<%= form_for :article, url: articles_path do |f| %>
|
1013
|
+
<% if @article.errors.any? %>
|
806
1014
|
<div id="error_explanation">
|
807
|
-
<h2><%= pluralize(@
|
808
|
-
this
|
1015
|
+
<h2><%= pluralize(@article.errors.count, "error") %> prohibited
|
1016
|
+
this article from being saved:</h2>
|
809
1017
|
<ul>
|
810
|
-
<% @
|
1018
|
+
<% @article.errors.full_messages.each do |msg| %>
|
811
1019
|
<li><%= msg %></li>
|
812
1020
|
<% end %>
|
813
1021
|
</ul>
|
@@ -828,55 +1036,58 @@ something went wrong. To do that, you'll modify
|
|
828
1036
|
</p>
|
829
1037
|
<% end %>
|
830
1038
|
|
831
|
-
<%= link_to 'Back',
|
1039
|
+
<%= link_to 'Back', articles_path %>
|
832
1040
|
```
|
833
1041
|
|
834
1042
|
A few things are going on. We check if there are any errors with
|
835
|
-
`@
|
836
|
-
errors with `@
|
1043
|
+
`@article.errors.any?`, and in that case we show a list of all
|
1044
|
+
errors with `@article.errors.full_messages`.
|
837
1045
|
|
838
1046
|
`pluralize` is a rails helper that takes a number and a string as its
|
839
|
-
arguments. If the number is greater than one, the string will be automatically
|
1047
|
+
arguments. If the number is greater than one, the string will be automatically
|
1048
|
+
pluralized.
|
840
1049
|
|
841
|
-
The reason why we added `@
|
842
|
-
otherwise `@
|
843
|
-
`@
|
1050
|
+
The reason why we added `@article = Article.new` in the `ArticlesController` is
|
1051
|
+
that otherwise `@article` would be `nil` in our view, and calling
|
1052
|
+
`@article.errors.any?` would throw an error.
|
844
1053
|
|
845
1054
|
TIP: Rails automatically wraps fields that contain an error with a div
|
846
1055
|
with class `field_with_errors`. You can define a css rule to make them
|
847
1056
|
standout.
|
848
1057
|
|
849
|
-
Now you'll get a nice error message when saving
|
850
|
-
attempt to do just that on the new
|
1058
|
+
Now you'll get a nice error message when saving an article without title when
|
1059
|
+
you attempt to do just that on the new article form
|
1060
|
+
[(http://localhost:3000/articles/new)](http://localhost:3000/articles/new).
|
851
1061
|
|
852
1062
|
![Form With Errors](images/getting_started/form_with_errors.png)
|
853
1063
|
|
854
|
-
### Updating
|
1064
|
+
### Updating Articles
|
855
1065
|
|
856
|
-
We've covered the "CR" part of CRUD. Now let's focus on the "U" part, updating
|
1066
|
+
We've covered the "CR" part of CRUD. Now let's focus on the "U" part, updating
|
1067
|
+
articles.
|
857
1068
|
|
858
|
-
The first step we'll take is adding an `edit` action to `
|
1069
|
+
The first step we'll take is adding an `edit` action to the `ArticlesController`.
|
859
1070
|
|
860
1071
|
```ruby
|
861
1072
|
def edit
|
862
|
-
@
|
1073
|
+
@article = Article.find(params[:id])
|
863
1074
|
end
|
864
1075
|
```
|
865
1076
|
|
866
1077
|
The view will contain a form similar to the one we used when creating
|
867
|
-
new
|
1078
|
+
new articles. Create a file called `app/views/articles/edit.html.erb` and make
|
868
1079
|
it look as follows:
|
869
1080
|
|
870
1081
|
```html+erb
|
871
|
-
<h1>Editing
|
1082
|
+
<h1>Editing article</h1>
|
872
1083
|
|
873
|
-
<%= form_for :
|
874
|
-
<% if @
|
1084
|
+
<%= form_for :article, url: article_path(@article), method: :patch do |f| %>
|
1085
|
+
<% if @article.errors.any? %>
|
875
1086
|
<div id="error_explanation">
|
876
|
-
<h2><%= pluralize(@
|
877
|
-
this
|
1087
|
+
<h2><%= pluralize(@article.errors.count, "error") %> prohibited
|
1088
|
+
this article from being saved:</h2>
|
878
1089
|
<ul>
|
879
|
-
<% @
|
1090
|
+
<% @article.errors.full_messages.each do |msg| %>
|
880
1091
|
<li><%= msg %></li>
|
881
1092
|
<% end %>
|
882
1093
|
</ul>
|
@@ -897,7 +1108,7 @@ it look as follows:
|
|
897
1108
|
</p>
|
898
1109
|
<% end %>
|
899
1110
|
|
900
|
-
<%= link_to 'Back',
|
1111
|
+
<%= link_to 'Back', articles_path %>
|
901
1112
|
```
|
902
1113
|
|
903
1114
|
This time we point the form to the `update` action, which is not defined yet
|
@@ -907,65 +1118,77 @@ The `method: :patch` option tells Rails that we want this form to be submitted
|
|
907
1118
|
via the `PATCH` HTTP method which is the HTTP method you're expected to use to
|
908
1119
|
**update** resources according to the REST protocol.
|
909
1120
|
|
910
|
-
|
1121
|
+
The first parameter of `form_for` can be an object, say, `@article` which would
|
1122
|
+
cause the helper to fill in the form with the fields of the object. Passing in a
|
1123
|
+
symbol (`:article`) with the same name as the instance variable (`@article`) also
|
1124
|
+
automagically leads to the same behavior. This is what is happening here. More details
|
1125
|
+
can be found in [form_for documentation](http://api.rubyonrails.org/classes/ActionView/Helpers/FormHelper.html#method-i-form_for).
|
911
1126
|
|
912
|
-
Next we need to create the `update` action in
|
1127
|
+
Next we need to create the `update` action in
|
1128
|
+
`app/controllers/articles_controller.rb`:
|
913
1129
|
|
914
1130
|
```ruby
|
915
1131
|
def update
|
916
|
-
@
|
1132
|
+
@article = Article.find(params[:id])
|
917
1133
|
|
918
|
-
if @
|
919
|
-
redirect_to @
|
1134
|
+
if @article.update(article_params)
|
1135
|
+
redirect_to @article
|
920
1136
|
else
|
921
1137
|
render 'edit'
|
922
1138
|
end
|
923
1139
|
end
|
1140
|
+
|
1141
|
+
private
|
1142
|
+
def article_params
|
1143
|
+
params.require(:article).permit(:title, :text)
|
1144
|
+
end
|
924
1145
|
```
|
925
1146
|
|
926
1147
|
The new method, `update`, is used when you want to update a record
|
927
1148
|
that already exists, and it accepts a hash containing the attributes
|
928
1149
|
that you want to update. As before, if there was an error updating the
|
929
|
-
|
1150
|
+
article we want to show the form back to the user.
|
1151
|
+
|
1152
|
+
We reuse the `article_params` method that we defined earlier for the create
|
1153
|
+
action.
|
930
1154
|
|
931
1155
|
TIP: You don't need to pass all attributes to `update`. For
|
932
|
-
example, if you'd call `@
|
1156
|
+
example, if you'd call `@article.update(title: 'A new title')`
|
933
1157
|
Rails would only update the `title` attribute, leaving all other
|
934
1158
|
attributes untouched.
|
935
1159
|
|
936
1160
|
Finally, we want to show a link to the `edit` action in the list of all the
|
937
|
-
|
938
|
-
appear next to the "Show" link:
|
1161
|
+
articles, so let's add that now to `app/views/articles/index.html.erb` to make
|
1162
|
+
it appear next to the "Show" link:
|
939
1163
|
|
940
1164
|
```html+erb
|
941
1165
|
<table>
|
942
1166
|
<tr>
|
943
1167
|
<th>Title</th>
|
944
1168
|
<th>Text</th>
|
945
|
-
<th></th>
|
946
|
-
<th></th>
|
1169
|
+
<th colspan="2"></th>
|
947
1170
|
</tr>
|
948
1171
|
|
949
|
-
<% @
|
1172
|
+
<% @articles.each do |article| %>
|
950
1173
|
<tr>
|
951
|
-
<td><%=
|
952
|
-
<td><%=
|
953
|
-
<td><%= link_to 'Show',
|
954
|
-
<td><%= link_to 'Edit',
|
1174
|
+
<td><%= article.title %></td>
|
1175
|
+
<td><%= article.text %></td>
|
1176
|
+
<td><%= link_to 'Show', article_path(article) %></td>
|
1177
|
+
<td><%= link_to 'Edit', edit_article_path(article) %></td>
|
955
1178
|
</tr>
|
956
1179
|
<% end %>
|
957
1180
|
</table>
|
958
1181
|
```
|
959
1182
|
|
960
|
-
And we'll also add one to the `app/views/
|
961
|
-
so that there's also an "Edit" link on
|
962
|
-
the template:
|
1183
|
+
And we'll also add one to the `app/views/articles/show.html.erb` template as
|
1184
|
+
well, so that there's also an "Edit" link on an article's page. Add this at the
|
1185
|
+
bottom of the template:
|
963
1186
|
|
964
1187
|
```html+erb
|
965
1188
|
...
|
966
1189
|
|
967
|
-
<%= link_to 'Back',
|
968
|
-
| <%= link_to 'Edit',
|
1190
|
+
<%= link_to 'Back', articles_path %>
|
1191
|
+
| <%= link_to 'Edit', edit_article_path(@article) %>
|
969
1192
|
```
|
970
1193
|
|
971
1194
|
And here's how our app looks so far:
|
@@ -982,17 +1205,17 @@ underscore.
|
|
982
1205
|
TIP: You can read more about partials in the
|
983
1206
|
[Layouts and Rendering in Rails](layouts_and_rendering.html) guide.
|
984
1207
|
|
985
|
-
Create a new file `app/views/
|
1208
|
+
Create a new file `app/views/articles/_form.html.erb` with the following
|
986
1209
|
content:
|
987
1210
|
|
988
1211
|
```html+erb
|
989
|
-
<%= form_for @
|
990
|
-
<% if @
|
1212
|
+
<%= form_for @article do |f| %>
|
1213
|
+
<% if @article.errors.any? %>
|
991
1214
|
<div id="error_explanation">
|
992
|
-
<h2><%= pluralize(@
|
993
|
-
this
|
1215
|
+
<h2><%= pluralize(@article.errors.count, "error") %> prohibited
|
1216
|
+
this article from being saved:</h2>
|
994
1217
|
<ul>
|
995
|
-
<% @
|
1218
|
+
<% @article.errors.full_messages.each do |msg| %>
|
996
1219
|
<li><%= msg %></li>
|
997
1220
|
<% end %>
|
998
1221
|
</ul>
|
@@ -1015,37 +1238,42 @@ content:
|
|
1015
1238
|
```
|
1016
1239
|
|
1017
1240
|
Everything except for the `form_for` declaration remained the same.
|
1018
|
-
|
1019
|
-
|
1020
|
-
|
1021
|
-
|
1241
|
+
The reason we can use this shorter, simpler `form_for` declaration
|
1242
|
+
to stand in for either of the other forms is that `@article` is a *resource*
|
1243
|
+
corresponding to a full set of RESTful routes, and Rails is able to infer
|
1244
|
+
which URI and method to use.
|
1245
|
+
For more information about this use of `form_for`, see
|
1246
|
+
[Resource-oriented style](//api.rubyonrails.org/classes/ActionView/Helpers/FormHelper.html#method-i-form_for-label-Resource-oriented+style).
|
1247
|
+
|
1248
|
+
Now, let's update the `app/views/articles/new.html.erb` view to use this new
|
1249
|
+
partial, rewriting it completely:
|
1022
1250
|
|
1023
1251
|
```html+erb
|
1024
|
-
<h1>New
|
1252
|
+
<h1>New article</h1>
|
1025
1253
|
|
1026
1254
|
<%= render 'form' %>
|
1027
1255
|
|
1028
|
-
<%= link_to 'Back',
|
1256
|
+
<%= link_to 'Back', articles_path %>
|
1029
1257
|
```
|
1030
1258
|
|
1031
|
-
Then do the same for the `app/views/
|
1259
|
+
Then do the same for the `app/views/articles/edit.html.erb` view:
|
1032
1260
|
|
1033
1261
|
```html+erb
|
1034
|
-
<h1>Edit
|
1262
|
+
<h1>Edit article</h1>
|
1035
1263
|
|
1036
1264
|
<%= render 'form' %>
|
1037
1265
|
|
1038
|
-
<%= link_to 'Back',
|
1266
|
+
<%= link_to 'Back', articles_path %>
|
1039
1267
|
```
|
1040
1268
|
|
1041
|
-
### Deleting
|
1269
|
+
### Deleting Articles
|
1042
1270
|
|
1043
|
-
We're now ready to cover the "D" part of CRUD, deleting
|
1271
|
+
We're now ready to cover the "D" part of CRUD, deleting articles from the
|
1044
1272
|
database. Following the REST convention, the route for
|
1045
|
-
deleting
|
1273
|
+
deleting articles as per output of `rake routes` is:
|
1046
1274
|
|
1047
1275
|
```ruby
|
1048
|
-
DELETE /
|
1276
|
+
DELETE /articles/:id(.:format) articles#destroy
|
1049
1277
|
```
|
1050
1278
|
|
1051
1279
|
The `delete` routing method should be used for routes that destroy
|
@@ -1053,19 +1281,19 @@ resources. If this was left as a typical `get` route, it could be possible for
|
|
1053
1281
|
people to craft malicious URLs like this:
|
1054
1282
|
|
1055
1283
|
```html
|
1056
|
-
<a href='http://example.com/
|
1284
|
+
<a href='http://example.com/articles/1/destroy'>look at this cat!</a>
|
1057
1285
|
```
|
1058
1286
|
|
1059
1287
|
We use the `delete` method for destroying resources, and this route is mapped to
|
1060
|
-
the `destroy` action inside `app/controllers/
|
1061
|
-
provided below:
|
1288
|
+
the `destroy` action inside `app/controllers/articles_controller.rb`, which
|
1289
|
+
doesn't exist yet, but is provided below:
|
1062
1290
|
|
1063
1291
|
```ruby
|
1064
1292
|
def destroy
|
1065
|
-
@
|
1066
|
-
@
|
1293
|
+
@article = Article.find(params[:id])
|
1294
|
+
@article.destroy
|
1067
1295
|
|
1068
|
-
redirect_to
|
1296
|
+
redirect_to articles_path
|
1069
1297
|
end
|
1070
1298
|
```
|
1071
1299
|
|
@@ -1073,47 +1301,46 @@ You can call `destroy` on Active Record objects when you want to delete
|
|
1073
1301
|
them from the database. Note that we don't need to add a view for this
|
1074
1302
|
action since we're redirecting to the `index` action.
|
1075
1303
|
|
1076
|
-
Finally, add a '
|
1077
|
-
(`app/views/
|
1304
|
+
Finally, add a 'Destroy' link to your `index` action template
|
1305
|
+
(`app/views/articles/index.html.erb`) to wrap everything
|
1078
1306
|
together.
|
1079
1307
|
|
1080
1308
|
```html+erb
|
1081
|
-
<h1>Listing
|
1082
|
-
<%= link_to 'New
|
1309
|
+
<h1>Listing Articles</h1>
|
1310
|
+
<%= link_to 'New article', new_article_path %>
|
1083
1311
|
<table>
|
1084
1312
|
<tr>
|
1085
1313
|
<th>Title</th>
|
1086
1314
|
<th>Text</th>
|
1087
|
-
<th></th>
|
1088
|
-
<th></th>
|
1089
|
-
<th></th>
|
1315
|
+
<th colspan="3"></th>
|
1090
1316
|
</tr>
|
1091
1317
|
|
1092
|
-
<% @
|
1318
|
+
<% @articles.each do |article| %>
|
1093
1319
|
<tr>
|
1094
|
-
<td><%=
|
1095
|
-
<td><%=
|
1096
|
-
<td><%= link_to 'Show',
|
1097
|
-
<td><%= link_to 'Edit',
|
1098
|
-
<td><%= link_to 'Destroy',
|
1320
|
+
<td><%= article.title %></td>
|
1321
|
+
<td><%= article.text %></td>
|
1322
|
+
<td><%= link_to 'Show', article_path(article) %></td>
|
1323
|
+
<td><%= link_to 'Edit', edit_article_path(article) %></td>
|
1324
|
+
<td><%= link_to 'Destroy', article_path(article),
|
1099
1325
|
method: :delete, data: { confirm: 'Are you sure?' } %></td>
|
1100
1326
|
</tr>
|
1101
1327
|
<% end %>
|
1102
1328
|
</table>
|
1103
1329
|
```
|
1104
1330
|
|
1105
|
-
Here we're using `link_to` in a different way. We pass the named route as the
|
1106
|
-
and then the
|
1107
|
-
options are used as HTML5 attributes so that when the link is
|
1108
|
-
Rails will first show a confirm dialog to the user, and then submit the
|
1109
|
-
This is done via the JavaScript file `jquery_ujs`
|
1110
|
-
into your application's layout
|
1111
|
-
|
1331
|
+
Here we're using `link_to` in a different way. We pass the named route as the
|
1332
|
+
second argument, and then the options as another argument. The `:method` and
|
1333
|
+
`:'data-confirm'` options are used as HTML5 attributes so that when the link is
|
1334
|
+
clicked, Rails will first show a confirm dialog to the user, and then submit the
|
1335
|
+
link with method `delete`. This is done via the JavaScript file `jquery_ujs`
|
1336
|
+
which is automatically included into your application's layout
|
1337
|
+
(`app/views/layouts/application.html.erb`) when you generated the application.
|
1338
|
+
Without this file, the confirmation dialog box wouldn't appear.
|
1112
1339
|
|
1113
1340
|
![Confirm Dialog](images/getting_started/confirm_dialog.png)
|
1114
1341
|
|
1115
1342
|
Congratulations, you can now create, show, list, update and destroy
|
1116
|
-
|
1343
|
+
articles.
|
1117
1344
|
|
1118
1345
|
TIP: In general, Rails encourages the use of resources objects in place
|
1119
1346
|
of declaring routes manually.
|
@@ -1123,24 +1350,24 @@ For more information about routing, see
|
|
1123
1350
|
Adding a Second Model
|
1124
1351
|
---------------------
|
1125
1352
|
|
1126
|
-
It's time to add a second model to the application. The second model will handle
|
1127
|
-
|
1353
|
+
It's time to add a second model to the application. The second model will handle
|
1354
|
+
comments on articles.
|
1128
1355
|
|
1129
1356
|
### Generating a Model
|
1130
1357
|
|
1131
1358
|
We're going to see the same generator that we used before when creating
|
1132
|
-
the `
|
1133
|
-
reference of
|
1359
|
+
the `Article` model. This time we'll create a `Comment` model to hold
|
1360
|
+
reference of article comments. Run this command in your terminal:
|
1134
1361
|
|
1135
1362
|
```bash
|
1136
|
-
$ rails generate model Comment commenter:string body:text
|
1363
|
+
$ bin/rails generate model Comment commenter:string body:text article:references
|
1137
1364
|
```
|
1138
1365
|
|
1139
1366
|
This command will generate four files:
|
1140
1367
|
|
1141
1368
|
| File | Purpose |
|
1142
1369
|
| -------------------------------------------- | ------------------------------------------------------------------------------------------------------ |
|
1143
|
-
| db/migrate/
|
1370
|
+
| db/migrate/20140120201010_create_comments.rb | Migration to create the comments table in your database (your name will include a different timestamp) |
|
1144
1371
|
| app/models/comment.rb | The Comment model |
|
1145
1372
|
| test/models/comment_test.rb | Testing harness for the comments model |
|
1146
1373
|
| test/fixtures/comments.yml | Sample comments for use in testing |
|
@@ -1149,12 +1376,12 @@ First, take a look at `app/models/comment.rb`:
|
|
1149
1376
|
|
1150
1377
|
```ruby
|
1151
1378
|
class Comment < ActiveRecord::Base
|
1152
|
-
belongs_to :
|
1379
|
+
belongs_to :article
|
1153
1380
|
end
|
1154
1381
|
```
|
1155
1382
|
|
1156
|
-
This is very similar to the `
|
1157
|
-
is the line `belongs_to :
|
1383
|
+
This is very similar to the `Article` model that you saw earlier. The difference
|
1384
|
+
is the line `belongs_to :article`, which sets up an Active Record _association_.
|
1158
1385
|
You'll learn a little about associations in the next section of this guide.
|
1159
1386
|
|
1160
1387
|
In addition to the model, Rails has also made a migration to create the
|
@@ -1166,22 +1393,22 @@ class CreateComments < ActiveRecord::Migration
|
|
1166
1393
|
create_table :comments do |t|
|
1167
1394
|
t.string :commenter
|
1168
1395
|
t.text :body
|
1169
|
-
|
1396
|
+
|
1397
|
+
# this line adds an integer column called `article_id`.
|
1398
|
+
t.references :article, index: true
|
1170
1399
|
|
1171
1400
|
t.timestamps
|
1172
1401
|
end
|
1173
|
-
|
1174
|
-
add_index :comments, :post_id
|
1175
1402
|
end
|
1176
1403
|
end
|
1177
1404
|
```
|
1178
1405
|
|
1179
1406
|
The `t.references` line sets up a foreign key column for the association between
|
1180
|
-
the two models.
|
1181
|
-
|
1407
|
+
the two models. An index for this association is also created on this column.
|
1408
|
+
Go ahead and run the migration:
|
1182
1409
|
|
1183
1410
|
```bash
|
1184
|
-
$ rake db:migrate
|
1411
|
+
$ bin/rake db:migrate
|
1185
1412
|
```
|
1186
1413
|
|
1187
1414
|
Rails is smart enough to only execute the migrations that have not already been
|
@@ -1190,66 +1417,66 @@ run against the current database, so in this case you will just see:
|
|
1190
1417
|
```bash
|
1191
1418
|
== CreateComments: migrating =================================================
|
1192
1419
|
-- create_table(:comments)
|
1193
|
-
-> 0.
|
1194
|
-
|
1195
|
-
-> 0.0003s
|
1196
|
-
== CreateComments: migrated (0.0012s) ========================================
|
1420
|
+
-> 0.0115s
|
1421
|
+
== CreateComments: migrated (0.0119s) ========================================
|
1197
1422
|
```
|
1198
1423
|
|
1199
1424
|
### Associating Models
|
1200
1425
|
|
1201
1426
|
Active Record associations let you easily declare the relationship between two
|
1202
|
-
models. In the case of comments and
|
1203
|
-
this way:
|
1427
|
+
models. In the case of comments and articles, you could write out the
|
1428
|
+
relationships this way:
|
1204
1429
|
|
1205
|
-
* Each comment belongs to one
|
1206
|
-
* One
|
1430
|
+
* Each comment belongs to one article.
|
1431
|
+
* One article can have many comments.
|
1207
1432
|
|
1208
1433
|
In fact, this is very close to the syntax that Rails uses to declare this
|
1209
|
-
association. You've already seen the line of code inside the `Comment` model
|
1210
|
-
makes each comment belong to
|
1434
|
+
association. You've already seen the line of code inside the `Comment` model
|
1435
|
+
(app/models/comment.rb) that makes each comment belong to an Article:
|
1211
1436
|
|
1212
1437
|
```ruby
|
1213
1438
|
class Comment < ActiveRecord::Base
|
1214
|
-
belongs_to :
|
1439
|
+
belongs_to :article
|
1215
1440
|
end
|
1216
1441
|
```
|
1217
1442
|
|
1218
|
-
You'll need to edit `app/models/
|
1443
|
+
You'll need to edit `app/models/article.rb` to add the other side of the
|
1444
|
+
association:
|
1219
1445
|
|
1220
1446
|
```ruby
|
1221
|
-
class
|
1447
|
+
class Article < ActiveRecord::Base
|
1222
1448
|
has_many :comments
|
1223
1449
|
validates :title, presence: true,
|
1224
1450
|
length: { minimum: 5 }
|
1225
|
-
[...]
|
1226
1451
|
end
|
1227
1452
|
```
|
1228
1453
|
|
1229
1454
|
These two declarations enable a good bit of automatic behavior. For example, if
|
1230
|
-
you have an instance variable `@
|
1231
|
-
the comments belonging to that
|
1455
|
+
you have an instance variable `@article` containing an article, you can retrieve
|
1456
|
+
all the comments belonging to that article as an array using
|
1457
|
+
`@article.comments`.
|
1232
1458
|
|
1233
1459
|
TIP: For more information on Active Record associations, see the [Active Record
|
1234
1460
|
Associations](association_basics.html) guide.
|
1235
1461
|
|
1236
1462
|
### Adding a Route for Comments
|
1237
1463
|
|
1238
|
-
As with the `welcome` controller, we will need to add a route so that Rails
|
1239
|
-
where we would like to navigate to see `comments`. Open up the
|
1464
|
+
As with the `welcome` controller, we will need to add a route so that Rails
|
1465
|
+
knows where we would like to navigate to see `comments`. Open up the
|
1240
1466
|
`config/routes.rb` file again, and edit it as follows:
|
1241
1467
|
|
1242
1468
|
```ruby
|
1243
|
-
resources :
|
1469
|
+
resources :articles do
|
1244
1470
|
resources :comments
|
1245
1471
|
end
|
1246
1472
|
```
|
1247
1473
|
|
1248
|
-
This creates `comments` as a _nested resource_ within `
|
1249
|
-
part of capturing the hierarchical relationship that exists between
|
1250
|
-
comments.
|
1474
|
+
This creates `comments` as a _nested resource_ within `articles`. This is
|
1475
|
+
another part of capturing the hierarchical relationship that exists between
|
1476
|
+
articles and comments.
|
1251
1477
|
|
1252
|
-
TIP: For more information on routing, see the [Rails Routing](routing.html)
|
1478
|
+
TIP: For more information on routing, see the [Rails Routing](routing.html)
|
1479
|
+
guide.
|
1253
1480
|
|
1254
1481
|
### Generating a Controller
|
1255
1482
|
|
@@ -1257,7 +1484,7 @@ With the model in hand, you can turn your attention to creating a matching
|
|
1257
1484
|
controller. Again, we'll use the same generator we used before:
|
1258
1485
|
|
1259
1486
|
```bash
|
1260
|
-
$ rails generate controller Comments
|
1487
|
+
$ bin/rails generate controller Comments
|
1261
1488
|
```
|
1262
1489
|
|
1263
1490
|
This creates six files and one empty directory:
|
@@ -1273,33 +1500,33 @@ This creates six files and one empty directory:
|
|
1273
1500
|
| app/assets/stylesheets/comment.css.scss | Cascading style sheet for the controller |
|
1274
1501
|
|
1275
1502
|
Like with any blog, our readers will create their comments directly after
|
1276
|
-
reading the
|
1277
|
-
the
|
1503
|
+
reading the article, and once they have added their comment, will be sent back
|
1504
|
+
to the article show page to see their comment now listed. Due to this, our
|
1278
1505
|
`CommentsController` is there to provide a method to create comments and delete
|
1279
1506
|
spam comments when they arrive.
|
1280
1507
|
|
1281
|
-
So first, we'll wire up the
|
1282
|
-
(`app/views/
|
1508
|
+
So first, we'll wire up the Article show template
|
1509
|
+
(`app/views/articles/show.html.erb`) to let us make a new comment:
|
1283
1510
|
|
1284
1511
|
```html+erb
|
1285
1512
|
<p>
|
1286
1513
|
<strong>Title:</strong>
|
1287
|
-
<%= @
|
1514
|
+
<%= @article.title %>
|
1288
1515
|
</p>
|
1289
1516
|
|
1290
1517
|
<p>
|
1291
1518
|
<strong>Text:</strong>
|
1292
|
-
<%= @
|
1519
|
+
<%= @article.text %>
|
1293
1520
|
</p>
|
1294
1521
|
|
1295
1522
|
<h2>Add a comment:</h2>
|
1296
|
-
<%= form_for([@
|
1523
|
+
<%= form_for([@article, @article.comments.build]) do |f| %>
|
1297
1524
|
<p>
|
1298
|
-
<%= f.label :commenter %><br
|
1525
|
+
<%= f.label :commenter %><br>
|
1299
1526
|
<%= f.text_field :commenter %>
|
1300
1527
|
</p>
|
1301
1528
|
<p>
|
1302
|
-
<%= f.label :body %><br
|
1529
|
+
<%= f.label :body %><br>
|
1303
1530
|
<%= f.text_area :body %>
|
1304
1531
|
</p>
|
1305
1532
|
<p>
|
@@ -1307,55 +1534,61 @@ So first, we'll wire up the Post show template
|
|
1307
1534
|
</p>
|
1308
1535
|
<% end %>
|
1309
1536
|
|
1310
|
-
<%= link_to 'Back',
|
1311
|
-
| <%= link_to 'Edit',
|
1537
|
+
<%= link_to 'Back', articles_path %>
|
1538
|
+
| <%= link_to 'Edit', edit_article_path(@article) %>
|
1312
1539
|
```
|
1313
1540
|
|
1314
|
-
This adds a form on the `
|
1541
|
+
This adds a form on the `Article` show page that creates a new comment by
|
1315
1542
|
calling the `CommentsController` `create` action. The `form_for` call here uses
|
1316
|
-
an array, which will build a nested route, such as `/
|
1543
|
+
an array, which will build a nested route, such as `/articles/1/comments`.
|
1317
1544
|
|
1318
1545
|
Let's wire up the `create` in `app/controllers/comments_controller.rb`:
|
1319
1546
|
|
1320
1547
|
```ruby
|
1321
1548
|
class CommentsController < ApplicationController
|
1322
1549
|
def create
|
1323
|
-
@
|
1324
|
-
@comment = @
|
1325
|
-
redirect_to
|
1550
|
+
@article = Article.find(params[:article_id])
|
1551
|
+
@comment = @article.comments.create(comment_params)
|
1552
|
+
redirect_to article_path(@article)
|
1326
1553
|
end
|
1554
|
+
|
1555
|
+
private
|
1556
|
+
def comment_params
|
1557
|
+
params.require(:comment).permit(:commenter, :body)
|
1558
|
+
end
|
1327
1559
|
end
|
1328
1560
|
```
|
1329
1561
|
|
1330
|
-
You'll see a bit more complexity here than you did in the controller for
|
1331
|
-
That's a side-effect of the nesting that you've set up. Each request
|
1332
|
-
comment has to keep track of the
|
1333
|
-
initial call to the `find` method of the `
|
1562
|
+
You'll see a bit more complexity here than you did in the controller for
|
1563
|
+
articles. That's a side-effect of the nesting that you've set up. Each request
|
1564
|
+
for a comment has to keep track of the article to which the comment is attached,
|
1565
|
+
thus the initial call to the `find` method of the `Article` model to get the
|
1566
|
+
article in question.
|
1334
1567
|
|
1335
1568
|
In addition, the code takes advantage of some of the methods available for an
|
1336
|
-
association. We use the `create` method on `@
|
1337
|
-
the comment. This will automatically link the comment so that it belongs to
|
1338
|
-
particular
|
1569
|
+
association. We use the `create` method on `@article.comments` to create and
|
1570
|
+
save the comment. This will automatically link the comment so that it belongs to
|
1571
|
+
that particular article.
|
1339
1572
|
|
1340
|
-
Once we have made the new comment, we send the user back to the original
|
1341
|
-
using the `
|
1342
|
-
`show` action of the `
|
1343
|
-
template. This is where we want the comment to show, so let's
|
1344
|
-
`app/views/
|
1573
|
+
Once we have made the new comment, we send the user back to the original article
|
1574
|
+
using the `article_path(@article)` helper. As we have already seen, this calls
|
1575
|
+
the `show` action of the `ArticlesController` which in turn renders the
|
1576
|
+
`show.html.erb` template. This is where we want the comment to show, so let's
|
1577
|
+
add that to the `app/views/articles/show.html.erb`.
|
1345
1578
|
|
1346
1579
|
```html+erb
|
1347
1580
|
<p>
|
1348
1581
|
<strong>Title:</strong>
|
1349
|
-
<%= @
|
1582
|
+
<%= @article.title %>
|
1350
1583
|
</p>
|
1351
1584
|
|
1352
1585
|
<p>
|
1353
1586
|
<strong>Text:</strong>
|
1354
|
-
<%= @
|
1587
|
+
<%= @article.text %>
|
1355
1588
|
</p>
|
1356
1589
|
|
1357
1590
|
<h2>Comments</h2>
|
1358
|
-
<% @
|
1591
|
+
<% @article.comments.each do |comment| %>
|
1359
1592
|
<p>
|
1360
1593
|
<strong>Commenter:</strong>
|
1361
1594
|
<%= comment.commenter %>
|
@@ -1368,13 +1601,13 @@ template. This is where we want the comment to show, so let's add that to the
|
|
1368
1601
|
<% end %>
|
1369
1602
|
|
1370
1603
|
<h2>Add a comment:</h2>
|
1371
|
-
<%= form_for([@
|
1604
|
+
<%= form_for([@article, @article.comments.build]) do |f| %>
|
1372
1605
|
<p>
|
1373
|
-
<%= f.label :commenter %><br
|
1606
|
+
<%= f.label :commenter %><br>
|
1374
1607
|
<%= f.text_field :commenter %>
|
1375
1608
|
</p>
|
1376
1609
|
<p>
|
1377
|
-
<%= f.label :body %><br
|
1610
|
+
<%= f.label :body %><br>
|
1378
1611
|
<%= f.text_area :body %>
|
1379
1612
|
</p>
|
1380
1613
|
<p>
|
@@ -1382,26 +1615,26 @@ template. This is where we want the comment to show, so let's add that to the
|
|
1382
1615
|
</p>
|
1383
1616
|
<% end %>
|
1384
1617
|
|
1385
|
-
<%= link_to 'Edit
|
1386
|
-
<%= link_to 'Back to
|
1618
|
+
<%= link_to 'Edit Article', edit_article_path(@article) %> |
|
1619
|
+
<%= link_to 'Back to Articles', articles_path %>
|
1387
1620
|
```
|
1388
1621
|
|
1389
|
-
Now you can add
|
1622
|
+
Now you can add articles and comments to your blog and have them show up in the
|
1390
1623
|
right places.
|
1391
1624
|
|
1392
|
-
![
|
1625
|
+
![Article with Comments](images/getting_started/article_with_comments.png)
|
1393
1626
|
|
1394
1627
|
Refactoring
|
1395
1628
|
-----------
|
1396
1629
|
|
1397
|
-
Now that we have
|
1398
|
-
`app/views/
|
1399
|
-
use partials to clean it up.
|
1630
|
+
Now that we have articles and comments working, take a look at the
|
1631
|
+
`app/views/articles/show.html.erb` template. It is getting long and awkward. We
|
1632
|
+
can use partials to clean it up.
|
1400
1633
|
|
1401
1634
|
### Rendering Partial Collections
|
1402
1635
|
|
1403
|
-
First, we will make a comment partial to extract showing all the comments for
|
1404
|
-
|
1636
|
+
First, we will make a comment partial to extract showing all the comments for
|
1637
|
+
the article. Create the file `app/views/comments/_comment.html.erb` and put the
|
1405
1638
|
following into it:
|
1406
1639
|
|
1407
1640
|
```html+erb
|
@@ -1416,31 +1649,31 @@ following into it:
|
|
1416
1649
|
</p>
|
1417
1650
|
```
|
1418
1651
|
|
1419
|
-
Then you can change `app/views/
|
1652
|
+
Then you can change `app/views/articles/show.html.erb` to look like the
|
1420
1653
|
following:
|
1421
1654
|
|
1422
1655
|
```html+erb
|
1423
1656
|
<p>
|
1424
1657
|
<strong>Title:</strong>
|
1425
|
-
<%= @
|
1658
|
+
<%= @article.title %>
|
1426
1659
|
</p>
|
1427
1660
|
|
1428
1661
|
<p>
|
1429
1662
|
<strong>Text:</strong>
|
1430
|
-
<%= @
|
1663
|
+
<%= @article.text %>
|
1431
1664
|
</p>
|
1432
1665
|
|
1433
1666
|
<h2>Comments</h2>
|
1434
|
-
<%= render @
|
1667
|
+
<%= render @article.comments %>
|
1435
1668
|
|
1436
1669
|
<h2>Add a comment:</h2>
|
1437
|
-
<%= form_for([@
|
1670
|
+
<%= form_for([@article, @article.comments.build]) do |f| %>
|
1438
1671
|
<p>
|
1439
|
-
<%= f.label :commenter %><br
|
1672
|
+
<%= f.label :commenter %><br>
|
1440
1673
|
<%= f.text_field :commenter %>
|
1441
1674
|
</p>
|
1442
1675
|
<p>
|
1443
|
-
<%= f.label :body %><br
|
1676
|
+
<%= f.label :body %><br>
|
1444
1677
|
<%= f.text_area :body %>
|
1445
1678
|
</p>
|
1446
1679
|
<p>
|
@@ -1448,13 +1681,13 @@ following:
|
|
1448
1681
|
</p>
|
1449
1682
|
<% end %>
|
1450
1683
|
|
1451
|
-
<%= link_to 'Edit
|
1452
|
-
<%= link_to 'Back to
|
1684
|
+
<%= link_to 'Edit Article', edit_article_path(@article) %> |
|
1685
|
+
<%= link_to 'Back to Articles', articles_path %>
|
1453
1686
|
```
|
1454
1687
|
|
1455
1688
|
This will now render the partial in `app/views/comments/_comment.html.erb` once
|
1456
|
-
for each comment that is in the `@
|
1457
|
-
method iterates over the `@
|
1689
|
+
for each comment that is in the `@article.comments` collection. As the `render`
|
1690
|
+
method iterates over the `@article.comments` collection, it assigns each
|
1458
1691
|
comment to a local variable named the same as the partial, in this case
|
1459
1692
|
`comment` which is then available in the partial for us to show.
|
1460
1693
|
|
@@ -1464,13 +1697,13 @@ Let us also move that new comment section out to its own partial. Again, you
|
|
1464
1697
|
create a file `app/views/comments/_form.html.erb` containing:
|
1465
1698
|
|
1466
1699
|
```html+erb
|
1467
|
-
<%= form_for([@
|
1700
|
+
<%= form_for([@article, @article.comments.build]) do |f| %>
|
1468
1701
|
<p>
|
1469
|
-
<%= f.label :commenter %><br
|
1702
|
+
<%= f.label :commenter %><br>
|
1470
1703
|
<%= f.text_field :commenter %>
|
1471
1704
|
</p>
|
1472
1705
|
<p>
|
1473
|
-
<%= f.label :body %><br
|
1706
|
+
<%= f.label :body %><br>
|
1474
1707
|
<%= f.text_area :body %>
|
1475
1708
|
</p>
|
1476
1709
|
<p>
|
@@ -1479,27 +1712,27 @@ create a file `app/views/comments/_form.html.erb` containing:
|
|
1479
1712
|
<% end %>
|
1480
1713
|
```
|
1481
1714
|
|
1482
|
-
Then you make the `app/views/
|
1715
|
+
Then you make the `app/views/articles/show.html.erb` look like the following:
|
1483
1716
|
|
1484
1717
|
```html+erb
|
1485
1718
|
<p>
|
1486
1719
|
<strong>Title:</strong>
|
1487
|
-
<%= @
|
1720
|
+
<%= @article.title %>
|
1488
1721
|
</p>
|
1489
1722
|
|
1490
1723
|
<p>
|
1491
1724
|
<strong>Text:</strong>
|
1492
|
-
<%= @
|
1725
|
+
<%= @article.text %>
|
1493
1726
|
</p>
|
1494
1727
|
|
1495
1728
|
<h2>Comments</h2>
|
1496
|
-
<%= render @
|
1729
|
+
<%= render @article.comments %>
|
1497
1730
|
|
1498
1731
|
<h2>Add a comment:</h2>
|
1499
1732
|
<%= render "comments/form" %>
|
1500
1733
|
|
1501
|
-
<%= link_to 'Edit
|
1502
|
-
<%= link_to 'Back to
|
1734
|
+
<%= link_to 'Edit Article', edit_article_path(@article) %> |
|
1735
|
+
<%= link_to 'Back to Articles', articles_path %>
|
1503
1736
|
```
|
1504
1737
|
|
1505
1738
|
The second render just defines the partial template we want to render,
|
@@ -1507,15 +1740,15 @@ The second render just defines the partial template we want to render,
|
|
1507
1740
|
string and realize that you want to render the `_form.html.erb` file in
|
1508
1741
|
the `app/views/comments` directory.
|
1509
1742
|
|
1510
|
-
The `@
|
1511
|
-
defined it as an instance variable.
|
1743
|
+
The `@article` object is available to any partials rendered in the view because
|
1744
|
+
we defined it as an instance variable.
|
1512
1745
|
|
1513
1746
|
Deleting Comments
|
1514
1747
|
-----------------
|
1515
1748
|
|
1516
1749
|
Another important feature of a blog is being able to delete spam comments. To do
|
1517
|
-
this, we need to implement a link of some sort in the view and a `
|
1518
|
-
in the `CommentsController`.
|
1750
|
+
this, we need to implement a link of some sort in the view and a `destroy`
|
1751
|
+
action in the `CommentsController`.
|
1519
1752
|
|
1520
1753
|
So first, let's add the delete link in the
|
1521
1754
|
`app/views/comments/_comment.html.erb` partial:
|
@@ -1532,88 +1765,93 @@ So first, let's add the delete link in the
|
|
1532
1765
|
</p>
|
1533
1766
|
|
1534
1767
|
<p>
|
1535
|
-
<%= link_to 'Destroy Comment', [comment.
|
1768
|
+
<%= link_to 'Destroy Comment', [comment.article, comment],
|
1536
1769
|
method: :delete,
|
1537
1770
|
data: { confirm: 'Are you sure?' } %>
|
1538
1771
|
</p>
|
1539
1772
|
```
|
1540
1773
|
|
1541
1774
|
Clicking this new "Destroy Comment" link will fire off a `DELETE
|
1542
|
-
/
|
1543
|
-
this to find the comment we want to delete, so let's add a destroy action
|
1544
|
-
controller (`app/controllers/comments_controller.rb`):
|
1775
|
+
/articles/:article_id/comments/:id` to our `CommentsController`, which can then
|
1776
|
+
use this to find the comment we want to delete, so let's add a `destroy` action
|
1777
|
+
to our controller (`app/controllers/comments_controller.rb`):
|
1545
1778
|
|
1546
1779
|
```ruby
|
1547
1780
|
class CommentsController < ApplicationController
|
1548
|
-
|
1549
1781
|
def create
|
1550
|
-
@
|
1551
|
-
@comment = @
|
1552
|
-
redirect_to
|
1782
|
+
@article = Article.find(params[:article_id])
|
1783
|
+
@comment = @article.comments.create(comment_params)
|
1784
|
+
redirect_to article_path(@article)
|
1553
1785
|
end
|
1554
1786
|
|
1555
1787
|
def destroy
|
1556
|
-
@
|
1557
|
-
@comment = @
|
1788
|
+
@article = Article.find(params[:article_id])
|
1789
|
+
@comment = @article.comments.find(params[:id])
|
1558
1790
|
@comment.destroy
|
1559
|
-
redirect_to
|
1791
|
+
redirect_to article_path(@article)
|
1560
1792
|
end
|
1561
1793
|
|
1794
|
+
private
|
1795
|
+
def comment_params
|
1796
|
+
params.require(:comment).permit(:commenter, :body)
|
1797
|
+
end
|
1562
1798
|
end
|
1563
1799
|
```
|
1564
1800
|
|
1565
|
-
The `destroy` action will find the
|
1566
|
-
within the `@
|
1567
|
-
database and send us back to the show action for the
|
1801
|
+
The `destroy` action will find the article we are looking at, locate the comment
|
1802
|
+
within the `@article.comments` collection, and then remove it from the
|
1803
|
+
database and send us back to the show action for the article.
|
1568
1804
|
|
1569
1805
|
|
1570
1806
|
### Deleting Associated Objects
|
1571
1807
|
|
1572
|
-
If you delete
|
1573
|
-
Otherwise they would simply occupy space in the database. Rails allows
|
1574
|
-
use the `dependent` option of an association to achieve this. Modify the
|
1575
|
-
model, `app/models/
|
1808
|
+
If you delete an article then its associated comments will also need to be
|
1809
|
+
deleted. Otherwise they would simply occupy space in the database. Rails allows
|
1810
|
+
you to use the `dependent` option of an association to achieve this. Modify the
|
1811
|
+
Article model, `app/models/article.rb`, as follows:
|
1576
1812
|
|
1577
1813
|
```ruby
|
1578
|
-
class
|
1814
|
+
class Article < ActiveRecord::Base
|
1579
1815
|
has_many :comments, dependent: :destroy
|
1580
1816
|
validates :title, presence: true,
|
1581
1817
|
length: { minimum: 5 }
|
1582
|
-
[...]
|
1583
1818
|
end
|
1584
1819
|
```
|
1585
1820
|
|
1586
1821
|
Security
|
1587
1822
|
--------
|
1588
1823
|
|
1824
|
+
### Basic Authentication
|
1825
|
+
|
1589
1826
|
If you were to publish your blog online, anybody would be able to add, edit and
|
1590
|
-
delete
|
1827
|
+
delete articles or delete comments.
|
1591
1828
|
|
1592
1829
|
Rails provides a very simple HTTP authentication system that will work nicely in
|
1593
1830
|
this situation.
|
1594
1831
|
|
1595
|
-
In the `
|
1832
|
+
In the `ArticlesController` we need to have a way to block access to the various
|
1596
1833
|
actions if the person is not authenticated, here we can use the Rails
|
1597
1834
|
`http_basic_authenticate_with` method, allowing access to the requested
|
1598
1835
|
action if that method allows it.
|
1599
1836
|
|
1600
1837
|
To use the authentication system, we specify it at the top of our
|
1601
|
-
`
|
1602
|
-
action, except for `index` and `show`, so we write that in
|
1838
|
+
`ArticlesController`, in this case, we want the user to be authenticated on
|
1839
|
+
every action, except for `index` and `show`, so we write that in
|
1840
|
+
`app/controllers/articles_controller.rb`:
|
1603
1841
|
|
1604
1842
|
```ruby
|
1605
|
-
class
|
1843
|
+
class ArticlesController < ApplicationController
|
1606
1844
|
|
1607
1845
|
http_basic_authenticate_with name: "dhh", password: "secret", except: [:index, :show]
|
1608
1846
|
|
1609
1847
|
def index
|
1610
|
-
@
|
1848
|
+
@articles = Article.all
|
1611
1849
|
end
|
1612
1850
|
|
1613
1851
|
# snipped for brevity
|
1614
1852
|
```
|
1615
1853
|
|
1616
|
-
We also
|
1854
|
+
We also want to allow only authenticated users to delete comments, so in the
|
1617
1855
|
`CommentsController` (`app/controllers/comments_controller.rb`) we write:
|
1618
1856
|
|
1619
1857
|
```ruby
|
@@ -1622,17 +1860,32 @@ class CommentsController < ApplicationController
|
|
1622
1860
|
http_basic_authenticate_with name: "dhh", password: "secret", only: :destroy
|
1623
1861
|
|
1624
1862
|
def create
|
1625
|
-
@
|
1863
|
+
@article = Article.find(params[:article_id])
|
1626
1864
|
...
|
1627
1865
|
end
|
1866
|
+
|
1628
1867
|
# snipped for brevity
|
1629
1868
|
```
|
1630
1869
|
|
1631
|
-
Now if you try to create a new
|
1870
|
+
Now if you try to create a new article, you will be greeted with a basic HTTP
|
1632
1871
|
Authentication challenge
|
1633
1872
|
|
1634
1873
|
![Basic HTTP Authentication Challenge](images/getting_started/challenge.png)
|
1635
1874
|
|
1875
|
+
Other authentication methods are available for Rails applications. Two popular
|
1876
|
+
authentication add-ons for Rails are the
|
1877
|
+
[Devise](https://github.com/plataformatec/devise) rails engine and
|
1878
|
+
the [Authlogic](https://github.com/binarylogic/authlogic) gem,
|
1879
|
+
along with a number of others.
|
1880
|
+
|
1881
|
+
|
1882
|
+
### Other Security Considerations
|
1883
|
+
|
1884
|
+
Security, especially in web applications, is a broad and detailed area. Security
|
1885
|
+
in your Rails application is covered in more depth in
|
1886
|
+
The [Ruby on Rails Security Guide](security.html)
|
1887
|
+
|
1888
|
+
|
1636
1889
|
What's Next?
|
1637
1890
|
------------
|
1638
1891
|
|
@@ -1646,12 +1899,19 @@ free to consult these support resources:
|
|
1646
1899
|
* The [Ruby on Rails mailing list](http://groups.google.com/group/rubyonrails-talk)
|
1647
1900
|
* The [#rubyonrails](irc://irc.freenode.net/#rubyonrails) channel on irc.freenode.net
|
1648
1901
|
|
1649
|
-
Rails also comes with built-in help that you can generate using the rake
|
1902
|
+
Rails also comes with built-in help that you can generate using the rake
|
1903
|
+
command-line utility:
|
1650
1904
|
|
1651
|
-
* Running `rake doc:guides` will put a full copy of the Rails Guides in the
|
1652
|
-
|
1905
|
+
* Running `rake doc:guides` will put a full copy of the Rails Guides in the
|
1906
|
+
`doc/guides` folder of your application. Open `doc/guides/index.html` in your
|
1907
|
+
web browser to explore the Guides.
|
1908
|
+
* Running `rake doc:rails` will put a full copy of the API documentation for
|
1909
|
+
Rails in the `doc/api` folder of your application. Open `doc/api/index.html`
|
1910
|
+
in your web browser to explore the API documentation.
|
1653
1911
|
|
1654
|
-
TIP: To be able to generate the Rails Guides locally with the `doc:guides` rake
|
1912
|
+
TIP: To be able to generate the Rails Guides locally with the `doc:guides` rake
|
1913
|
+
task you need to install the RedCloth gem. Add it to your `Gemfile` and run
|
1914
|
+
`bundle install` and you're ready to go.
|
1655
1915
|
|
1656
1916
|
Configuration Gotchas
|
1657
1917
|
---------------------
|
@@ -1671,15 +1931,16 @@ cannot be automatically detected by Rails and corrected.
|
|
1671
1931
|
|
1672
1932
|
Two very common sources of data that are not UTF-8:
|
1673
1933
|
|
1674
|
-
* Your text editor: Most text editors (such as TextMate), default to saving
|
1675
|
-
UTF-8. If your text editor does not, this can result in special
|
1676
|
-
enter in your templates (such as é) to appear as a diamond
|
1677
|
-
in the browser. This also applies to your i18n
|
1678
|
-
Most editors that do not already default to UTF-8 (such as
|
1679
|
-
Dreamweaver) offer a way to change the default to UTF-8. Do
|
1680
|
-
|
1681
|
-
|
1682
|
-
|
1683
|
-
|
1684
|
-
|
1685
|
-
|
1934
|
+
* Your text editor: Most text editors (such as TextMate), default to saving
|
1935
|
+
files as UTF-8. If your text editor does not, this can result in special
|
1936
|
+
characters that you enter in your templates (such as é) to appear as a diamond
|
1937
|
+
with a question mark inside in the browser. This also applies to your i18n
|
1938
|
+
translation files. Most editors that do not already default to UTF-8 (such as
|
1939
|
+
some versions of Dreamweaver) offer a way to change the default to UTF-8. Do
|
1940
|
+
so.
|
1941
|
+
* Your database: Rails defaults to converting data from your database into UTF-8
|
1942
|
+
at the boundary. However, if your database is not using UTF-8 internally, it
|
1943
|
+
may not be able to store all characters that your users enter. For instance,
|
1944
|
+
if your database is using Latin-1 internally, and your user enters a Russian,
|
1945
|
+
Hebrew, or Japanese character, the data will be lost forever once it enters
|
1946
|
+
the database. If possible, use UTF-8 as the internal storage of your database.
|