aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--actionpack/lib/abstract_controller/layouts.rb38
-rw-r--r--actionpack/lib/action_dispatch/middleware/debug_exceptions.rb2
-rw-r--r--activesupport/lib/active_support/basic_object.rb3
-rw-r--r--activesupport/lib/active_support/core_ext/integer/time.rb3
-rw-r--r--guides/source/active_record_validations.md140
-rw-r--r--railties/CHANGELOG.md4
-rw-r--r--railties/lib/rails/info_controller.rb3
-rw-r--r--railties/lib/rails/templates/rails/info/routes.html.erb75
-rw-r--r--railties/test/rails_info_controller_test.rb2
9 files changed, 248 insertions, 22 deletions
diff --git a/actionpack/lib/abstract_controller/layouts.rb b/actionpack/lib/abstract_controller/layouts.rb
index 12da273af9..73799e8085 100644
--- a/actionpack/lib/abstract_controller/layouts.rb
+++ b/actionpack/lib/abstract_controller/layouts.rb
@@ -212,21 +212,23 @@ module AbstractController
delegate :_layout_conditions, :to => "self.class"
module ClassMethods
- def inherited(klass)
+ def inherited(klass) # :nodoc:
super
klass._write_layout_method
end
# This module is mixed in if layout conditions are provided. This means
# that if no layout conditions are used, this method is not used
- module LayoutConditions
- # Determines whether the current action has a layout by checking the
- # action name against the :only and :except conditions set on the
- # layout.
+ module LayoutConditions # :nodoc:
+ private
+
+ # Determines whether the current action has a layout definition by
+ # checking the action name against the :only and :except conditions
+ # set by the <tt>layout</tt> method.
#
# ==== Returns
- # * <tt> Boolean</tt> - True if the action has a layout, false otherwise.
- def conditional_layout?
+ # * <tt> Boolean</tt> - True if the action has a layout definition, false otherwise.
+ def _conditional_layout?
return unless super
conditions = _layout_conditions
@@ -271,7 +273,7 @@ module AbstractController
#
# ==== Returns
# * <tt>String</tt> - A template name
- def _implied_layout_name
+ def _implied_layout_name # :nodoc:
controller_path
end
@@ -279,7 +281,7 @@ module AbstractController
#
# If a layout is not explicitly mentioned then look for a layout with the controller's name.
# if nothing is found then try same procedure to find super class's layout.
- def _write_layout_method
+ def _write_layout_method # :nodoc:
remove_possible_method(:_layout)
prefixes = _implied_layout_name =~ /\blayouts/ ? [] : ["layouts"]
@@ -318,7 +320,7 @@ module AbstractController
self.class_eval <<-RUBY, __FILE__, __LINE__ + 1
def _layout
- if conditional_layout?
+ if _conditional_layout?
#{layout_definition}
else
#{name_clause}
@@ -329,7 +331,7 @@ module AbstractController
end
end
- def _normalize_options(options)
+ def _normalize_options(options) # :nodoc:
super
if _include_layout?(options)
@@ -340,21 +342,27 @@ module AbstractController
attr_internal_writer :action_has_layout
- def initialize(*)
+ def initialize(*) # :nodoc:
@_action_has_layout = true
super
end
+ # Controls whether an action should be rendered using a layout.
+ # If you want to disable any <tt>layout</tt> settings for the
+ # current action so that it is rendered without a layout then
+ # either override this method in your controller to return false
+ # for that action or set the <tt>action_has_layout</tt> attribute
+ # to false before rendering.
def action_has_layout?
@_action_has_layout
end
- def conditional_layout?
+ private
+
+ def _conditional_layout?
true
end
- private
-
# This will be overwritten by _write_layout_method
def _layout; end
diff --git a/actionpack/lib/action_dispatch/middleware/debug_exceptions.rb b/actionpack/lib/action_dispatch/middleware/debug_exceptions.rb
index 0f0589a844..f356c2a85c 100644
--- a/actionpack/lib/action_dispatch/middleware/debug_exceptions.rb
+++ b/actionpack/lib/action_dispatch/middleware/debug_exceptions.rb
@@ -7,7 +7,7 @@ module ActionDispatch
# This middleware is responsible for logging exceptions and
# showing a debugging page in case the request is local.
class DebugExceptions
- RESCUES_TEMPLATE_PATH = File.join(File.dirname(__FILE__), 'templates')
+ RESCUES_TEMPLATE_PATH = File.expand_path('../templates', __FILE__)
def initialize(app, routes_app = nil)
@app = app
diff --git a/activesupport/lib/active_support/basic_object.rb b/activesupport/lib/active_support/basic_object.rb
index d4d06b2aa4..91aac6db64 100644
--- a/activesupport/lib/active_support/basic_object.rb
+++ b/activesupport/lib/active_support/basic_object.rb
@@ -2,8 +2,7 @@ require 'active_support/deprecation'
require 'active_support/proxy_object'
module ActiveSupport
- # :nodoc:
- class BasicObject < ProxyObject
+ class BasicObject < ProxyObject # :nodoc:
def self.inherited(*)
::ActiveSupport::Deprecation.warn 'ActiveSupport::BasicObject is deprecated! Use ActiveSupport::ProxyObject instead.'
super
diff --git a/activesupport/lib/active_support/core_ext/integer/time.rb b/activesupport/lib/active_support/core_ext/integer/time.rb
index 9fb4f6b73a..82080ffe51 100644
--- a/activesupport/lib/active_support/core_ext/integer/time.rb
+++ b/activesupport/lib/active_support/core_ext/integer/time.rb
@@ -1,3 +1,6 @@
+require 'active_support/duration'
+require 'active_support/core_ext/numeric/time'
+
class Integer
# Enables the use of time calculations and declarations, like <tt>45.minutes +
# 2.hours + 4.years</tt>.
diff --git a/guides/source/active_record_validations.md b/guides/source/active_record_validations.md
index 88d52cb829..822d12aa3a 100644
--- a/guides/source/active_record_validations.md
+++ b/guides/source/active_record_validations.md
@@ -909,6 +909,146 @@ class Invoice < ActiveRecord::Base
end
```
+Working with Validation Errors
+------------------------------
+
+In addition to the `valid?` and `invalid?` methods covered earlier, Rails provides a number of methods for working with the `errors` collection and inquiring about the validity of objects.
+
+The following is a list of the most commonly used methods. Please refer to the `ActiveModel::Errors` documentation for a list of all the available methods.
+
+### `errors`
+
+Returns an instance of the class `ActiveModel::Errors` containing all errors. Each key is the attribute name and the value is an array of strings with all errors.
+
+```ruby
+class Person < ActiveRecord::Base
+ validates :name, presence: true, length: { minimum: 3 }
+end
+
+person = Person.new
+person.valid? # => false
+person.errors
+ # => {:name=>["can't be blank", "is too short (minimum is 3 characters)"]}
+
+person = Person.new(name: "John Doe")
+person.valid? # => true
+person.errors # => []
+```
+
+### `errors[]`
+
+`errors[]` is used when you want to check the error messages for a specific attribute. It returns an array of strings with all error messages for the given attribute, each string with one error message. If there are no errors related to the attribute, it returns an empty array.
+
+```ruby
+class Person < ActiveRecord::Base
+ validates :name, presence: true, length: { minimum: 3 }
+end
+
+person = Person.new(name: "John Doe")
+person.valid? # => true
+person.errors[:name] # => []
+
+person = Person.new(name: "JD")
+person.valid? # => false
+person.errors[:name] # => ["is too short (minimum is 3 characters)"]
+
+person = Person.new
+person.valid? # => false
+person.errors[:name]
+ # => ["can't be blank", "is too short (minimum is 3 characters)"]
+```
+
+### `errors.add`
+
+The `add` method lets you manually add messages that are related to particular attributes. You can use the `errors.full_messages` or `errors.to_a` methods to view the messages in the form they might be displayed to a user. Those particular messages get the attribute name prepended (and capitalized). `add` receives the name of the attribute you want to add the message to, and the message itself.
+
+```ruby
+class Person < ActiveRecord::Base
+ def a_method_used_for_validation_purposes
+ errors.add(:name, "cannot contain the characters !@#%*()_-+=")
+ end
+end
+
+person = Person.create(name: "!@#")
+
+person.errors[:name]
+ # => ["cannot contain the characters !@#%*()_-+="]
+
+person.errors.full_messages
+ # => ["Name cannot contain the characters !@#%*()_-+="]
+```
+
+Another way to do this is using `[]=` setter
+
+```ruby
+ class Person < ActiveRecord::Base
+ def a_method_used_for_validation_purposes
+ errors[:name] = "cannot contain the characters !@#%*()_-+="
+ end
+ end
+
+ person = Person.create(name: "!@#")
+
+ person.errors[:name]
+ # => ["cannot contain the characters !@#%*()_-+="]
+
+ person.errors.to_a
+ # => ["Name cannot contain the characters !@#%*()_-+="]
+```
+
+### `errors[:base]`
+
+You can add error messages that are related to the object's state as a whole, instead of being related to a specific attribute. You can use this method when you want to say that the object is invalid, no matter the values of its attributes. Since `errors[:base]` is an array, you can simply add a string to it and it will be used as an error message.
+
+```ruby
+class Person < ActiveRecord::Base
+ def a_method_used_for_validation_purposes
+ errors[:base] << "This person is invalid because ..."
+ end
+end
+```
+
+### `errors.clear`
+
+The `clear` method is used when you intentionally want to clear all the messages in the `errors` collection. Of course, calling `errors.clear` upon an invalid object won't actually make it valid: the `errors` collection will now be empty, but the next time you call `valid?` or any method that tries to save this object to the database, the validations will run again. If any of the validations fail, the `errors` collection will be filled again.
+
+```ruby
+class Person < ActiveRecord::Base
+ validates :name, presence: true, length: { minimum: 3 }
+end
+
+person = Person.new
+person.valid? # => false
+person.errors[:name]
+ # => ["can't be blank", "is too short (minimum is 3 characters)"]
+
+person.errors.clear
+person.errors.empty? # => true
+
+p.save # => false
+
+p.errors[:name]
+# => ["can't be blank", "is too short (minimum is 3 characters)"]
+```
+
+### `errors.size`
+
+The `size` method returns the total number of error messages for the object.
+
+```ruby
+class Person < ActiveRecord::Base
+ validates :name, presence: true, length: { minimum: 3 }
+end
+
+person = Person.new
+person.valid? # => false
+person.errors.size # => 2
+
+person = Person.new(name: "Andrea", email: "andrea@example.com")
+person.valid? # => true
+person.errors.size # => 0
+```
+
Displaying Validation Errors in Views
-------------------------------------
diff --git a/railties/CHANGELOG.md b/railties/CHANGELOG.md
index ed5dfc6446..126a38a2d6 100644
--- a/railties/CHANGELOG.md
+++ b/railties/CHANGELOG.md
@@ -1,5 +1,9 @@
## Rails 4.0.0 (unreleased) ##
+* The `rails/info/routes` now correctly formats routing output as an html table.
+
+ *Richard Schneeman*
+
* The `public/index.html` is no longer generated for new projects.
Page is replaced by internal `welcome_controller` inside of railties.
diff --git a/railties/lib/rails/info_controller.rb b/railties/lib/rails/info_controller.rb
index e296637f39..ec7d5ed610 100644
--- a/railties/lib/rails/info_controller.rb
+++ b/railties/lib/rails/info_controller.rb
@@ -15,8 +15,7 @@ class Rails::InfoController < ActionController::Base # :nodoc:
end
def routes
- inspector = ActionDispatch::Routing::RoutesInspector.new
- @info = inspector.format(_routes.routes).join("\n")
+ @routes = ActionDispatch::Routing::RoutesInspector.new.collect_routes(_routes.routes)
end
protected
diff --git a/railties/lib/rails/templates/rails/info/routes.html.erb b/railties/lib/rails/templates/rails/info/routes.html.erb
index 890f6f5b03..e34c1c4135 100644
--- a/railties/lib/rails/templates/rails/info/routes.html.erb
+++ b/railties/lib/rails/templates/rails/info/routes.html.erb
@@ -6,4 +6,77 @@
Routes match in priority from top to bottom
</p>
-<p><pre><%= @info %></pre></p> \ No newline at end of file
+<style type='text/css'>
+ #route_table td {padding: 0 30px;}
+ #route_table {margin: 0 auto 0;}
+</style>
+
+<table id='route_table' class='route_table'>
+ <thead>
+ <tr>
+ <th>Helper<br />
+ <%= link_to "Path", "#", 'data-route-helper' => '_path',
+ title: "Returns a relative path (without the http or domain)" %> /
+ <%= link_to "Url", "#", 'data-route-helper' => '_url',
+ title: "Returns an absolute url (with the http and domain)" %>
+ </th>
+ <th>HTTP Verb</th>
+ <th>Path</th>
+ <th>Controller#Action</th>
+ </tr>
+ </thead>
+ <tbody>
+ <% @routes.each do |route| %>
+ <tr class='route_row' data-helper='path'>
+ <td data-route-name='<%= route[:name] %>'>
+ <% if route[:name].present? %>
+ <%= route[:name] %><span class='helper'>_path</span>
+ <% end %>
+ </td>
+ <td data-route-verb='<%= route[:verb] %>'>
+ <%= route[:verb] %>
+ </td>
+ <td data-route-path='<%= route[:path] %>'>
+ <%= route[:path] %>
+ </td>
+ <td data-route-reqs='<%= route[:reqs] %>'>
+ <%= route[:reqs] %>
+ </td>
+ </tr>
+ <% end %>
+ </tbody>
+</table>
+
+<script type='text/javascript'>
+ function each(elems, func) {
+ if (!elems instanceof Array) var elems = [elems];
+ for(var i = elems.length; i--; ) {
+ func(elems[i]);
+ };
+ }
+
+ function setValOn(elems, val) {
+ each(elems, function(elem) {
+ elem.innerHTML = val;
+ })
+ }
+
+ function onClick(elems, func) {
+ each(elems, function(elem) {
+ elem.onclick = func;
+ })
+ }
+
+ // Enables functionality to toggle between `_path` and `_url` helper suffixes
+ function setupRouteToggleHelperLinks() {
+ var toggleLinks = document.querySelectorAll('#route_table [data-route-helper]');
+ onClick(toggleLinks, function(){
+ var helperTxt = this.getAttribute("data-route-helper");
+ var helperElems = document.querySelectorAll('[data-route-name] span.helper');
+ setValOn(helperElems, helperTxt);
+ })
+ }
+
+ setupRouteToggleHelperLinks();
+
+</script>
diff --git a/railties/test/rails_info_controller_test.rb b/railties/test/rails_info_controller_test.rb
index 08fcddd4bf..a9b237d0a5 100644
--- a/railties/test/rails_info_controller_test.rb
+++ b/railties/test/rails_info_controller_test.rb
@@ -50,7 +50,7 @@ class InfoControllerTest < ActionController::TestCase
test "info controller renders with routes" do
get :routes
- assert_select 'pre'
+ assert_response :success
end
end