kitabu 1.0.6 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +5 -3
- data/.travis.yml +18 -0
- data/CHANGELOG.md +9 -0
- data/Gemfile.lock +67 -50
- data/README.md +235 -0
- data/attachments/browser-version.png +0 -0
- data/attachments/cover.png +0 -0
- data/attachments/kitabu.epub +0 -0
- data/attachments/kitabu.mobi +0 -0
- data/attachments/kitabu.pdf +0 -0
- data/{spec/support/mybook/output → examples/kitabu/output/epub/images}/.gitkeep +0 -0
- data/examples/kitabu/output/epub/images/kitabu-icon.png +0 -0
- data/examples/kitabu/output/epub/images/kitabu-icon.svg +19 -0
- data/examples/kitabu/output/epub/images/kitabu-word.png +0 -0
- data/examples/kitabu/output/epub/images/kitabu-word.svg +14 -0
- data/examples/kitabu/output/epub/images/kitabu.png +0 -0
- data/examples/kitabu/output/epub/images/kitabu.svg +20 -0
- data/examples/kitabu/output/epub/section_0.html +266 -0
- data/examples/kitabu/output/epub/section_1.html +246 -0
- data/examples/kitabu/output/epub/section_2.html +520 -0
- data/examples/kitabu/output/epub/section_3.html +282 -0
- data/examples/kitabu/output/epub/section_4.html +276 -0
- data/examples/kitabu/output/epub/styles/epub.css +437 -0
- data/examples/kitabu/output/epub/styles/html.css +712 -0
- data/examples/kitabu/output/epub/styles/pdf.css +840 -0
- data/examples/kitabu/output/epub/styles/print.css +1278 -0
- data/examples/kitabu/output/epub/toc.html +37 -0
- data/{spec/support/mybook/templates/epub/style.css → examples/kitabu/output/images/.gitkeep} +0 -0
- data/examples/kitabu/output/images/kitabu-icon.png +0 -0
- data/examples/kitabu/output/images/kitabu-icon.svg +19 -0
- data/examples/kitabu/output/images/kitabu-word.png +0 -0
- data/examples/kitabu/output/images/kitabu-word.svg +14 -0
- data/examples/kitabu/output/images/kitabu.png +0 -0
- data/examples/kitabu/output/images/kitabu.svg +20 -0
- data/examples/kitabu/output/kitabu.epub +0 -0
- data/examples/kitabu/output/kitabu.html +513 -0
- data/examples/kitabu/output/kitabu.mobi +0 -0
- data/examples/kitabu/output/kitabu.pdf +0 -0
- data/examples/kitabu/output/kitabu.pdf.html +729 -0
- data/examples/kitabu/output/kitabu.print.html +729 -0
- data/examples/kitabu/output/kitabu.print.pdf +0 -0
- data/examples/kitabu/output/kitabu.txt +440 -0
- data/examples/kitabu/output/styles/epub.css +437 -0
- data/examples/kitabu/output/styles/html.css +712 -0
- data/examples/kitabu/output/styles/pdf.css +840 -0
- data/examples/kitabu/output/styles/print.css +1278 -0
- data/kitabu.gemspec +7 -5
- data/lib/kitabu.rb +10 -20
- data/lib/kitabu/cli.rb +0 -5
- data/lib/kitabu/dependency.rb +0 -4
- data/lib/kitabu/exporter.rb +2 -0
- data/lib/kitabu/extensions/rouge.rb +9 -0
- data/lib/kitabu/generator.rb +9 -21
- data/lib/kitabu/helpers.rb +47 -0
- data/lib/kitabu/markdown.rb +31 -0
- data/lib/kitabu/parser.rb +21 -3
- data/lib/kitabu/parser/epub.rb +31 -18
- data/lib/kitabu/parser/html.rb +48 -29
- data/lib/kitabu/parser/mobi.rb +1 -1
- data/lib/kitabu/parser/pdf.rb +52 -8
- data/lib/kitabu/version.rb +2 -2
- data/spec/kitabu/cli/export_spec.rb +4 -4
- data/spec/kitabu/cli/new_spec.rb +2 -2
- data/spec/kitabu/markdown_spec.rb +24 -0
- data/spec/kitabu/parser/html_spec.rb +20 -25
- data/spec/kitabu/parser/mobi_spec.rb +14 -0
- data/spec/kitabu/parser/pdf_spec.rb +18 -1
- data/spec/kitabu/parser/txt_spec.rb +14 -0
- data/spec/spec_helper.rb +10 -6
- data/spec/support/mybook/config/helper.rb +4 -29
- data/spec/support/mybook/config/kitabu.yml +0 -10
- data/spec/support/mybook/templates/epub/cover.erb +4 -3
- data/{templates → spec/support/mybook/templates/epub}/cover.png +0 -0
- data/spec/support/mybook/templates/epub/page.erb +3 -2
- data/spec/support/mybook/templates/html/layout.erb +10 -13
- data/spec/support/mybook/templates/styles/epub.scss +3 -0
- data/spec/support/mybook/templates/styles/html.scss +3 -0
- data/spec/support/mybook/templates/styles/pdf.scss +3 -0
- data/spec/support/mybook/templates/styles/print.scss +3 -0
- data/spec/support/mybook/text/{01_Markdown_Chapter.markdown → 01_Markdown_Chapter.md} +2 -3
- data/spec/support/mybook/text/02_ERB_Chapter.md.erb +7 -0
- data/spec/support/mybook/text/{04_With_Directory/Some_Chapter.mkdn → 03_With_Directory/Some_Chapter.md} +0 -0
- data/spec/support/mybook/text/{CHANGELOG.textile → CHANGELOG.md} +2 -2
- data/spec/support/mybook/text/{TOC.textile → TOC.md} +0 -0
- data/spec/support/mybook/text/{_00_Introduction.markdown → _00_Introduction.md} +0 -0
- data/spec/support/shared.rb +14 -10
- data/templates/Gemfile +3 -3
- data/templates/Guardfile +1 -5
- data/templates/config.erb +5 -5
- data/templates/cover.erb +4 -3
- data/templates/epub.erb +3 -2
- data/templates/helper.rb +28 -29
- data/templates/images/.gitkeep +0 -0
- data/templates/images/kitabu-icon.png +0 -0
- data/templates/images/kitabu-icon.svg +19 -0
- data/templates/images/kitabu-word.png +0 -0
- data/templates/images/kitabu-word.svg +14 -0
- data/templates/images/kitabu.png +0 -0
- data/templates/images/kitabu.svg +20 -0
- data/{examples/RailsGuides/templates → templates/templates/epub}/cover.erb +4 -3
- data/templates/templates/epub/cover.png +0 -0
- data/templates/templates/epub/page.erb +16 -0
- data/templates/{layout.erb → templates/html/layout.erb} +22 -11
- data/templates/templates/styles/epub.scss +1 -0
- data/templates/templates/styles/files/_normalize.scss +427 -0
- data/templates/templates/styles/html.scss +252 -0
- data/templates/templates/styles/pdf.scss +371 -0
- data/templates/templates/styles/print.scss +2 -0
- data/templates/text/01_Getting_Started.md +26 -0
- data/templates/text/02_Creating_Chapters.md +22 -0
- data/templates/text/03_Syntax_Highlighting.erb +69 -0
- data/templates/text/04_Dynamic_Content.erb +64 -0
- data/templates/text/05_Exporting_Files.md +49 -0
- metadata +143 -83
- data/README.rdoc +0 -218
- data/examples/RailsGuides/config/helper.rb +0 -29
- data/examples/RailsGuides/config/kitabu.yml +0 -44
- data/examples/RailsGuides/images/challenge.png +0 -0
- data/examples/RailsGuides/images/posts_index.png +0 -0
- data/examples/RailsGuides/images/rails_welcome.png +0 -0
- data/examples/RailsGuides/output/RailsGuides.epub +0 -0
- data/examples/RailsGuides/output/RailsGuides.html +0 -1556
- data/examples/RailsGuides/output/RailsGuides.pdf +3 -4934
- data/examples/RailsGuides/templates/layout.css +0 -352
- data/examples/RailsGuides/templates/layout.erb +0 -43
- data/examples/RailsGuides/templates/syntax.css +0 -62
- data/examples/RailsGuides/templates/user.css +0 -19
- data/examples/RailsGuides/text/01_Guide_Assumptions.mkdn +0 -13
- data/examples/RailsGuides/text/02_What_is_Rails.mkdn +0 -106
- data/examples/RailsGuides/text/03_Creating_a_new_Rails_project.mkdn +0 -200
- data/examples/RailsGuides/text/04_Hello_Rails.mkdn +0 -62
- data/examples/RailsGuides/text/05_Getting_Up_and_Running_Quickly_with_Scaffolding.mkdn +0 -4
- data/examples/RailsGuides/text/06_Creating_a_resource.mkdn +0 -503
- data/examples/RailsGuides/text/07_Adding_a_second_model.mkdn +0 -232
- data/examples/RailsGuides/text/08_Refactoring.mkdn +0 -123
- data/examples/RailsGuides/text/09_Deleting_comments.mkdn +0 -57
- data/examples/RailsGuides/text/09_Security.mkdn +0 -56
- data/examples/RailsGuides/text/10_Building_a_multi_model_form.mkdn +0 -130
- data/examples/RailsGuides/text/11_View_helpers.mkdn +0 -50
- data/examples/RailsGuides/text/12_Whats_next.mkdn +0 -14
- data/examples/RailsGuides/text/13_Configuration_gotchas.mkdn +0 -10
- data/lib/kitabu/adapters/markdown.rb +0 -34
- data/lib/kitabu/extensions/redcloth.rb +0 -69
- data/lib/kitabu/syntax.rb +0 -130
- data/spec/kitabu/extensions/redcloth_spec.rb +0 -57
- data/spec/kitabu/syntax_spec.rb +0 -106
- data/spec/support/mybook/templates/html/layout.css +0 -353
- data/spec/support/mybook/templates/html/syntax.css +0 -58
- data/spec/support/mybook/templates/html/user.css +0 -1
- data/spec/support/mybook/text/02_Textile_Chapter.textile +0 -3
- data/spec/support/mybook/text/03_HTML_Chapter.html +0 -3
- data/templates/epub.css +0 -500
- data/templates/layout.css +0 -353
- data/templates/sample.md +0 -6
- data/templates/syntax.css +0 -58
- data/templates/user.css +0 -1
@@ -1,232 +0,0 @@
|
|
1
|
-
## Adding a Second Model
|
2
|
-
|
3
|
-
Now that you’ve seen how a model built with scaffolding looks like, it’s time to add a second model to the application. The second model will handle comments on blog posts.
|
4
|
-
|
5
|
-
### Generating a Model
|
6
|
-
|
7
|
-
Models in Rails use a singular name, and their corresponding database tables use a plural name. For the model to hold comments, the convention is to use the name Comment. Even if you don’t want to use the entire apparatus set up by scaffolding, most Rails developers still use generators to make things like models and controllers. To create the new model, run this command in your terminal:
|
8
|
-
|
9
|
-
$ rails generate model Comment commenter:string body:text post:references
|
10
|
-
|
11
|
-
This command will generate four files:
|
12
|
-
|
13
|
-
* `app/models/comment.rb` – The model
|
14
|
-
* `db/migrate/20100207235629_create_comments.rb` – The migration
|
15
|
-
* `test/unit/comment_test.rb and test/fixtures/comments.yml` – The test harness.
|
16
|
-
|
17
|
-
First, take a look at `comment.rb`:
|
18
|
-
|
19
|
-
@@@ ruby
|
20
|
-
class Comment < ActiveRecord::Base
|
21
|
-
belongs_to :post
|
22
|
-
end
|
23
|
-
@@@
|
24
|
-
|
25
|
-
This is very similar to the `post.rb` model that you saw earlier. The difference is the line `belongs_to :post`, which sets up an Active Record *association*. You’ll learn a little about associations in the next section of this guide.
|
26
|
-
|
27
|
-
In addition to the model, Rails has also made a migration to create the corresponding database table:
|
28
|
-
|
29
|
-
@@@ ruby
|
30
|
-
class CreateComments < ActiveRecord::Migration
|
31
|
-
def self.up
|
32
|
-
create_table :comments do |t|
|
33
|
-
t.string :commenter
|
34
|
-
t.text :body
|
35
|
-
t.references :post
|
36
|
-
|
37
|
-
t.timestamps
|
38
|
-
end
|
39
|
-
end
|
40
|
-
|
41
|
-
def self.down
|
42
|
-
drop_table :comments
|
43
|
-
end
|
44
|
-
end
|
45
|
-
@@@
|
46
|
-
|
47
|
-
The `t.references` line sets up a foreign key column for the association between the two models. Go ahead and run the migration:
|
48
|
-
|
49
|
-
$ rake db:migrate
|
50
|
-
|
51
|
-
Rails is smart enough to only execute the migrations that have not already been run against the current database, so in this case you will just see:
|
52
|
-
|
53
|
-
== CreateComments: migrating ============
|
54
|
-
-- create_table(:comments)
|
55
|
-
-> 0.0017s
|
56
|
-
== CreateComments: migrated (0.0018s) ===
|
57
|
-
|
58
|
-
### Associating Models
|
59
|
-
|
60
|
-
Active Record associations let you easily declare the relationship between two models. In the case of comments and posts, you could write out the relationships this way:
|
61
|
-
|
62
|
-
* Each comment belongs to one post
|
63
|
-
* One post can have many comments
|
64
|
-
|
65
|
-
In fact, this is very close to the syntax that Rails uses to declare this association. You’ve already seen the line of code inside the Comment model that makes each comment belong to a Post:
|
66
|
-
|
67
|
-
@@@ ruby
|
68
|
-
class Comment < ActiveRecord::Base
|
69
|
-
belongs_to :post
|
70
|
-
end
|
71
|
-
@@@
|
72
|
-
|
73
|
-
You’ll need to edit the `post.rb` file to add the other side of the association:
|
74
|
-
|
75
|
-
@@@ ruby
|
76
|
-
class Post < ActiveRecord::Base
|
77
|
-
validates :name, :presence => true
|
78
|
-
validates :title, :presence => true,
|
79
|
-
:length => { :minimum => 5 }
|
80
|
-
|
81
|
-
has_many :comments
|
82
|
-
end
|
83
|
-
@@@
|
84
|
-
|
85
|
-
These two declarations enable a good bit of automatic behavior. For example, if you have an instance variable `@post` containing a post, you can retrieve all the comments belonging to that post as the array `@post.comments`.
|
86
|
-
|
87
|
-
<p class="notice">
|
88
|
-
For more information on Active Record associations, see the <a href="http://guides.rubyonrails.org/association_basics.html" title="Ruby on Rails Guides: A Guide to Active Record Associations">Active Record Associations</a> guide.
|
89
|
-
</p>
|
90
|
-
|
91
|
-
### Adding a Route for Comments
|
92
|
-
|
93
|
-
As with the `home` controller, we will need to add a route so that Rails knows where we would like to navigate to see `comments`. Open up the `config/routes.rb` file again, you will see an entry that was added automatically for posts near the top by the scaffold generator, `resources :posts`, edit it as follows:
|
94
|
-
|
95
|
-
@@@ ruby
|
96
|
-
resources :posts do
|
97
|
-
resources :comments
|
98
|
-
end
|
99
|
-
@@@
|
100
|
-
|
101
|
-
This creates `comments` as a *nested resource* within `posts`. This is another part of capturing the hierarchical relationship that exists between posts and comments.
|
102
|
-
|
103
|
-
<p class="notice">
|
104
|
-
For more information on routing, see the <a href="http://guides.rubyonrails.org/routing.html" title="Ruby on Rails Guides: Rails Routing from the Outside In">Rails Routing from the Outside In</a> guide.
|
105
|
-
</p>
|
106
|
-
|
107
|
-
### Generating a Controller
|
108
|
-
|
109
|
-
With the model in hand, you can turn your attention to creating a matching controller. Again, there’s a generator for this:
|
110
|
-
|
111
|
-
$ rails generate controller Comments
|
112
|
-
|
113
|
-
This creates four files and one empty directory:
|
114
|
-
|
115
|
-
* `app/controllers/comments_controller.rb` – The controller
|
116
|
-
* `app/helpers/comments_helper.rb` – A view helper file
|
117
|
-
* `test/functional/comments_controller_test.rb` – The functional tests for the controller
|
118
|
-
* `test/unit/helpers/comments_helper_test.rb` – The unit tests for the helper
|
119
|
-
* `app/views/comments/` – Views of the controller are stored here
|
120
|
-
|
121
|
-
Like with any blog, our readers will create their comments directly after reading the post, and once they have added their comment, will be sent back to the post show page to see their comment now listed. Due to this, our `CommentsController` is there to provide a method to create comments and delete SPAM comments when they arrive.
|
122
|
-
|
123
|
-
So first, we’ll wire up the Post show template (`/app/views/posts/show.html.erb`) to let us make a new comment:
|
124
|
-
|
125
|
-
@@@ html
|
126
|
-
<p class="notice"><%= notice %></p>
|
127
|
-
|
128
|
-
<p>
|
129
|
-
<b>Name:</b>
|
130
|
-
<%= @post.name %>
|
131
|
-
</p>
|
132
|
-
|
133
|
-
<p>
|
134
|
-
<b>Title:</b>
|
135
|
-
<%= @post.title %>
|
136
|
-
</p>
|
137
|
-
|
138
|
-
<p>
|
139
|
-
<b>Content:</b>
|
140
|
-
<%= @post.content %>
|
141
|
-
</p>
|
142
|
-
|
143
|
-
<h2>Add a comment:</h2>
|
144
|
-
<%= form_for([@post, @post.comments.build]) do |f| %>
|
145
|
-
<div class="field">
|
146
|
-
<%= f.label :commenter %><br />
|
147
|
-
<%= f.text_field :commenter %>
|
148
|
-
</div>
|
149
|
-
<div class="field">
|
150
|
-
<%= f.label :body %><br />
|
151
|
-
<%= f.text_area :body %>
|
152
|
-
</div>
|
153
|
-
<div class="actions">
|
154
|
-
<%= f.submit %>
|
155
|
-
</div>
|
156
|
-
<% end %>
|
157
|
-
|
158
|
-
<%= link_to 'Edit Post', edit_post_path(@post) %> |
|
159
|
-
<%= link_to 'Back to Posts', posts_path %> |
|
160
|
-
@@@
|
161
|
-
|
162
|
-
This adds a form on the Post show page that creates a new comment, which will call the `CommentsController` create action, so let’s wire that up:
|
163
|
-
|
164
|
-
@@@ ruby
|
165
|
-
class CommentsController < ApplicationController
|
166
|
-
def create
|
167
|
-
@post = Post.find(params[:post_id])
|
168
|
-
@comment = @post.comments.create(params[:comment])
|
169
|
-
redirect_to post_path(@post)
|
170
|
-
end
|
171
|
-
end
|
172
|
-
@@@
|
173
|
-
|
174
|
-
You’ll see a bit more complexity here than you did in the controller for posts. That’s a side-effect of the nesting that you’ve set up; each request for a comment has to keep track of the post to which the comment is attached, thus the initial find action to the Post model to get the post in question.
|
175
|
-
|
176
|
-
In addition, the code takes advantage of some of the methods available for an association. We use the `create` method on `@post.comments` to create and save the comment. This will automatically link the comment so that it belongs to that particular post.
|
177
|
-
|
178
|
-
Once we have made the new comment, we send the user back to the original post using the `post_path(@post)` helper. As we have already seen, this calls the `show` action of the `PostsController` which in turn renders the `show.html.erb` template. This is where we want the comment to show, so let’s add that to the `app/views/posts/show.html.erb`.
|
179
|
-
|
180
|
-
@@@ html
|
181
|
-
<p class="notice"><%= notice %></p>
|
182
|
-
|
183
|
-
<p>
|
184
|
-
<b>Name:</b>
|
185
|
-
<%= @post.name %>
|
186
|
-
</p>
|
187
|
-
|
188
|
-
<p>
|
189
|
-
<b>Title:</b>
|
190
|
-
<%= @post.title %>
|
191
|
-
</p>
|
192
|
-
|
193
|
-
<p>
|
194
|
-
<b>Content:</b>
|
195
|
-
<%= @post.content %>
|
196
|
-
</p>
|
197
|
-
|
198
|
-
<h2>Comments</h2>
|
199
|
-
<% @post.comments.each do |comment| %>
|
200
|
-
<p>
|
201
|
-
<b>Commenter:</b>
|
202
|
-
<%= comment.commenter %>
|
203
|
-
</p>
|
204
|
-
|
205
|
-
<p>
|
206
|
-
<b>Comment:</b>
|
207
|
-
<%= comment.body %>
|
208
|
-
</p>
|
209
|
-
<% end %>
|
210
|
-
|
211
|
-
<h2>Add a comment:</h2>
|
212
|
-
<%= form_for([@post, @post.comments.build]) do |f| %>
|
213
|
-
<div class="field">
|
214
|
-
<%= f.label :commenter %><br />
|
215
|
-
<%= f.text_field :commenter %>
|
216
|
-
</div>
|
217
|
-
<div class="field">
|
218
|
-
<%= f.label :body %><br />
|
219
|
-
<%= f.text_area :body %>
|
220
|
-
</div>
|
221
|
-
<div class="actions">
|
222
|
-
<%= f.submit %>
|
223
|
-
</div>
|
224
|
-
<% end %>
|
225
|
-
|
226
|
-
<br />
|
227
|
-
|
228
|
-
<%= link_to 'Edit Post', edit_post_path(@post) %> |
|
229
|
-
<%= link_to 'Back to Posts', posts_path %> |
|
230
|
-
@@@
|
231
|
-
|
232
|
-
Now you can add posts and comments to your blog and have them show up in the right places.
|
@@ -1,123 +0,0 @@
|
|
1
|
-
## Refactoring
|
2
|
-
|
3
|
-
Now that we have Posts and Comments working, if we take a look at the `app/views/posts/show.html.erb` template, it’s getting long and awkward. We can use partials to clean this up.
|
4
|
-
|
5
|
-
### Rendering Partial Collections
|
6
|
-
|
7
|
-
First we will make a comment partial to extract showing all the comments for the post. Create the file `app/views/comments/_comment.html.erb` and put the following into it:
|
8
|
-
|
9
|
-
@@@ html
|
10
|
-
<p>
|
11
|
-
<b>Commenter:</b>
|
12
|
-
<%= comment.commenter %>
|
13
|
-
</p>
|
14
|
-
|
15
|
-
<p>
|
16
|
-
<b>Comment:</b>
|
17
|
-
<%= comment.body %>
|
18
|
-
</p>
|
19
|
-
@@@
|
20
|
-
|
21
|
-
Then in the `app/views/posts/show.html.erb` you can change it to look like the following:
|
22
|
-
|
23
|
-
@@@ html
|
24
|
-
<p class="notice"><%= notice %></p>
|
25
|
-
|
26
|
-
<p>
|
27
|
-
<b>Name:</b>
|
28
|
-
<%= @post.name %>
|
29
|
-
</p>
|
30
|
-
|
31
|
-
<p>
|
32
|
-
<b>Title:</b>
|
33
|
-
<%= @post.title %>
|
34
|
-
</p>
|
35
|
-
|
36
|
-
<p>
|
37
|
-
<b>Content:</b>
|
38
|
-
<%= @post.content %>
|
39
|
-
</p>
|
40
|
-
|
41
|
-
<h2>Comments</h2>
|
42
|
-
<%= render :partial => "comments/comment",
|
43
|
-
:collection => @post.comments %>
|
44
|
-
|
45
|
-
<h2>Add a comment:</h2>
|
46
|
-
<%= form_for([@post, @post.comments.build]) do |f| %>
|
47
|
-
<div class="field">
|
48
|
-
<%= f.label :commenter %><br />
|
49
|
-
<%= f.text_field :commenter %>
|
50
|
-
</div>
|
51
|
-
<div class="field">
|
52
|
-
<%= f.label :body %><br />
|
53
|
-
<%= f.text_area :body %>
|
54
|
-
</div>
|
55
|
-
<div class="actions">
|
56
|
-
<%= f.submit %>
|
57
|
-
</div>
|
58
|
-
<% end %>
|
59
|
-
|
60
|
-
<br />
|
61
|
-
|
62
|
-
<%= link_to 'Edit Post', edit_post_path(@post) %> |
|
63
|
-
<%= link_to 'Back to Posts', posts_path %> |
|
64
|
-
@@@
|
65
|
-
|
66
|
-
This will now render the partial in `app/views/comments/_comment.html.erb` once for each comment that is in the `@post.comments collection`. As the render method iterates over the `@post.comments` collection, it assigns each comment to a local variable named the same as the partial, in this case comment which is then available in the partial for us to show.
|
67
|
-
|
68
|
-
### Rendering a Partial Form
|
69
|
-
|
70
|
-
Lets also move that new comment section out to it’s own partial, again, you create a file `app/views/comments/_form.html.erb` and in it you put:
|
71
|
-
|
72
|
-
@@@ html
|
73
|
-
<%= form_for([@post, @post.comments.build]) do |f| %>
|
74
|
-
<div class="field">
|
75
|
-
<%= f.label :commenter %><br />
|
76
|
-
<%= f.text_field :commenter %>
|
77
|
-
</div>
|
78
|
-
<div class="field">
|
79
|
-
<%= f.label :body %><br />
|
80
|
-
<%= f.text_area :body %>
|
81
|
-
</div>
|
82
|
-
<div class="actions">
|
83
|
-
<%= f.submit %>
|
84
|
-
</div>
|
85
|
-
<% end %>
|
86
|
-
@@@
|
87
|
-
|
88
|
-
Then you make the `app/views/posts/show.html.erb` look like the following:
|
89
|
-
|
90
|
-
@@@ html
|
91
|
-
<p class="notice"><%= notice %></p>
|
92
|
-
|
93
|
-
<p>
|
94
|
-
<b>Name:</b>
|
95
|
-
<%= @post.name %>
|
96
|
-
</p>
|
97
|
-
|
98
|
-
<p>
|
99
|
-
<b>Title:</b>
|
100
|
-
<%= @post.title %>
|
101
|
-
</p>
|
102
|
-
|
103
|
-
<p>
|
104
|
-
<b>Content:</b>
|
105
|
-
<%= @post.content %>
|
106
|
-
</p>
|
107
|
-
|
108
|
-
<h2>Comments</h2>
|
109
|
-
<%= render :partial => "comments/comment",
|
110
|
-
:collection => @post.comments %>
|
111
|
-
|
112
|
-
<h2>Add a comment:</h2>
|
113
|
-
<%= render "comments/form" %>
|
114
|
-
|
115
|
-
<br />
|
116
|
-
|
117
|
-
<%= link_to 'Edit Post', edit_post_path(@post) %> |
|
118
|
-
<%= link_to 'Back to Posts', posts_path %> |
|
119
|
-
@@@
|
120
|
-
|
121
|
-
The second render just defines the partial template we want to render, `comments/form`, Rails is smart enough to spot the forward slash in that string and realize that you want to render the `_form.html.erb` file in the `app/views/comments` directory.
|
122
|
-
|
123
|
-
The `@post` object is available to any partials rendered in the view because we defined it as an instance variable.
|
@@ -1,57 +0,0 @@
|
|
1
|
-
## Deleting Comments
|
2
|
-
|
3
|
-
Another important feature on a blog is being able to delete SPAM comments. To do this, we need to implement a link of some sort in the view and a `DELETE` action in the `CommentsController`.
|
4
|
-
|
5
|
-
So first, let’s add the delete link in the `app/views/comments/_comment.html.erb` partial:
|
6
|
-
|
7
|
-
@@@ html
|
8
|
-
<p>
|
9
|
-
<b>Commenter:</b>
|
10
|
-
<%= comment.commenter %>
|
11
|
-
</p>
|
12
|
-
|
13
|
-
<p>
|
14
|
-
<b>Comment:</b>
|
15
|
-
<%= comment.body %>
|
16
|
-
</p>
|
17
|
-
|
18
|
-
<p>
|
19
|
-
<%= link_to 'Destroy Comment', [comment.post, comment],
|
20
|
-
:confirm => 'Are you sure?',
|
21
|
-
:method => :delete %>
|
22
|
-
</p>
|
23
|
-
@@@
|
24
|
-
|
25
|
-
Clicking this new “Destroy Comment” link will fire off a `DELETE /posts/:id/comments/:id` to our `CommentsController`, which can then use this to find the comment we want to delete, so let’s add a `destroy` action to our controller:
|
26
|
-
|
27
|
-
@@@ ruby
|
28
|
-
class CommentsController < ApplicationController
|
29
|
-
def create
|
30
|
-
@post = Post.find(params[:post_id])
|
31
|
-
@comment = @post.comments.create(params[:comment])
|
32
|
-
redirect_to post_path(@post)
|
33
|
-
end
|
34
|
-
|
35
|
-
def destroy
|
36
|
-
@post = Post.find(params[:post_id])
|
37
|
-
@comment = @post.comments.find(params[:id])
|
38
|
-
@comment.destroy
|
39
|
-
redirect_to post_path(@post)
|
40
|
-
end
|
41
|
-
end
|
42
|
-
@@@
|
43
|
-
|
44
|
-
The `destroy` action will find the post we are looking at, locate the comment within the `@post.comments` collection, and then remove it from the database and send us back to the `show` action for the post.
|
45
|
-
|
46
|
-
### Deleting Associated Objects
|
47
|
-
|
48
|
-
If you delete a post then its associated comments will also need to be deleted. Otherwise they would simply occupy space in the database. Rails allows you to use the `dependent` option of an association to achieve this. Modify the `Post` model, `app/models/post.rb`, as follows:
|
49
|
-
|
50
|
-
@@@ ruby
|
51
|
-
class Post < ActiveRecord::Base
|
52
|
-
validates :name, :presence => true
|
53
|
-
validates :title, :presence => true,
|
54
|
-
:length => { :minimum => 5 }
|
55
|
-
has_many :comments, :dependent => :destroy
|
56
|
-
end
|
57
|
-
@@@
|
@@ -1,56 +0,0 @@
|
|
1
|
-
## Security
|
2
|
-
|
3
|
-
If you were to publish your blog online, anybody would be able to add, edit and delete posts or delete comments.
|
4
|
-
|
5
|
-
Rails provides a very simple HTTP authentication system that will work nicely in this situation. First, we enable simple HTTP based authentication in our `app/controllers/application_controller.rb`:
|
6
|
-
|
7
|
-
@@@ ruby
|
8
|
-
class ApplicationController < ActionController::Base
|
9
|
-
protect_from_forgery
|
10
|
-
|
11
|
-
private
|
12
|
-
|
13
|
-
def authenticate
|
14
|
-
authenticate_or_request_with_http_basic do |user_name, password|
|
15
|
-
user_name == 'admin' && password == 'password'
|
16
|
-
end
|
17
|
-
end
|
18
|
-
end
|
19
|
-
@@@
|
20
|
-
|
21
|
-
You can obviously change the username and password to whatever you want. We put this method inside of `ApplicationController` so that it is available to all of our controllers.
|
22
|
-
|
23
|
-
Then in the `PostsController` we need to have a way to block access to the various actions if the person is not authenticated, here we can use the Rails `before_filter` method, which allows us to specify that Rails must run a method and only then allow access to the requested action if that method allows it.
|
24
|
-
|
25
|
-
To use the before filter, we specify it at the top of our `PostsController`, in this case, we want the user to be authenticated on every action, except for `index` and `show`, so we write that:
|
26
|
-
|
27
|
-
@@@ ruby
|
28
|
-
class PostsController < ApplicationController
|
29
|
-
|
30
|
-
before_filter :authenticate, :except => [:index, :show]
|
31
|
-
|
32
|
-
# GET /posts
|
33
|
-
# GET /posts.xml
|
34
|
-
def index
|
35
|
-
@posts = Post.all
|
36
|
-
respond_to do |format|
|
37
|
-
# snipped for brevity
|
38
|
-
@@@
|
39
|
-
|
40
|
-
<p class="figure">
|
41
|
-
<img src="../images/challenge.png" alt="Basic Auth challenge window" />
|
42
|
-
</p>
|
43
|
-
|
44
|
-
We also only want to allow authenticated users to delete comments, so in the `CommentsController` we write:
|
45
|
-
|
46
|
-
@@@ ruby
|
47
|
-
class CommentsController < ApplicationController
|
48
|
-
|
49
|
-
before_filter :authenticate, :only => :destroy
|
50
|
-
|
51
|
-
def create
|
52
|
-
@post = Post.find(params[:post_id])
|
53
|
-
# snipped for brevity
|
54
|
-
@@@
|
55
|
-
|
56
|
-
Now if you try to create a new post, you will be greeted with a basic HTTP Authentication challenge.
|