Merge branch 'master' of github.com:lifo/docrails
This commit is contained in:
commit
4a3ce153f1
@ -64,6 +64,9 @@ module DateHelper
|
||||
# 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)
|
||||
|
@ -902,7 +902,7 @@ def text_area(object_name, method, options = {})
|
||||
# # 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")
|
||||
|
@ -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
|
||||
|
@ -58,7 +58,8 @@ def authenticate(unencrypted_password)
|
||||
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
|
||||
|
@ -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 ||= {}
|
||||
|
BIN
guides/assets/images/favicon.ico
Normal file
BIN
guides/assets/images/favicon.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.1 KiB |
Binary file not shown.
After Width: | Height: | Size: 15 KiB |
@ -21,4 +21,18 @@ def create
|
||||
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
|
||||
|
@ -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>
|
||||
|
@ -2,5 +2,4 @@
|
||||
|
||||
<%= render 'form' %>
|
||||
|
||||
<%= link_to 'Show', @post %> |
|
||||
<%= link_to 'Back', posts_path %>
|
||||
<%= link_to 'Back', :action => :index %>
|
||||
|
@ -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>
|
||||
|
@ -9,3 +9,4 @@
|
||||
</p>
|
||||
|
||||
<%= link_to 'Back', :action => :index %>
|
||||
| <%= link_to 'Edit', :action => :edit, :id => @post.id %>
|
||||
|
@ -7,6 +7,8 @@
|
||||
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.
|
||||
|
@ -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.
|
||||
|
@ -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.
|
||||
|
@ -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.
|
||||
and restart the web server when a change is made.
|
||||
|
||||
Congratulations, you're riding the rails! Now it’s time to see how it all works.
|
||||
|
||||
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
|
||||
|
@ -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 %>
|
||||
|
@ -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
|
||||
|
@ -56,7 +56,7 @@ def test_routes_should_not_be_namespaced
|
||||
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"
|
||||
|
Loading…
Reference in New Issue
Block a user