diff options
Diffstat (limited to 'guides/source/getting_started.textile')
-rw-r--r-- | guides/source/getting_started.textile | 326 |
1 files changed, 46 insertions, 280 deletions
diff --git a/guides/source/getting_started.textile b/guides/source/getting_started.textile index 44f3b978db..947abd7ba0 100644 --- a/guides/source/getting_started.textile +++ b/guides/source/getting_started.textile @@ -87,7 +87,10 @@ To install Rails, use the +gem install+ command provided by RubyGems: # gem install rails </shell> -TIP. If you're working on Windows, you can quickly install Ruby and Rails with "Rails Installer":http://railsinstaller.org. +TIP. A number of tools exist to help you quickly install Ruby and Ruby +on Rails on your system. Windows users can use "Rails +Installer":http://railsinstaller.org, while Mac OS X users can use +"Rails One Click":http://railsoneclick.com. To verify that you have everything installed correctly, you should be able to run the following: @@ -401,7 +404,10 @@ $ rails generate model Post title:string text:text With that command we told Rails that we want a +Post+ model, which in turn should have a title attribute of type string, and a text attribute -of type text. Rails in turn responded by creating a bunch of files. For +of type text. Those attributes are automatically added to the +posts+ +table in the database and mapped to the +Post+ model. + +Rails in turn responded by creating a bunch of files. For now, we're only interested in +app/models/post.rb+ and +db/migrate/20120419084633_create_posts.rb+. The latter is responsible for creating the database structure, which is what we'll look at next. @@ -1367,60 +1373,53 @@ template. This is where we want the comment to show, so let's add that to the +app/views/posts/show.html.erb+. <erb> -<p id="notice"><%= notice %></p> - -<p> - <b>Name:</b> - <%= @post.name %> -</p> - <p> - <b>Title:</b> + <strong>Title:</strong> <%= @post.title %> </p> <p> - <b>Content:</b> - <%= @post.content %> + <strong>Text:</strong> + <%= @post.texthttp://beginningruby.org/ %> </p> <h2>Comments</h2> <% @post.comments.each do |comment| %> <p> - <b>Commenter:</b> + <strong>Commenter:</strong> <%= comment.commenter %> </p> <p> - <b>Comment:</b> + <strong>Comment:</strong> <%= comment.body %> </p> <% end %> <h2>Add a comment:</h2> <%= form_for([@post, @post.comments.build]) do |f| %> - <div class="field"> + <p> <%= f.label :commenter %><br /> <%= f.text_field :commenter %> - </div> - <div class="field"> + </p> + <p> <%= f.label :body %><br /> <%= f.text_area :body %> - </div> - <div class="actions"> + </p> + <p> <%= f.submit %> - </div> + </p> <% end %> -<br /> - <%= link_to 'Edit Post', edit_post_path(@post) %> | -<%= link_to 'Back to Posts', posts_path %> | +<%= link_to 'Back to Posts', posts_path %> </erb> Now you can add posts and comments to your blog and have them show up in the right places. +!images/getting_started/post_with_comments.png(Post with Comments)! + h3. Refactoring Now that we have posts and comments working, take a look at the @@ -1435,12 +1434,12 @@ following into it: <erb> <p> - <b>Commenter:</b> + <strong>Commenter:</strong> <%= comment.commenter %> </p> <p> - <b>Comment:</b> + <strong>Comment:</strong> <%= comment.body %> </p> </erb> @@ -1449,21 +1448,14 @@ Then you can change +app/views/posts/show.html.erb+ to look like the following: <erb> -<p id="notice"><%= notice %></p> - -<p> - <b>Name:</b> - <%= @post.name %> -</p> - <p> - <b>Title:</b> + <strong>Title:</strong> <%= @post.title %> </p> <p> - <b>Content:</b> - <%= @post.content %> + <strong>Text:</strong> + <%= @post.texthttp://beginningruby.org/ %> </p> <h2>Comments</h2> @@ -1471,23 +1463,21 @@ following: <h2>Add a comment:</h2> <%= form_for([@post, @post.comments.build]) do |f| %> - <div class="field"> + <p> <%= f.label :commenter %><br /> <%= f.text_field :commenter %> - </div> - <div class="field"> + </p> + <p> <%= f.label :body %><br /> <%= f.text_area :body %> - </div> - <div class="actions"> + </p> + <p> <%= f.submit %> - </div> + </p> <% end %> -<br /> - <%= link_to 'Edit Post', edit_post_path(@post) %> | -<%= link_to 'Back to Posts', posts_path %> | +<%= link_to 'Back to Posts', posts_path %> </erb> This will now render the partial in +app/views/comments/_comment.html.erb+ once @@ -1503,50 +1493,38 @@ create a file +app/views/comments/_form.html.erb+ containing: <erb> <%= form_for([@post, @post.comments.build]) do |f| %> - <div class="field"> + <p> <%= f.label :commenter %><br /> <%= f.text_field :commenter %> - </div> - <div class="field"> + </p> + <p> <%= f.label :body %><br /> <%= f.text_area :body %> - </div> - <div class="actions"> + </p> + <p> <%= f.submit %> - </div> + </p> <% end %> </erb> Then you make the +app/views/posts/show.html.erb+ look like the following: <erb> -<p id="notice"><%= notice %></p> - <p> - <b>Name:</b> - <%= @post.name %> -</p> - -<p> - <b>Title:</b> + <strong>Title:</strong> <%= @post.title %> </p> <p> - <b>Content:</b> - <%= @post.content %> + <strong>Text:</strong> + <%= @post.texthttp://beginningruby.org/ %> </p> -<h2>Comments</h2> -<%= render @post.comments %> - <h2>Add a comment:</h2> <%= render "comments/form" %> -<br /> - <%= link_to 'Edit Post', edit_post_path(@post) %> | -<%= link_to 'Back to Posts', posts_path %> | +<%= link_to 'Back to Posts', posts_path %> </erb> The second render just defines the partial template we want to render, @@ -1568,12 +1546,12 @@ So first, let's add the delete link in the <erb> <p> - <b>Commenter:</b> + <strong>Commenter:</strong> <%= comment.commenter %> </p> <p> - <b>Comment:</b> + <strong>Comment:</strong> <%= comment.body %> </p> @@ -1622,7 +1600,6 @@ model, +app/models/post.rb+, as follows: <ruby> class Post < ActiveRecord::Base - validates :name, :presence => true validates :title, :presence => true, :length => { :minimum => 5 } has_many :comments, :dependent => :destroy @@ -1651,11 +1628,8 @@ class PostsController < ApplicationController http_basic_authenticate_with :name => "dhh", :password => "secret", :except => [:index, :show] - # GET /posts - # GET /posts.json def index @posts = Post.all - respond_to do |format| # snipped for brevity </ruby> @@ -1677,214 +1651,6 @@ Authentication challenge !images/challenge.png(Basic HTTP Authentication Challenge)! -h3. Building a Multi-Model Form - -Another feature of your average blog is the ability to tag posts. To implement -this feature your application needs to interact with more than one model on a -single form. Rails offers support for nested forms. - -To demonstrate this, we will add support for giving each post multiple tags, -right in the form where you create the post. First, create a new model to hold -the tags: - -<shell> -$ rails generate model Tag name:string post:references -</shell> - -Again, run the migration to create the database table: - -<shell> -$ rake db:migrate -</shell> - -Next, edit the +post.rb+ file to create the other side of the association, and -to tell Rails (via the +accepts_nested_attributes_for+ macro) that you intend to -edit tags via posts: - -<ruby> -class Post < ActiveRecord::Base - validates :name, :presence => true - validates :title, :presence => true, - :length => { :minimum => 5 } - - has_many :comments, :dependent => :destroy - has_many :tags - attr_protected :tags - - accepts_nested_attributes_for :tags, :allow_destroy => :true, - :reject_if => proc { |attrs| attrs.all? { |k, v| v.blank? } } -end -</ruby> - -The +:allow_destroy+ option tells Rails to enable destroying tags through the -nested attributes (you'll handle that by displaying a "remove" checkbox on the -view that you'll build shortly). The +:reject_if+ option prevents saving new -tags that do not have any attributes filled in. - -We will modify +views/posts/_form.html.erb+ to render a partial to make a tag: - -<erb> -<% @post.tags.build %> -<%= form_for(@post) do |post_form| %> - <% if @post.errors.any? %> - <div id="errorExplanation"> - <h2><%= pluralize(@post.errors.count, "error") %> prohibited this post from being saved:</h2> - <ul> - <% @post.errors.full_messages.each do |msg| %> - <li><%= msg %></li> - <% end %> - </ul> - </div> - <% end %> - - <div class="field"> - <%= post_form.label :name %><br /> - <%= post_form.text_field :name %> - </div> - <div class="field"> - <%= post_form.label :title %><br /> - <%= post_form.text_field :title %> - </div> - <div class="field"> - <%= post_form.label :content %><br /> - <%= post_form.text_area :content %> - </div> - <h2>Tags</h2> - <%= render :partial => 'tags/form', - :locals => {:form => post_form} %> - <div class="actions"> - <%= post_form.submit %> - </div> -<% end %> -</erb> - -Note that we have changed the +f+ in +form_for(@post) do |f|+ to +post_form+ to -make it easier to understand what is going on. - -This example shows another option of the render helper, being able to pass in -local variables, in this case, we want the local variable +form+ in the partial -to refer to the +post_form+ object. - -We also add a <tt>@post.tags.build</tt> at the top of this form. This is to make -sure there is a new tag ready to have its name filled in by the user. If you do -not build the new tag, then the form will not appear as there is no new Tag -object ready to create. - -Now create the folder <tt>app/views/tags</tt> and make a file in there called -<tt>_form.html.erb</tt> which contains the form for the tag: - -<erb> -<%= form.fields_for :tags do |tag_form| %> - <div class="field"> - <%= tag_form.label :name, 'Tag:' %> - <%= tag_form.text_field :name %> - </div> - <% unless tag_form.object.nil? || tag_form.object.new_record? %> - <div class="field"> - <%= tag_form.label :_destroy, 'Remove:' %> - <%= tag_form.check_box :_destroy %> - </div> - <% end %> -<% end %> -</erb> - -Finally, we will edit the <tt>app/views/posts/show.html.erb</tt> template to -show our tags. - -<erb> -<p id="notice"><%= notice %></p> - -<p> - <b>Name:</b> - <%= @post.name %> -</p> - -<p> - <b>Title:</b> - <%= @post.title %> -</p> - -<p> - <b>Content:</b> - <%= @post.content %> -</p> - -<p> - <b>Tags:</b> - <%= @post.tags.map { |t| t.name }.join(", ") %> -</p> - -<h2>Comments</h2> -<%= render @post.comments %> - -<h2>Add a comment:</h2> -<%= render "comments/form" %> - - -<%= link_to 'Edit Post', edit_post_path(@post) %> | -<%= link_to 'Back to Posts', posts_path %> | -</erb> - -With these changes in place, you'll find that you can edit a post and its tags -directly on the same view. - -However, that method call <tt>@post.tags.map { |t| t.name }.join(", ")</tt> is -awkward, we could handle this by making a helper method. - -h3. View Helpers - -View Helpers live in <tt>app/helpers</tt> and provide small snippets of reusable -code for views. In our case, we want a method that strings a bunch of objects -together using their name attribute and joining them with a comma. As this is -for the Post show template, we put it in the PostsHelper. - -Open up <tt>app/helpers/posts_helper.rb</tt> and add the following: - -<erb> -module PostsHelper - def join_tags(post) - post.tags.map { |t| t.name }.join(", ") - end -end -</erb> - -Now you can edit the view in <tt>app/views/posts/show.html.erb</tt> to look like -this: - -<erb> -<p id="notice"><%= notice %></p> - -<p> - <b>Name:</b> - <%= @post.name %> -</p> - -<p> - <b>Title:</b> - <%= @post.title %> -</p> - -<p> - <b>Content:</b> - <%= @post.content %> -</p> - -<p> - <b>Tags:</b> - <%= join_tags(@post) %> -</p> - -<h2>Comments</h2> -<%= render @post.comments %> - -<h2>Add a comment:</h2> -<%= render "comments/form" %> - - -<%= link_to 'Edit Post', edit_post_path(@post) %> | -<%= link_to 'Back to Posts', posts_path %> | -</erb> - h3. What's Next? Now that you've seen your first Rails application, you should feel free to |