aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--actionpack/lib/action_view/helpers/date_helper.rb3
-rw-r--r--actionpack/lib/action_view/helpers/form_helper.rb2
-rw-r--r--activemodel/README.rdoc5
-rw-r--r--activemodel/lib/active_model/secure_password.rb3
-rw-r--r--activemodel/lib/active_model/serialization.rb16
-rw-r--r--guides/assets/images/favicon.icobin0 -> 1150 bytes
-rw-r--r--guides/assets/images/getting_started/index_action_with_edit_link.pngbin0 -> 15547 bytes
-rw-r--r--guides/code/getting_started/app/controllers/posts_controller.rb14
-rw-r--r--guides/code/getting_started/app/helpers/welcome_helper.rb (renamed from guides/code/getting_started/app/helpers/home_helper.rb)0
-rw-r--r--guides/code/getting_started/app/views/posts/_form.html.erb2
-rw-r--r--guides/code/getting_started/app/views/posts/edit.html.erb3
-rw-r--r--guides/code/getting_started/app/views/posts/index.html.erb2
-rw-r--r--guides/code/getting_started/app/views/posts/show.html.erb1
-rw-r--r--guides/code/getting_started/config/routes.rb2
-rw-r--r--guides/source/active_record_querying.textile2
-rw-r--r--guides/source/generators.textile21
-rw-r--r--guides/source/getting_started.textile196
-rw-r--r--guides/source/layout.html.erb2
-rw-r--r--guides/source/plugins.textile10
-rw-r--r--railties/test/generators/namespaced_generators_test.rb2
20 files changed, 242 insertions, 44 deletions
diff --git a/actionpack/lib/action_view/helpers/date_helper.rb b/actionpack/lib/action_view/helpers/date_helper.rb
index ffb1afa089..81f856feda 100644
--- a/actionpack/lib/action_view/helpers/date_helper.rb
+++ b/actionpack/lib/action_view/helpers/date_helper.rb
@@ -64,6 +64,9 @@ module ActionView
# distance_of_time_in_words(to_time, from_time, true) # => about 6 years
# distance_of_time_in_words(Time.now, Time.now) # => less than a minute
#
+ # distance_of_time_in_words(70) # => 1 minute
+ # distance_of_time_in_words(60*60) # => about 1 hour
+ #
def distance_of_time_in_words(from_time, to_time = 0, include_seconds = false, options = {})
from_time = from_time.to_time if from_time.respond_to?(:to_time)
to_time = to_time.to_time if to_time.respond_to?(:to_time)
diff --git a/actionpack/lib/action_view/helpers/form_helper.rb b/actionpack/lib/action_view/helpers/form_helper.rb
index ad097f2eb7..8e7224937d 100644
--- a/actionpack/lib/action_view/helpers/form_helper.rb
+++ b/actionpack/lib/action_view/helpers/form_helper.rb
@@ -902,7 +902,7 @@ module ActionView
# # Let's say that @post.validated? is 1:
# check_box("post", "validated")
# # => <input name="post[validated]" type="hidden" value="0" />
- # # <input type="checkbox" id="post_validated" name="post[validated]" value="1" />
+ # # <input checked="checked" type="checkbox" id="post_validated" name="post[validated]" value="1" />
#
# # Let's say that @puppy.gooddog is "no":
# check_box("puppy", "gooddog", {}, "yes", "no")
diff --git a/activemodel/README.rdoc b/activemodel/README.rdoc
index 7d13a0123b..9b05384792 100644
--- a/activemodel/README.rdoc
+++ b/activemodel/README.rdoc
@@ -26,7 +26,7 @@ to integrate with Action Pack out of the box: <tt>ActiveModel::Model</tt>.
person = Person.new(:name => 'bob', :age => '18')
person.name # => 'bob'
person.age # => 18
- person.valid? # => false
+ person.valid? # => true
It includes model name introspections, conversions, translations and
validations, resulting in a class suitable to be used with Action Pack.
@@ -116,9 +116,6 @@ behavior out of the box:
person.errors.full_messages
# => ["Name can not be nil"]
- person.errors.full_messages
- # => ["Name can not be nil"]
-
{Learn more}[link:classes/ActiveModel/Errors.html]
* Model name introspection
diff --git a/activemodel/lib/active_model/secure_password.rb b/activemodel/lib/active_model/secure_password.rb
index ff2213231f..8711b24124 100644
--- a/activemodel/lib/active_model/secure_password.rb
+++ b/activemodel/lib/active_model/secure_password.rb
@@ -58,7 +58,8 @@ module ActiveModel
BCrypt::Password.new(password_digest) == unencrypted_password && self
end
- # Encrypts the password into the password_digest attribute.
+ # Encrypts the password into the password_digest attribute, only if the
+ # new password is not blank.
def password=(unencrypted_password)
unless unencrypted_password.blank?
@password = unencrypted_password
diff --git a/activemodel/lib/active_model/serialization.rb b/activemodel/lib/active_model/serialization.rb
index 06bedf1c47..a5828476b1 100644
--- a/activemodel/lib/active_model/serialization.rb
+++ b/activemodel/lib/active_model/serialization.rb
@@ -26,17 +26,18 @@ module ActiveModel
# person.serializable_hash # => {"name"=>"Bob"}
#
# You need to declare an attributes hash which contains the attributes
- # you want to serialize. When called, serializable hash will use
+ # you want to serialize. Attributes must be strings, not symbols.
+ # When called, serializable hash will use
# instance methods that match the name of the attributes hash's keys.
# In order to override this behavior, take a look at the private
- # method read_attribute_for_serialization.
+ # method +read_attribute_for_serialization+.
#
# Most of the time though, you will want to include the JSON or XML
# serializations. Both of these modules automatically include the
- # ActiveModel::Serialization module, so there is no need to explicitly
+ # +ActiveModel::Serialization+ module, so there is no need to explicitly
# include it.
#
- # So a minimal implementation including XML and JSON would be:
+ # A minimal implementation including XML and JSON would be:
#
# class Person
# include ActiveModel::Serializers::JSON
@@ -63,7 +64,12 @@ module ActiveModel
# person.to_json # => "{\"name\":\"Bob\"}"
# person.to_xml # => "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<serial-person...
#
- # Valid options are <tt>:only</tt>, <tt>:except</tt> and <tt>:methods</tt> .
+ # Valid options are <tt>:only</tt>, <tt>:except</tt>, <tt>:methods</tt> and <tt>include</tt>.
+ # The following are all valid examples:
+ #
+ # person.serializable_hash(:only => 'name')
+ # person.serializable_hash(:include => :address)
+ # person.serializable_hash(:include => { :address => { :only => 'city' }})
module Serialization
def serializable_hash(options = nil)
options ||= {}
diff --git a/guides/assets/images/favicon.ico b/guides/assets/images/favicon.ico
new file mode 100644
index 0000000000..e0e80cf8f1
--- /dev/null
+++ b/guides/assets/images/favicon.ico
Binary files differ
diff --git a/guides/assets/images/getting_started/index_action_with_edit_link.png b/guides/assets/images/getting_started/index_action_with_edit_link.png
new file mode 100644
index 0000000000..6e58a13756
--- /dev/null
+++ b/guides/assets/images/getting_started/index_action_with_edit_link.png
Binary files differ
diff --git a/guides/code/getting_started/app/controllers/posts_controller.rb b/guides/code/getting_started/app/controllers/posts_controller.rb
index 947cd2a767..fc71e9b4e8 100644
--- a/guides/code/getting_started/app/controllers/posts_controller.rb
+++ b/guides/code/getting_started/app/controllers/posts_controller.rb
@@ -21,4 +21,18 @@ class PostsController < ApplicationController
render 'new'
end
end
+
+ def edit
+ @post = Post.find(params[:id])
+ end
+
+ def update
+ @post = Post.find(params[:id])
+
+ if @post.update_attributes(params[:post])
+ redirect_to :action => :show, :id => @post.id
+ else
+ render 'edit'
+ end
+ end
end
diff --git a/guides/code/getting_started/app/helpers/home_helper.rb b/guides/code/getting_started/app/helpers/welcome_helper.rb
index eeead45fc9..eeead45fc9 100644
--- a/guides/code/getting_started/app/helpers/home_helper.rb
+++ b/guides/code/getting_started/app/helpers/welcome_helper.rb
diff --git a/guides/code/getting_started/app/views/posts/_form.html.erb b/guides/code/getting_started/app/views/posts/_form.html.erb
index 18cb29f335..46ec257b91 100644
--- a/guides/code/getting_started/app/views/posts/_form.html.erb
+++ b/guides/code/getting_started/app/views/posts/_form.html.erb
@@ -1,4 +1,4 @@
-<%= form_for :post, :url => { :action => :create } do |f| %>
+<%= form_for :post, :url => { :action => :update, :id => @post.id }, :method => :put do |f| %>
<% if @post.errors.any? %>
<div id="errorExplanation">
<h2><%= pluralize(@post.errors.count, "error") %> prohibited this post from being saved:</h2>
diff --git a/guides/code/getting_started/app/views/posts/edit.html.erb b/guides/code/getting_started/app/views/posts/edit.html.erb
index 720580236b..911a48569d 100644
--- a/guides/code/getting_started/app/views/posts/edit.html.erb
+++ b/guides/code/getting_started/app/views/posts/edit.html.erb
@@ -2,5 +2,4 @@
<%= render 'form' %>
-<%= link_to 'Show', @post %> |
-<%= link_to 'Back', posts_path %>
+<%= link_to 'Back', :action => :index %>
diff --git a/guides/code/getting_started/app/views/posts/index.html.erb b/guides/code/getting_started/app/views/posts/index.html.erb
index 455a74b17f..3ba7091c15 100644
--- a/guides/code/getting_started/app/views/posts/index.html.erb
+++ b/guides/code/getting_started/app/views/posts/index.html.erb
@@ -7,6 +7,7 @@
<th>Title</th>
<th>Text</th>
<th></th>
+ <th></th>
</tr>
<% @posts.each do |post| %>
@@ -14,6 +15,7 @@
<td><%= post.title %></td>
<td><%= post.text %></td>
<td><%= link_to 'Show', :action => :show, :id => post.id %>
+ <td><%= link_to 'Edit', :action => :edit, :id => post.id %>
</tr>
<% end %>
</table>
diff --git a/guides/code/getting_started/app/views/posts/show.html.erb b/guides/code/getting_started/app/views/posts/show.html.erb
index a79fadfe4c..aea28cd5a2 100644
--- a/guides/code/getting_started/app/views/posts/show.html.erb
+++ b/guides/code/getting_started/app/views/posts/show.html.erb
@@ -9,3 +9,4 @@
</p>
<%= link_to 'Back', :action => :index %>
+| <%= link_to 'Edit', :action => :edit, :id => @post.id %>
diff --git a/guides/code/getting_started/config/routes.rb b/guides/code/getting_started/config/routes.rb
index 10009a35cf..b0973c62d5 100644
--- a/guides/code/getting_started/config/routes.rb
+++ b/guides/code/getting_started/config/routes.rb
@@ -7,6 +7,8 @@ Blog::Application.routes.draw do
get "posts/new"
post "posts/create"
get "posts/:id" => "posts#show"
+ get "posts/:id/edit" => "posts#edit"
+ put "posts/:id/update" => "posts#update"
# The priority is based upon order of creation:
# first created -> highest priority.
diff --git a/guides/source/active_record_querying.textile b/guides/source/active_record_querying.textile
index 58eae2ee0f..98937266ba 100644
--- a/guides/source/active_record_querying.textile
+++ b/guides/source/active_record_querying.textile
@@ -388,6 +388,8 @@ The field name can also be a string:
Client.where('locked' => true)
</ruby>
+NOTE: The values cannot be symbols. For example, you cannot do +Client.where(:status => :active)+.
+
h5(#hash-range_conditions). Range Conditions
The good thing about this is that we can pass in a range for our fields without it generating a large query as shown in the preamble of this section.
diff --git a/guides/source/generators.textile b/guides/source/generators.textile
index 920ff997ae..e9d713d91d 100644
--- a/guides/source/generators.textile
+++ b/guides/source/generators.textile
@@ -451,6 +451,27 @@ Adds a specified source to +Gemfile+:
add_source "http://gems.github.com"
</ruby>
+h4. +inject_into_file+
+
+Injects a block of code into a defined position in your file.
+
+<ruby>
+inject_into_file 'name_of_file.rb', :after => "#The code goes below this line. Don't forget the Line break at the end\n" do <<-'RUBY'
+ puts "Hello World"
+RUBY
+end
+</ruby>
+
+h4. +gsub_file+
+
+Replaces text inside a file.
+
+<ruby>
+gsub_file 'name_of_file.rb', 'method.to_be_replaced', 'method.the_replacing_code'
+</ruby
+
+Regular Expressions can be used to make this method more precise. You can also use append_file and prepend_file in the same way to place code at the beginning and end of a file respectively.
+
h4. +application+
Adds a line to +config/application.rb+ directly after the application class definition.
diff --git a/guides/source/getting_started.textile b/guides/source/getting_started.textile
index f184004f80..88d5ce6d9b 100644
--- a/guides/source/getting_started.textile
+++ b/guides/source/getting_started.textile
@@ -516,7 +516,7 @@ end
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
+hold a 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
@@ -577,8 +577,8 @@ end
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.
+You can now create, show, and list posts. Now let's add some links to
+navigate through pages.
Open +app/views/welcome/index.html.erb+ and modify it as follows:
@@ -619,19 +619,7 @@ Let's add links to the other views as well.
# 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 %>
@@ -657,11 +645,9 @@ controller by default.
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
-and restart the web server.
-
-Congratulations, you're riding the rails! Now it’s time to see how it all works.
+and restart the web server when a change is made.
-h4. The Model
+h4. Adding Some Validation
The model file, +app/models/post.rb+ is about as simple as it can get:
@@ -676,8 +662,6 @@ your Rails models for free, including basic database CRUD (Create, Read, Update,
Destroy) operations, data validation, as well as sophisticated search support
and the ability to relate multiple models to one another.
-h4. Adding Some Validation
-
Rails includes methods to help you validate the data that you send to models.
Open the +app/models/post.rb+ file and edit it:
@@ -730,7 +714,7 @@ 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| %>
+<%= form_for :post, :url => { :action => :create } do |f| %>
<% if @post.errors.any? %>
<div id="errorExplanation">
<h2><%= pluralize(@post.errors.count, "error") %> prohibited
@@ -780,6 +764,172 @@ 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. Updating Posts
+
+We've covered the "CR" part of CRUD. Now let's focus on the "U" part,
+updating posts.
+
+The first step we'll take is adding a +edit+ action to
++posts_controller+.
+
+Start by adding a route to +config/routes.rb+:
+
+<ruby>
+get "posts/:id/edit" => "posts#edit"
+</ruby>
+
+And then add the controller action:
+
+<ruby>
+def edit
+ @post = Post.find(params[:id])
+end
+</ruby>
+
+The view will contain a form similar to the one we used when creating
+new posts. Create a file called +app/views/posts/edit.html.erb+ and make
+it look as follows:
+
+<erb>
+<h1>Editing post</h1>
+
+<%= form_for :post, :url => { :action => :update, :id => @post.id },
+:method => :put 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>
+
+This time we point the form to the +update+ action (not defined yet).
+The +:method => :put+ option tells Rails that we want this form to be
+submitted via +put+, which is the http method you're expected to use to
+*update* resources according to the REST protocol.
+
+TIP: By default forms built with the +form_for_ helper are sent via +POST+.
+
+Moving on, we need to add the +update+ action. The file
++config/routes.rb+ will need just one more line:
+
+<ruby>
+put "posts/:id/update"
+</ruby>
+
+And the +update+ action in +posts_controller+ itself should not look too complicated by now:
+
+<ruby>
+def update
+ @post = Post.find(params[:id])
+
+ if @post.update_attributes(params[:post])
+ redirect_to :action => :show, :id => @post.id
+ else
+ render 'edit'
+ end
+end
+</ruby>
+
+The new method +update_attributes+ is used when you want to update a record
+that already exists, and it accepts an hash containing the attributes
+that you want to update. As before, if there was an error updating the
+post we want to show the form back to the user.
+
+TIP: you don't need to pass all attributes to +update_attributes+. For
+example, if you'd call +@post.update_attributes(:title => 'A new title')+
+Rails would only update the +title+ attribute, leaving all other
+attributes untouched.
+
+Finally, we want to show a link to the +edit+ action in the +index+ and
++show+ views:
+
+<erb>
+# app/view/posts/index.html.erb
+
+<table>
+ <tr>
+ <th>Title</th>
+ <th>Text</th>
+ <th></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>
+ <td><%= link_to 'Edit', :action => :edit, :id => post.id %></td>
+ </tr>
+<% end %>
+</table>
+
+# app/view/posts/show.html.erb
+
+...
+
+<%= link_to 'Back', :action => :index %>
+| <%= link_to 'Edit', :action => :edit, :id => @post.id %>
+</erb>
+
+And here's how our app looks so far:
+
+!images/getting_started/index_action_with_edit_link.png(Index action
+with edit link)!
+
+h4. Using partials to clean up duplication in views
+
++partials+ are what Rails uses to remove duplication in views. Here's a
+simple example:
+
+<erb>
+# app/views/user/show.html.erb
+
+<h1><%= @user.name %></h1>
+
+<%= render 'user_details' %>
+
+# app/views/user/_user_details.html.erb
+
+<%= @user.location %>
+
+<%= @user.about_me %>
+</erb>
+
+The +show+ view will automatically include the content of the
++_user_details+ view. Note that partials are prefixed by an underscore,
+as to not be confused with regular views. However, you don't include the
+underscore when including them with the +helper+ method.
+
+TIP: You can red more about partials in the "Layouts and Rendering in
+Rails":layouts_and_rendering.html guide.
+
+Our +edit+ action looks very similar to the +new+ action, in fact they
+both share the same code for displaying the form. Lets clean them up by
+using a +_form+ partial.
+
h4. Using the Console
To see your validations in action, you can use the console. The console is a
diff --git a/guides/source/layout.html.erb b/guides/source/layout.html.erb
index 35b6fc7014..0a8daf7ae5 100644
--- a/guides/source/layout.html.erb
+++ b/guides/source/layout.html.erb
@@ -14,6 +14,8 @@
<link rel="stylesheet" type="text/css" href="stylesheets/syntaxhighlighter/shThemeRailsGuides.css" />
<link rel="stylesheet" type="text/css" href="stylesheets/fixes.css" />
+
+<link href="images/favicon.ico" rel="shortcut icon" type="image/x-icon" />
</head>
<body class="guide">
<% if @edge %>
diff --git a/guides/source/plugins.textile b/guides/source/plugins.textile
index 97b4eca779..95e38db483 100644
--- a/guides/source/plugins.textile
+++ b/guides/source/plugins.textile
@@ -25,16 +25,14 @@ endprologue.
h3. Setup
-Before you continue, take a moment to decide if your new plugin will be potentially shared across different Rails applications.
+_"vendored plugins"_ were available in previous versions of Rails, but they are deprecated in
+Rails 3.2, and will not be available in the future.
-* If your plugin is specific to your application, your new plugin will be a _vendored plugin_.
-* If you think your plugin may be used across applications, build it as a _gemified plugin_.
+Currently, Rails plugins are built as gems, _gemified plugins_. They can be shared accross
+different rails applications using RubyGems and Bundler if desired.
h4. Generate a gemified plugin.
-Writing your Rails plugin as a gem, rather than as a vendored plugin,
- lets you share your plugin across different rails applications using
- RubyGems and Bundler.
Rails 3.1 ships with a +rails plugin new+ command which creates a
skeleton for developing any kind of Rails extension with the ability
diff --git a/railties/test/generators/namespaced_generators_test.rb b/railties/test/generators/namespaced_generators_test.rb
index 5c63b13dce..76c34d4c50 100644
--- a/railties/test/generators/namespaced_generators_test.rb
+++ b/railties/test/generators/namespaced_generators_test.rb
@@ -56,7 +56,7 @@ class NamespacedControllerGeneratorTest < NamespacedGeneratorTestCase
run_generator
assert_file "config/routes.rb", /get "account\/foo"/, /get "account\/bar"/
end
-#
+
def test_invokes_default_template_engine_even_with_no_action
run_generator ["account"]
assert_file "app/views/test_app/account"