提交 a719843d 编写于 作者: V Vijay Dev

Merge branch 'master' of github.com:lifo/docrails

...@@ -72,8 +72,8 @@ module Redirection ...@@ -72,8 +72,8 @@ module Redirection
# "http://#{request.host_with_port}/#{path}" # "http://#{request.host_with_port}/#{path}"
# } # }
# #
# Note that the `do end` syntax for the redirect block wouldn't work, as Ruby would pass # Note that the +do end+ syntax for the redirect block wouldn't work, as Ruby would pass
# the block to `match` instead of `redirect`. Use `{ ... }` instead. # the block to +match+ instead of +redirect+. Use <tt>{ ... }</tt> instead.
# #
# The options version of redirect allows you to supply only the parts of the url which need # The options version of redirect allows you to supply only the parts of the url which need
# to change, it also supports interpolation of the path similar to the first example. # to change, it also supports interpolation of the path similar to the first example.
......
...@@ -442,7 +442,7 @@ def image_alt(src) ...@@ -442,7 +442,7 @@ def image_alt(src)
# <video><source src="/videos/trailer.ogg" /><source src="/videos/trailer.flv" /></video> # <video><source src="/videos/trailer.ogg" /><source src="/videos/trailer.flv" /></video>
# video_tag(["trailer.ogg", "trailer.flv"]) # => # video_tag(["trailer.ogg", "trailer.flv"]) # =>
# <video><source src="/videos/trailer.ogg" /><source src="/videos/trailer.flv" /></video> # <video><source src="/videos/trailer.ogg" /><source src="/videos/trailer.flv" /></video>
# video_tag(["trailer.ogg", "trailer.flv"] :size => "160x120") # => # video_tag(["trailer.ogg", "trailer.flv"], :size => "160x120") # =>
# <video height="120" width="160"><source src="/videos/trailer.ogg" /><source src="/videos/trailer.flv" /></video> # <video height="120" width="160"><source src="/videos/trailer.ogg" /><source src="/videos/trailer.flv" /></video>
def video_tag(*sources) def video_tag(*sources)
multiple_sources_tag('video', sources) do |options| multiple_sources_tag('video', sources) do |options|
......
...@@ -184,7 +184,7 @@ def convert_to_model(object) ...@@ -184,7 +184,7 @@ def convert_to_model(object)
# First name: <%= f.text_field :first_name %> # First name: <%= f.text_field :first_name %>
# Last name : <%= f.text_field :last_name %> # Last name : <%= f.text_field :last_name %>
# Biography : <%= text_area :person, :biography %> # Biography : <%= text_area :person, :biography %>
# Admin? : <%= check_box_tag "person[admin]", @person.company.admin? %> # Admin? : <%= check_box_tag "person[admin]", "1", @person.company.admin? %>
# <%= f.submit %> # <%= f.submit %>
# <% end %> # <% end %>
# #
......
...@@ -214,6 +214,7 @@ def observed_class ...@@ -214,6 +214,7 @@ def observed_class
end end
# Start observing the declared classes and their subclasses. # Start observing the declared classes and their subclasses.
# Called automatically by the instance method.
def initialize def initialize
observed_classes.each { |klass| add_observer!(klass) } observed_classes.each { |klass| add_observer!(klass) }
end end
...@@ -242,6 +243,7 @@ def add_observer!(klass) #:nodoc: ...@@ -242,6 +243,7 @@ def add_observer!(klass) #:nodoc:
klass.add_observer(self) klass.add_observer(self)
end end
# Returns true if notifications are disabled for this object.
def disabled_for?(object) def disabled_for?(object)
klass = object.class klass = object.class
return false unless klass.respond_to?(:observers) return false unless klass.respond_to?(:observers)
......
source 'https://rubygems.org' source 'https://rubygems.org'
gem 'rails', '3.2.0' gem 'rails', '3.2.3'
# Bundle edge Rails instead: # Bundle edge Rails instead:
# gem 'rails', :git => 'git://github.com/rails/rails.git' # gem 'rails', :git => 'git://github.com/rails/rails.git'
...@@ -15,7 +15,7 @@ group :assets do ...@@ -15,7 +15,7 @@ group :assets do
gem 'coffee-rails', '~> 3.2.1' gem 'coffee-rails', '~> 3.2.1'
# See https://github.com/sstephenson/execjs#readme for more supported runtimes # See https://github.com/sstephenson/execjs#readme for more supported runtimes
# gem 'therubyracer' # gem 'therubyracer', :platform => :ruby
gem 'uglifier', '>= 1.0.3' gem 'uglifier', '>= 1.0.3'
end end
...@@ -28,7 +28,7 @@ gem 'jquery-rails' ...@@ -28,7 +28,7 @@ gem 'jquery-rails'
# To use Jbuilder templates for JSON # To use Jbuilder templates for JSON
# gem 'jbuilder' # gem 'jbuilder'
# Use unicorn as the web server # Use unicorn as the app server
# gem 'unicorn' # gem 'unicorn'
# Deploy with Capistrano # Deploy with Capistrano
......
# Place all the behaviors and hooks related to the matching controller here.
# All this logic will automatically be available in application.js.
# You can use CoffeeScript in this file: http://jashkenas.github.com/coffee-script/
# Place all the behaviors and hooks related to the matching controller here.
# All this logic will automatically be available in application.js.
# You can use CoffeeScript in this file: http://jashkenas.github.com/coffee-script/
# Place all the behaviors and hooks related to the matching controller here.
# All this logic will automatically be available in application.js.
# You can use CoffeeScript in this file: http://jashkenas.github.com/coffee-script/
// Place all the styles related to the Comments controller here.
// They will automatically be included in application.css.
// You can use Sass (SCSS) here: http://sass-lang.com/
// Place all the styles related to the home controller here.
// They will automatically be included in application.css.
// You can use Sass (SCSS) here: http://sass-lang.com/
// Place all the styles related to the Posts controller here.
// They will automatically be included in application.css.
// You can use Sass (SCSS) here: http://sass-lang.com/
body {
background-color: #fff;
color: #333;
font-family: verdana, arial, helvetica, sans-serif;
font-size: 13px;
line-height: 18px; }
p, ol, ul, td {
font-family: verdana, arial, helvetica, sans-serif;
font-size: 13px;
line-height: 18px; }
pre {
background-color: #eee;
padding: 10px;
font-size: 11px; }
a {
color: #000;
&:visited {
color: #666; }
&:hover {
color: #fff;
background-color: #000; } }
div {
&.field, &.actions {
margin-bottom: 10px; } }
#notice {
color: green; }
.field_with_errors {
padding: 2px;
background-color: red;
display: table; }
#error_explanation {
width: 450px;
border: 2px solid red;
padding: 7px;
padding-bottom: 0;
margin-bottom: 20px;
background-color: #f0f0f0;
h2 {
text-align: left;
font-weight: bold;
padding: 5px 5px 5px 15px;
font-size: 12px;
margin: -7px;
margin-bottom: 0px;
background-color: #c00;
color: #fff; }
ul li {
font-size: 12px;
list-style: square; } }
class HomeController < ApplicationController class WelcomeController < ApplicationController
def index def index
end end
......
class PostsController < ApplicationController class PostsController < ApplicationController
http_basic_authenticate_with :name => "dhh", :password => "secret", :except => :index
# GET /posts
# GET /posts.json
def index def index
@posts = Post.all @posts = Post.all
respond_to do |format|
format.html # index.html.erb
format.json { render json: @posts }
end
end end
# GET /posts/1
# GET /posts/1.json
def show def show
@post = Post.find(params[:id]) @post = Post.find(params[:id])
respond_to do |format|
format.html # show.html.erb
format.json { render json: @post }
end
end end
# GET /posts/new
# GET /posts/new.json
def new def new
@post = Post.new @post = Post.new
respond_to do |format|
format.html # new.html.erb
format.json { render json: @post }
end
end
# GET /posts/1/edit
def edit
@post = Post.find(params[:id])
end end
# POST /posts
# POST /posts.json
def create def create
@post = Post.new(params[:post]) @post = Post.new(params[:post])
respond_to do |format| if @post.save
if @post.save redirect_to :action => :show, :id => @post.id
format.html { redirect_to @post, notice: 'Post was successfully created.' } else
format.json { render json: @post, status: :created, location: @post } render 'new'
else
format.html { render action: "new" }
format.json { render json: @post.errors, status: :unprocessable_entity }
end
end
end
# PUT /posts/1
# PUT /posts/1.json
def update
@post = Post.find(params[:id])
respond_to do |format|
if @post.update_attributes(params[:post])
format.html { redirect_to @post, notice: 'Post was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: "edit" }
format.json { render json: @post.errors, status: :unprocessable_entity }
end
end
end
# DELETE /posts/1
# DELETE /posts/1.json
def destroy
@post = Post.find(params[:id])
@post.destroy
respond_to do |format|
format.html { redirect_to posts_url }
format.json { head :no_content }
end end
end end
end end
module PostsHelper module PostsHelper
def join_tags(post)
post.tags.map { |t| t.name }.join(", ")
end
end end
class Post < ActiveRecord::Base class Post < ActiveRecord::Base
validates :name, :presence => true
validates :title, :presence => true, validates :title, :presence => true,
:length => { :minimum => 5 } :length => { :minimum => 5 }
has_many :comments, :dependent => :destroy has_many :comments, :dependent => :destroy
has_many :tags
accepts_nested_attributes_for :tags, :allow_destroy => :true,
:reject_if => proc { |attrs| attrs.all? { |k, v| v.blank? } }
end end
class Tag < ActiveRecord::Base
belongs_to :post
end
<% @post.tags.build %> <%= form_for :post, :url => { :action => :create } do |f| %>
<%= form_for(@post) do |post_form| %>
<% if @post.errors.any? %> <% if @post.errors.any? %>
<div id="errorExplanation"> <div id="errorExplanation">
<h2><%= pluralize(@post.errors.count, "error") %> prohibited this post from being saved:</h2> <h2><%= pluralize(@post.errors.count, "error") %> prohibited this post from being saved:</h2>
<ul> <ul>
<% @post.errors.full_messages.each do |msg| %> <% @post.errors.full_messages.each do |msg| %>
<li><%= msg %></li> <li><%= msg %></li>
<% end %> <% end %>
</ul> </ul>
</div> </div>
<% end %> <% end %>
<p>
<div class="field"> <%= f.label :title %><br>
<%= post_form.label :name %><br /> <%= f.text_field :title %>
<%= post_form.text_field :name %> </p>
</div>
<div class="field"> <p>
<%= post_form.label :title %><br /> <%= f.label :text %><br>
<%= post_form.text_field :title %> <%= f.text_area :text %>
</div> </p>
<div class="field">
<%= post_form.label :content %><br /> <p>
<%= post_form.text_area :content %> <%= f.submit %>
</div> </p>
<h2>Tags</h2>
<%= render :partial => 'tags/form',
:locals => {:form => post_form} %>
<div class="actions">
<%= post_form.submit %>
</div>
<% end %> <% end %>
<h1>Listing posts</h1> <h1>Listing posts</h1>
<%= link_to 'New post', :action => :new %>
<table> <table>
<tr> <tr>
<th>Name</th>
<th>Title</th> <th>Title</th>
<th>Content</th> <th>Text</th>
<th></th>
<th></th>
<th></th> <th></th>
</tr> </tr>
<% @posts.each do |post| %> <% @posts.each do |post| %>
<tr> <tr>
<td><%= post.name %></td>
<td><%= post.title %></td> <td><%= post.title %></td>
<td><%= post.content %></td> <td><%= post.text %></td>
<td><%= link_to 'Show', post %></td> <td><%= link_to 'Show', :action => :show, :id => post.id %>
<td><%= link_to 'Edit', edit_post_path(post) %></td>
<td><%= link_to 'Destroy', post, confirm: 'Are you sure?', method: :delete %></td>
</tr> </tr>
<% end %> <% end %>
</table> </table>
<br />
<%= link_to 'New Post', new_post_path %>
...@@ -2,4 +2,4 @@ ...@@ -2,4 +2,4 @@
<%= render 'form' %> <%= render 'form' %>
<%= link_to 'Back', posts_path %> <%= link_to 'Back', :action => :index %>
<p class="notice"><%= notice %></p>
<p> <p>
<b>Name:</b> <strong>Title:</strong>
<%= @post.name %>
</p>
<p>
<b>Title:</b>
<%= @post.title %> <%= @post.title %>
</p> </p>
<p>
<b>Content:</b>
<%= @post.content %>
</p>
<p> <p>
<b>Tags:</b> <strong>Text:</strong>
<%= join_tags(@post) %> <%= @post.text %>
</p> </p>
<h2>Comments</h2> <%= link_to 'Back', :action => :index %>
<%= 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 %> |
<%= 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 %>
<h1>Hello, Rails!</h1> <h1>Hello, Rails!</h1>
<%= link_to "My Blog", posts_path %> <%= link_to "My Blog", :controller => "posts" %>
Blog::Application.routes.draw do Blog::Application.routes.draw do
resources :posts do # resources :posts do
resources :comments # resources :comments
end # end
get "home/index" get "posts" => "posts#index"
get "posts/new"
post "posts/create"
get "posts/:id" => "posts#show"
# The priority is based upon order of creation: # The priority is based upon order of creation:
# first created -> highest priority. # first created -> highest priority.
...@@ -54,8 +57,8 @@ ...@@ -54,8 +57,8 @@
# You can have the root of your site routed with "root" # You can have the root of your site routed with "root"
# just remember to delete public/index.html. # just remember to delete public/index.html.
root :to => "home#index" root :to => "welcome#index"
# See how all your routes lay out with "rake routes" # See how all your routes lay out with "rake routes"
# This is a legacy wild controller route that's not recommended for RESTful applications. # This is a legacy wild controller route that's not recommended for RESTful applications.
......
class CreateTags < ActiveRecord::Migration
def change
create_table :tags do |t|
t.string :name
t.references :post
t.timestamps
end
add_index :tags, :post_id
end
end
class CreatePosts < ActiveRecord::Migration class CreatePosts < ActiveRecord::Migration
def change def change
create_table :posts do |t| create_table :posts do |t|
t.string :name
t.string :title t.string :title
t.text :content t.text :text
t.timestamps t.timestamps
end end
......
...@@ -11,31 +11,30 @@ ...@@ -11,31 +11,30 @@
# #
# It's strongly recommended to check this file into your version control system. # It's strongly recommended to check this file into your version control system.
ActiveRecord::Schema.define(:version => 20110901013701) do ActiveRecord::Schema.define(:version => 20120420083127) do
create_table "comments", :force => true do |t| create_table "comments", :force => true do |t|
t.string "commenter" t.string "commenter"
t.text "body" t.text "body"
t.integer "post_id" t.integer "post_id"
t.datetime "created_at" t.datetime "created_at", :null => false
t.datetime "updated_at" t.datetime "updated_at", :null => false
end end
add_index "comments", ["post_id"], :name => "index_comments_on_post_id" add_index "comments", ["post_id"], :name => "index_comments_on_post_id"
create_table "posts", :force => true do |t| create_table "posts", :force => true do |t|
t.string "name"
t.string "title" t.string "title"
t.text "content" t.text "text"
t.datetime "created_at" t.datetime "created_at", :null => false
t.datetime "updated_at" t.datetime "updated_at", :null => false
end end
create_table "tags", :force => true do |t| create_table "tags", :force => true do |t|
t.string "name" t.string "name"
t.integer "post_id" t.integer "post_id"
t.datetime "created_at" t.datetime "created_at", :null => false
t.datetime "updated_at" t.datetime "updated_at", :null => false
end end
add_index "tags", ["post_id"], :name => "index_tags_on_post_id" add_index "tags", ["post_id"], :name => "index_tags_on_post_id"
......
# Read about fixtures at http://api.rubyonrails.org/classes/Fixtures.html # Read about fixtures at http://api.rubyonrails.org/classes/Fixtures.html
one: one:
name: MyString
title: MyString title: MyString
content: MyText text: MyText
two: two:
name: MyString
title: MyString title: MyString
content: MyText text: MyText
require 'test_helper' require 'test_helper'
class HomeControllerTest < ActionController::TestCase class WelcomeControllerTest < ActionController::TestCase
test "should get index" do test "should get index" do
get :index get :index
assert_response :success assert_response :success
......
...@@ -525,6 +525,13 @@ development: ...@@ -525,6 +525,13 @@ development:
password: password:
</yaml> </yaml>
If you use external connection pool manager, you can disable prepared statements in rails:
<yaml>
production:
adapter: postgresql
prepared_statements: false
</yaml>
h5. Configuring an SQLite3 Database for JRuby Platform h5. Configuring an SQLite3 Database for JRuby Platform
If you choose to use SQLite3 and are using JRuby, your +config/database.yml+ will look a little different. Here's the development section: If you choose to use SQLite3 and are using JRuby, your +config/database.yml+ will look a little different. Here's the development section:
......
...@@ -89,7 +89,7 @@ form_tag(:controller => "people", :action => "search", :method => "get", :class ...@@ -89,7 +89,7 @@ form_tag(:controller => "people", :action => "search", :method => "get", :class
# => '<form accept-charset="UTF-8" action="/people/search?method=get&class=nifty_form" method="post">' # => '<form accept-charset="UTF-8" action="/people/search?method=get&class=nifty_form" method="post">'
</ruby> </ruby>
Here, +method+ and +class+ are appended to the query string of the generated URL because you even though you mean to write two hashes, you really only specified one. So you need to tell Ruby which is which by delimiting the first hash (or both) with curly brackets. This will generate the HTML you expect: Here, +method+ and +class+ are appended to the query string of the generated URL because even though you mean to write two hashes, you really only specified one. So you need to tell Ruby which is which by delimiting the first hash (or both) with curly brackets. This will generate the HTML you expect:
<ruby> <ruby>
form_tag({:controller => "people", :action => "search"}, :method => "get", :class => "nifty_form") form_tag({:controller => "people", :action => "search"}, :method => "get", :class => "nifty_form")
......
...@@ -10,7 +10,7 @@ you should be familiar with: ...@@ -10,7 +10,7 @@ you should be familiar with:
endprologue. endprologue.
WARNING. This Guide is based on Rails 3.1. Some of the code shown here will not WARNING. This Guide is based on Rails 3.2. Some of the code shown here will not
work in earlier versions of Rails. work in earlier versions of Rails.
WARNING: The Edge version of this guide is currently being re-worked. Please excuse us while we re-arrange the place. WARNING: The Edge version of this guide is currently being re-worked. Please excuse us while we re-arrange the place.
...@@ -27,8 +27,8 @@ prerequisites installed: ...@@ -27,8 +27,8 @@ prerequisites installed:
TIP: Note that Ruby 1.8.7 p248 and p249 have marshaling bugs that crash Rails TIP: Note that Ruby 1.8.7 p248 and p249 have marshaling bugs that crash Rails
3.0. Ruby Enterprise Edition have these fixed since release 1.8.7-2010.02 3.0. Ruby Enterprise Edition have these fixed since release 1.8.7-2010.02
though. On the 1.9 front, Ruby 1.9.1 is not usable because it outright segfaults though. On the 1.9 front, Ruby 1.9.1 is not usable because it outright segfaults
on Rails 3.0, so if you want to use Rails 3 with 1.9.x jump on 1.9.2 for smooth on Rails 3.0, so if you want to use Rails 3 with 1.9.x jump on 1.9.2 or
sailing. 1.9.3 for smooth sailing.
* The "RubyGems":http://rubyforge.org/frs/?group_id=126 packaging system * The "RubyGems":http://rubyforge.org/frs/?group_id=126 packaging system
** If you want to learn more about RubyGems, please read the "RubyGems User Guide":http://docs.rubygems.org/read/book/1 ** If you want to learn more about RubyGems, please read the "RubyGems User Guide":http://docs.rubygems.org/read/book/1
...@@ -73,7 +73,8 @@ h3. Creating a New Rails Project ...@@ -73,7 +73,8 @@ h3. Creating a New Rails Project
The best way to use this guide is to follow each step as it happens, no code or The best way to use this guide is to follow each step as it happens, no code or
step needed to make this example application has been left out, so you can step needed to make this example application has been left out, so you can
literally follow along step by step. You can get the complete code "here":https://github.com/lifo/docrails/tree/master/guides/code/getting_started. literally follow along step by step. You can get the complete code
"here":https://github.com/lifo/docrails/tree/master/guides/code/getting_started.
By following along with this guide, you'll create a Rails project called <tt>blog</tt>, a By following along with this guide, you'll create a Rails project called <tt>blog</tt>, a
(very) simple weblog. Before you can start building the application, you need to (very) simple weblog. Before you can start building the application, you need to
...@@ -97,7 +98,7 @@ To verify that you have everything installed correctly, you should be able to ru ...@@ -97,7 +98,7 @@ To verify that you have everything installed correctly, you should be able to ru
$ rails --version $ rails --version
</shell> </shell>
If it says something like "Rails 3.2.2" you are ready to continue. If it says something like "Rails 3.2.3" you are ready to continue.
h4. Creating the Blog Application h4. Creating the Blog Application
...@@ -111,7 +112,7 @@ $ rails new blog ...@@ -111,7 +112,7 @@ $ rails new blog
This will create a Rails application called Blog in a directory called blog. This will create a Rails application called Blog in a directory called blog.
TIP: You can see all of the switches that the Rails application builder accepts by running <tt>rails new -h</tt>. TIP: You can see all of the command line options that the Rails application builder accepts by running <tt>rails new -h</tt>.
After you create the blog application, switch to its folder to continue work directly in that application: After you create the blog application, switch to its folder to continue work directly in that application:
...@@ -225,7 +226,6 @@ h4. Laying down the ground work ...@@ -225,7 +226,6 @@ h4. Laying down the ground work
The first thing that you are going to need to create a new post within the application is a place to do that. A great place for that would be at +/posts/new+. If you attempt to navigate to that now -- by visiting "http://localhost:3000/posts/new":http://localhost:3000/posts/new -- Rails will give you a routing error: The first thing that you are going to need to create a new post within the application is a place to do that. A great place for that would be at +/posts/new+. If you attempt to navigate to that now -- by visiting "http://localhost:3000/posts/new":http://localhost:3000/posts/new -- Rails will give you a routing error:
!images/getting_started/routing_error_no_route_matches.png(A routing error, no route matches /posts/new)! !images/getting_started/routing_error_no_route_matches.png(A routing error, no route matches /posts/new)!
This is because there is nowhere inside the routes for the application -- defined inside +config/routes.rb+ -- that defines this route. By default, Rails has no routes configured at all, and so you must define your routes as you need them. This is because there is nowhere inside the routes for the application -- defined inside +config/routes.rb+ -- that defines this route. By default, Rails has no routes configured at all, and so you must define your routes as you need them.
...@@ -240,7 +240,7 @@ This route is a super-simple route: it defines a new route that only responds to ...@@ -240,7 +240,7 @@ This route is a super-simple route: it defines a new route that only responds to
With the route defined, requests can now be made to +/posts/new+ in the application. Navigate to "http://localhost:3000/posts/new":http://localhost:3000/posts/new and you'll see another routing error: With the route defined, requests can now be made to +/posts/new+ in the application. Navigate to "http://localhost:3000/posts/new":http://localhost:3000/posts/new and you'll see another routing error:
!images/getting_started/routing_error_no_controller.png(Another routing error, uninitialized constant PostsController) !images/getting_started/routing_error_no_controller.png(Another routing error, uninitialized constant PostsController)!
This error is happening because this route need a controller to be defined. The route is attempting to find that controller so it can serve the request, but with the controller undefined, it just can't do that. The solution to this particular problem is simple: you need to create a controller called +PostsController+. You can do this by running this command: This error is happening because this route need a controller to be defined. The route is attempting to find that controller so it can serve the request, but with the controller undefined, it just can't do that. The solution to this particular problem is simple: you need to create a controller called +PostsController+. You can do this by running this command:
...@@ -259,7 +259,7 @@ A controller is simply a class that is defined to inherit from +ApplicationContr ...@@ -259,7 +259,7 @@ A controller is simply a class that is defined to inherit from +ApplicationContr
If you refresh "http://localhost:3000/posts/new":http://localhost:3000/posts/new now, you'll get a new error: If you refresh "http://localhost:3000/posts/new":http://localhost:3000/posts/new now, you'll get a new error:
!images/getting_started/unknown_action_new_for_posts.png(Unknown action new for PostsController!) !images/getting_started/unknown_action_new_for_posts.png(Unknown action new for PostsController!)!
This error indicates that Rails cannot find the +new+ action inside the +PostsController+ that you just generated. This is because when controllers are generated in Rails they are empty by default, unless you tell it you wanted actions during the generation process. This error indicates that Rails cannot find the +new+ action inside the +PostsController+ that you just generated. This is because when controllers are generated in Rails they are empty by default, unless you tell it you wanted actions during the generation process.
...@@ -272,7 +272,7 @@ end ...@@ -272,7 +272,7 @@ end
With the +new+ method defined in +PostsController+, if you refresh "http://localhost:3000/posts/new":http://localhost:3000/posts/new you'll see another error: With the +new+ method defined in +PostsController+, if you refresh "http://localhost:3000/posts/new":http://localhost:3000/posts/new you'll see another error:
!images/getting_started/template_is_missing_posts_new.png(Template is missing for posts/new) !images/getting_started/template_is_missing_posts_new.png(Template is missing for posts/new)!
You're getting this error now because Rails expects plain actions like this one to have views associated with them to display their information. With no view available, Rails errors out. You're getting this error now because Rails expects plain actions like this one to have views associated with them to display their information. With no view available, Rails errors out.
...@@ -302,7 +302,9 @@ When you refresh "http://localhost:3000/posts/new":http://localhost:3000/posts/n ...@@ -302,7 +302,9 @@ When you refresh "http://localhost:3000/posts/new":http://localhost:3000/posts/n
h4. The first form h4. The first form
To create a form within this template, you will use a _form builder_. The primary form builder for Rails is provided by a helper method called +form_for+. To use this method, write this code into +app/views/posts/new.html.erb+: To create a form within this template, you will use a <em>form
builder</em>. The primary form builder for Rails is provided by a helper
method called +form_for+. To use this method, add this code into +app/views/posts/new.html.erb+:
<erb> <erb>
<%= form_for :post do |f| %> <%= form_for :post do |f| %>
...@@ -346,7 +348,7 @@ By using the +post+ method rather than the +get+ method, Rails will define a rou ...@@ -346,7 +348,7 @@ By using the +post+ method rather than the +get+ method, Rails will define a rou
With the form and the route for it defined now, you will be able to fill in the form and then click the submit button to begin the process of creating a new post, so go ahead and do that. When you submit the form, you should see a familiar error: With the form and the route for it defined now, you will be able to fill in the form and then click the submit button to begin the process of creating a new post, so go ahead and do that. When you submit the form, you should see a familiar error:
!images/getting_started/unknown_action_create_for_posts(Unknown action create for PostsController)! !images/getting_started/unknown_action_create_for_posts.png(Unknown action create for PostsController)!
You will now need to create the +create+ action within the +PostsController+ for this to work. You will now need to create the +create+ action within the +PostsController+ for this to work.
...@@ -385,10 +387,30 @@ If you re-submit the form one more time you'll now no longer get the missing tem ...@@ -385,10 +387,30 @@ If you re-submit the form one more time you'll now no longer get the missing tem
This action is now displaying the parameters for the post that are coming in from the form. However, this isn't really all that helpful. Yes, you can see the parameters but nothing in particular is being done with them. This action is now displaying the parameters for the post that are coming in from the form. However, this isn't really all that helpful. Yes, you can see the parameters but nothing in particular is being done with them.
h4. Creating the Post model
Rails uses models to manage database objects, so if you want to save
data to the database you'll have to create a model. In our blog
application you want to save posts, so you'll create a +Post+ model.
You can create a model with the following command:
<shell>
$ rails generate model Post title:string text:text
</shell>
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
now, we're only interested in +app/models/post.rb+ and
+db/migrate/20120419084633_create_posts.rb+. The latter is responsible
for creating the dabase structure, which is what we'll look at next.
h4. Running a Migration h4. Running a Migration
One of the products of the +rails generate scaffold+ command is a _database As we've just seen, +rails generate model+ created a _database
migration_. Migrations are Ruby classes that are designed to make it simple to migration_ file inside the +db/migrate+ directory.
Migrations are Ruby classes that are designed to make it simple to
create and modify database tables. Rails uses rake commands to run migrations, create and modify database tables. Rails uses rake commands to run migrations,
and it's possible to undo a migration after it's been applied to your database. and it's possible to undo a migration after it's been applied to your database.
Migration filenames include a timestamp to ensure that they're processed in the Migration filenames include a timestamp to ensure that they're processed in the
...@@ -401,9 +423,8 @@ yours will have a slightly different name), here's what you'll find: ...@@ -401,9 +423,8 @@ yours will have a slightly different name), here's what you'll find:
class CreatePosts < ActiveRecord::Migration class CreatePosts < ActiveRecord::Migration
def change def change
create_table :posts do |t| create_table :posts do |t|
t.string :name
t.string :title t.string :title
t.text :content t.text :text
t.timestamps t.timestamps
end end
...@@ -415,7 +436,7 @@ The above migration creates a method named +change+ which will be called when yo ...@@ -415,7 +436,7 @@ The above migration creates a method named +change+ which will be called when yo
run this migration. The action defined in this method is also reversible, which run this migration. The action defined in this method is also reversible, which
means Rails knows how to reverse the change made by this migration, in case you means Rails knows how to reverse the change made by this migration, in case you
want to reverse it later. When you run this migration it will create a want to reverse it later. When you run this migration it will create a
+posts+ table with two string columns and a text column. It also creates two +posts+ table with one string column and a text column. It also creates two
timestamp fields to allow Rails to track post creation and update times. More timestamp fields to allow Rails to track post creation and update times. More
information about Rails migrations can be found in the "Rails Database information about Rails migrations can be found in the "Rails Database
Migrations":migrations.html guide. Migrations":migrations.html guide.
...@@ -442,39 +463,203 @@ command will apply to the database defined in the +development+ section of your ...@@ -442,39 +463,203 @@ command will apply to the database defined in the +development+ section of your
environment, for instance in production, you must explicitly pass it when environment, for instance in production, you must explicitly pass it when
invoking the command: <tt>rake db:migrate RAILS_ENV=production</tt>. invoking the command: <tt>rake db:migrate RAILS_ENV=production</tt>.
h4. Adding a Link h4. Saving data in the controller
Back into +posts_controller+, we need to change the +create+ action
to use the new +Post+ model to save data in the database. Open that file
and change the +create+ action to look like the following:
<ruby>
def create
@post = Post.new(params[:post])
@post.save
redirect_to :action => :show, :id => @post.id
end
</ruby>
Here's what's going on: every Rails model can be initialized with its
respective attributes, which are automatically mapped to its
database columns. In the first line we do just that (remember that
+params[:post]+ contains the attributes we're interested in). Then,
+@post.save+ is responsible for saving the model in the database.
Finally, on the last line we redirect the user to the +show+ action,
wich we have not defined yet.
To hook the posts up to the home page you've already created, you can add a link TIP: As we'll see later, +@post.save+ returns a boolean indicating
to the home page. Open +app/views/welcome/index.html.erb+ and modify it as follows: wherever the model was saved or not, and you can (and usually do) take
different actions depending on the result of calling +@post.save+.
h4. Showing posts
Before trying to create a new post, let's add the +show+ action, which
will be responsible for showing our posts. Open +config/routes.rb+
and add the following route:
<ruby>
get "posts/:id" => "posts#show"
</ruby>
The special syntax +:id+ tells rails that this route expects an +:id+
parameter, which in our case will be the id of the post. Note that this
time we had to specify the actual mapping, +posts#show+ because
otherwise Rails would not know which action to render.
As we did before, we need to add the +show+ action in the
+posts_controller+ and its respective view.
<ruby>
def show
@post = Post.find(params[:id])
end
</ruby>
A couple of things to note. We use +Post.find+ to find the post we're
interested in. We also use an instance variable (prefixed by +@+) to
hold our reference to the post object. We do this because Rails will pass all instance
variables to the view.
Now, create a new file +app/view/posts/show.html.erb+ with the following
content:
<erb>
<p>
<strong>Title:</strong>
<%= @post.title %>
</p>
<p>
<strong>Text:</strong>
<%= @post.text %>
</p>
</erb>
Finally, if you now go to
"http://localhost:3000/posts/new":http://localhost:3000/posts/new you'll
be able to create a post. Try it!
!images/getting_started/show_action_for_posts.png(Show action for posts)!
h4. Listing all posts
We still need a way to list all our posts, so let's do that. As usual,
we'll need a route, a controller action, and a view:
<ruby>
# Add to config/routes.rb
get "posts" => "posts#index"
# Add to app/controllers/posts_controller.rb
def index
@posts = Post.all
end
</ruby>
+app/view/posts/index.html.erb+:
<erb>
<h1>Listing posts</h1>
<table>
<tr>
<th>Title</th>
<th>Text</th>
</tr>
<% @posts.each do |post| %>
<tr>
<td><%= post.title %></td>
<td><%= post.text %></td>
</tr>
<% end %>
</table>
</erb>
h4. Adding links
You can now create, show, and list posts. But it's difficult to navigate
through pages, so let's add some links.
Open +app/views/welcome/index.html.erb+ and modify it as follows:
<ruby> <ruby>
<h1>Hello, Rails!</h1> <h1>Hello, Rails!</h1>
<%= link_to "My Blog", posts_path %> <%= link_to "My Blog", :controller => "posts" %>
</ruby> </ruby>
The +link_to+ method is one of Rails' built-in view helpers. It creates a The +link_to+ method is one of Rails' built-in view helpers. It creates a
hyperlink based on text to display and where to go - in this case, to the path hyperlink based on text to display and where to go - in this case, to the path
for posts. for posts.
h4. Working with Posts in the Browser Let's add links to the other views as well.
Now you're ready to start working with posts. To do that, navigate to <erb>
"http://localhost:3000":http://localhost:3000/ and then click the "My Blog" # app/views/posts/index.html.erb
link:
!images/posts_index.png(Posts Index screenshot)! <h1>Listing posts</h1>
This is the result of Rails rendering the +index+ view of your posts. There <%= link_to 'New post', :action => :new %>
aren't currently any posts in the database, but if you click the +New Post+ link
you can create one. After that, you'll find that you can edit posts, look at <table>
their details, or destroy them. All of the logic and HTML to handle this was <tr>
built by the single +rails generate scaffold+ command. <th>Title</th>
<th>Text</th>
<th></th>
</tr>
<% @posts.each do |post| %>
<tr>
<td><%= post.title %></td>
<td><%= post.text %></td>
<td><%= link_to 'Show', :action => :show, :id => post.id %></td>
</tr>
<% end %>
</table>
# app/views/posts/new.html.erb
<%= form_for :post do |f| %>
<p>
<%= f.label :title %><br>
<%= f.text_field :title %>
</p>
<p>
<%= f.label :text %><br>
<%= f.text_area :text %>
</p>
<p>
<%= f.submit %>
</p>
<% end %>
<%= link_to 'Back', :action => :index %>
# app/views/posts/show.html.erb
<p>
<strong>Title:</strong>
<%= @post.title %>
</p>
<p>
<strong>Text:</strong>
<%= @post.text %>
</p>
<%= link_to 'Back', :action => :index %>
</erb>
TIP: If you want to link to an action in the same controller, you don't
need to specify the +:controller+ option, as Rails will use the current
controller by default.
TIP: In development mode (which is what you're working in by default), Rails TIP: In development mode (which is what you're working in by default), Rails
reloads your application with every browser request, so there's no need to stop reloads your application with every browser request, so there's no need to stop
and restart the web server. and restart the web server.
Congratulations, you're riding the rails! Now it's time to see how it all works. Congratulations, you're riding the rails! Now its time to see how it all works.
h4. The Model h4. The Model
...@@ -498,17 +683,102 @@ Open the +app/models/post.rb+ file and edit it: ...@@ -498,17 +683,102 @@ Open the +app/models/post.rb+ file and edit it:
<ruby> <ruby>
class Post < ActiveRecord::Base class Post < ActiveRecord::Base
validates :name, :presence => true
validates :title, :presence => true, validates :title, :presence => true,
:length => { :minimum => 5 } :length => { :minimum => 5 }
end end
</ruby> </ruby>
These changes will ensure that all posts have a name and a title, and that the These changes will ensure that all posts have a title that is at least five characters long.
title is at least five characters long. Rails can validate a variety of Rails can validate a variety of conditions in a model, including the presence or uniqueness of columns, their
conditions in a model, including the presence or uniqueness of columns, their
format, and the existence of associated objects. Validations are covered in detail format, and the existence of associated objects. Validations are covered in detail
in "Active Record Validations and Callbacks":active_record_validations_callbacks.html#validations-overview in "Active Record Validations and
Callbacks":active_record_validations_callbacks.html#validations-overview
If you open +posts_controller+ again, you'll notice that we don't check
the result of calling +@post.save+. We need to change its behavior to
show the form back to the user if any error occur:
<ruby>
def new
@post = Post.new
end
def create
@post = Post.new(params[:post])
if @post.save
redirect_to :action => :show, :id => @post.id
else
render 'new'
end
end
</ruby>
Notice that I've also added +@post = Post.new+ to the +new+ action. I'll
explain why I did that in the next section, for now add that to your
controller as well.
Also notice that we use +render+ instead of +redirect_to+ when +save+
returns false. We can use +render+ so that the +@post+ object is passed
back to the view.
If you reload
"http://localhost:3000/posts/new":http://localhost:3000/posts/new and
try to save a post without a title, Rails will send you back to the
form, but that's not very useful. You need to tell the user that
something went wrong. To do that, you'll modify
+app/views/posts/index.html.erb+ to check for error messages:
<erb>
<%= form_for :post do |f| %>
<% 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 %>
<p>
<%= f.label :title %><br>
<%= f.text_field :title %>
</p>
<p>
<%= f.label :text %><br>
<%= f.text_area :text %>
</p>
<p>
<%= f.submit %>
</p>
<% end %>
<%= link_to 'Back', :action => :index %>
</erb>
A few things are going on. We check if there are any errors with
+@post.errors.any?+, and in that case we show a list of all
errors with +@post.errors.full_messages+.
+pluralize+ is a rails helper
that takes a number and a string as its arguments. If the number is
greater than one, the string will be automatically pluralized.
The reason why we added +@post = Post.new+ in +posts_controller+ is that
otherwise +@post+ would be +nil+ in our view, and calling
+@post.errors.any?+ would throw an error.
TIP: Rails automatically wraps fields that contain an error with a div
with class +field_with_errors+. You can define a css rule to make them
standout.
Now you'll get a nice error message when saving a post without title:
!images/getting_started/form_with_errors.png(Form With Errors)!
h4. Using the Console h4. Using the Console
......
...@@ -82,6 +82,8 @@ it to default to +false+ for new users, but existing users are considered to ...@@ -82,6 +82,8 @@ it to default to +false+ for new users, but existing users are considered to
have already opted in, so we use the User model to set the flag to +true+ for have already opted in, so we use the User model to set the flag to +true+ for
existing users. existing users.
h4. Using the change method
Rails 3.1 makes migrations smarter by providing a new <tt>change</tt> method. Rails 3.1 makes migrations smarter by providing a new <tt>change</tt> method.
This method is preferred for writing constructive migrations (adding columns or This method is preferred for writing constructive migrations (adding columns or
tables). The migration knows how to migrate your database and reverse it when tables). The migration knows how to migrate your database and reverse it when
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册