From eb063538bd58c915c953e4b8a295d3a1b1a321d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Wed, 7 Apr 2010 00:45:56 +0200 Subject: Use config.filter_parameters on in-browser request dump. [#4335 state:resolved] --- .../middleware/templates/rescues/_request_and_response.erb | 2 +- actionpack/test/dispatch/show_exceptions_test.rb | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/actionpack/lib/action_dispatch/middleware/templates/rescues/_request_and_response.erb b/actionpack/lib/action_dispatch/middleware/templates/rescues/_request_and_response.erb index 839df50999..09ff052fd0 100644 --- a/actionpack/lib/action_dispatch/middleware/templates/rescues/_request_and_response.erb +++ b/actionpack/lib/action_dispatch/middleware/templates/rescues/_request_and_response.erb @@ -6,7 +6,7 @@ <% end %> <% - clean_params = @request.parameters.clone + clean_params = @request.filtered_parameters.clone clean_params.delete("action") clean_params.delete("controller") diff --git a/actionpack/test/dispatch/show_exceptions_test.rb b/actionpack/test/dispatch/show_exceptions_test.rb index 97da680f17..b447b0715c 100644 --- a/actionpack/test/dispatch/show_exceptions_test.rb +++ b/actionpack/test/dispatch/show_exceptions_test.rb @@ -106,4 +106,13 @@ class ShowExceptionsTest < ActionController::IntegrationTest assert_response 405 assert_match /ActionController::MethodNotAllowed/, body end + + test "does not show filtered parameters" do + @app = DevelopmentApp + + get "/", {"foo"=>"bar"}, {'action_dispatch.show_exceptions' => true, + 'action_dispatch.parameter_filter' => [:foo]} + assert_response 500 + assert_match ""foo"=>"[FILTERED]"", body + end end -- cgit v1.2.3 From 48634bf59a0ed89cddd4a539c08866c9e025c5e3 Mon Sep 17 00:00:00 2001 From: Pratik Naik Date: Wed, 7 Apr 2010 01:16:45 +0100 Subject: Reset named scope cache whenever the @target is reset --- .../lib/active_record/associations/association_collection.rb | 11 +++++++++-- activerecord/test/cases/named_scope_test.rb | 10 ++++++++++ 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/activerecord/lib/active_record/associations/association_collection.rb b/activerecord/lib/active_record/associations/association_collection.rb index 5ecdf1ac8d..c1ec98a9c6 100644 --- a/activerecord/lib/active_record/associations/association_collection.rb +++ b/activerecord/lib/active_record/associations/association_collection.rb @@ -105,6 +105,7 @@ module ActiveRecord def reset reset_target! + reset_named_scopes_cache! @loaded = false end @@ -162,6 +163,7 @@ module ActiveRecord load_target delete(@target) reset_target! + reset_named_scopes_cache! end # Calculate sum using SQL, not Enumerable @@ -250,6 +252,7 @@ module ActiveRecord load_target destroy(@target) reset_target! + reset_named_scopes_cache! end def create(attrs = {}) @@ -406,8 +409,8 @@ module ActiveRecord super end elsif @reflection.klass.scopes[method] - @_scopes ||= {} - @_scopes[method] ||= with_scope(construct_scope) { @reflection.klass.send(method, *args) } + @_named_scopes_cache ||= {} + @_named_scopes_cache[method] ||= with_scope(construct_scope) { @reflection.klass.send(method, *args) } else with_scope(construct_scope) do if block_given? @@ -428,6 +431,10 @@ module ActiveRecord @target = Array.new end + def reset_named_scopes_cache! + @_named_scopes_cache = {} + end + def find_target records = if @reflection.options[:finder_sql] diff --git a/activerecord/test/cases/named_scope_test.rb b/activerecord/test/cases/named_scope_test.rb index 3d5ebb6cb8..e4cafad11e 100644 --- a/activerecord/test/cases/named_scope_test.rb +++ b/activerecord/test/cases/named_scope_test.rb @@ -422,6 +422,16 @@ class NamedScopeTest < ActiveRecord::TestCase post.comments.containing_the_letter_e.all # force load assert_no_queries { post.comments.containing_the_letter_e.all } end + + def test_named_scopes_are_reset_on_association_reload + post = posts(:welcome) + + [:destroy_all, :reset, :delete_all].each do |method| + before = post.comments.containing_the_letter_e + post.comments.send(method) + assert before.object_id != post.comments.containing_the_letter_e.object_id, "AssociationCollection##{method} should reset the named scopes cache" + end + end end class DynamicScopeMatchTest < ActiveRecord::TestCase -- cgit v1.2.3 From ec73710c79c5e1587b489b2ce05cc34138acf071 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Wed, 7 Apr 2010 02:24:29 +0200 Subject: Alleviate the pain in working with utf8 templates by setting a default encoding. --- railties/lib/rails/application/configuration.rb | 22 +++++++++++++++------- .../rails/app/templates/config/application.rb | 3 +++ railties/test/application/configuration_test.rb | 12 ++++++++++++ 3 files changed, 30 insertions(+), 7 deletions(-) diff --git a/railties/lib/rails/application/configuration.rb b/railties/lib/rails/application/configuration.rb index d3e4742e8a..f9f47ef679 100644 --- a/railties/lib/rails/application/configuration.rb +++ b/railties/lib/rails/application/configuration.rb @@ -6,21 +6,29 @@ module Rails include ::Rails::Configuration::Deprecated attr_accessor :allow_concurrency, :cache_classes, :cache_store, - :secret_token, :consider_all_requests_local, :dependency_loading, + :encoding, :consider_all_requests_local, :dependency_loading, :filter_parameters, :log_level, :logger, :metals, :plugins, :preload_frameworks, :reload_engines, :reload_plugins, - :serve_static_assets, :time_zone, :whiny_nils + :secret_token, :serve_static_assets, :time_zone, :whiny_nils def initialize(*) super - @allow_concurrency = false - @filter_parameters = [] - @dependency_loading = true + @allow_concurrency = false + @consider_all_requests_local = false + @encoding = "utf-8" + @filter_parameters = [] + @dependency_loading = true @serve_static_assets = true - @time_zone = "UTC" - @consider_all_requests_local = true @session_store = :cookie_store @session_options = {} + @time_zone = "UTC" + end + + def encoding=(value) + @encoding = value + if defined?(Encoding) && Encoding.respond_to?(:default_external=) + Encoding.default_external = value + end end def middleware diff --git a/railties/lib/rails/generators/rails/app/templates/config/application.rb b/railties/lib/rails/generators/rails/app/templates/config/application.rb index bd4fedcdec..377e607d2b 100644 --- a/railties/lib/rails/generators/rails/app/templates/config/application.rb +++ b/railties/lib/rails/generators/rails/app/templates/config/application.rb @@ -46,6 +46,9 @@ module <%= app_const_base %> # g.test_framework :test_unit, :fixture => true # end + # Configure the default encoding used in templates for Ruby 1.9. + config.encoding = "utf-8" + # Configure sensitive parameters which will be filtered from the log file. config.filter_parameters << :password end diff --git a/railties/test/application/configuration_test.rb b/railties/test/application/configuration_test.rb index 90f2e2b370..97d5f64708 100644 --- a/railties/test/application/configuration_test.rb +++ b/railties/test/application/configuration_test.rb @@ -172,6 +172,18 @@ module ApplicationTests assert $prepared end + test "config.encoding sets the default encoding" do + add_to_config <<-RUBY + config.encoding = "utf-8" + RUBY + + require "#{app_path}/config/application" + + unless RUBY_VERSION < '1.9' + assert_equal Encoding.find("utf-8"), Encoding.default_external + end + end + def make_basic_app require "rails" require "action_controller/railtie" -- cgit v1.2.3 From 149d13e1f0d157a48c04c8b3944f09ce463e9416 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Wed, 7 Apr 2010 16:18:13 +0200 Subject: Move the error raising to api_behavior. --- actionpack/lib/action_controller/metal/responder.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/actionpack/lib/action_controller/metal/responder.rb b/actionpack/lib/action_controller/metal/responder.rb index d97c10a293..6ad9a23542 100644 --- a/actionpack/lib/action_controller/metal/responder.rb +++ b/actionpack/lib/action_controller/metal/responder.rb @@ -135,7 +135,6 @@ module ActionController #:nodoc: def to_format default_render rescue ActionView::MissingTemplate => e - raise unless resourceful? api_behavior(e) end @@ -154,6 +153,8 @@ module ActionController #:nodoc: # This is the common behavior for "API" requests, like :xml and :json. def api_behavior(error) + raise error unless resourceful? + if get? display resource elsif has_errors? -- cgit v1.2.3 From 086392492cdf546713122c6ef1601e45fdf2142f Mon Sep 17 00:00:00 2001 From: Joshua Peek Date: Wed, 7 Apr 2010 13:12:47 -0500 Subject: Remove #size call on rack input io --- actionpack/lib/action_dispatch/middleware/params_parser.rb | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/actionpack/lib/action_dispatch/middleware/params_parser.rb b/actionpack/lib/action_dispatch/middleware/params_parser.rb index 18a3688bb0..c0efdae2a0 100644 --- a/actionpack/lib/action_dispatch/middleware/params_parser.rb +++ b/actionpack/lib/action_dispatch/middleware/params_parser.rb @@ -36,17 +36,13 @@ module ActionDispatch when Proc strategy.call(request.raw_post) when :xml_simple, :xml_node - request.body.size == 0 ? {} : Hash.from_xml(request.raw_post).with_indifferent_access + (Hash.from_xml(request.raw_post) || {}).with_indifferent_access when :yaml YAML.load(request.raw_post) when :json - if request.body.size == 0 - {} - else - data = ActiveSupport::JSON.decode(request.raw_post) - data = {:_json => data} unless data.is_a?(Hash) - data.with_indifferent_access - end + data = ActiveSupport::JSON.decode(request.raw_post) + data = {:_json => data} unless data.is_a?(Hash) + data.with_indifferent_access else false end -- cgit v1.2.3 From 3957d44fd10c683518562f22d8b73f1b1c3d455d Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Wed, 7 Apr 2010 11:42:07 -0700 Subject: Use request.body IO and rewind, if possible --- actionpack/lib/action_dispatch/middleware/params_parser.rb | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/actionpack/lib/action_dispatch/middleware/params_parser.rb b/actionpack/lib/action_dispatch/middleware/params_parser.rb index c0efdae2a0..1524b00d5b 100644 --- a/actionpack/lib/action_dispatch/middleware/params_parser.rb +++ b/actionpack/lib/action_dispatch/middleware/params_parser.rb @@ -36,11 +36,14 @@ module ActionDispatch when Proc strategy.call(request.raw_post) when :xml_simple, :xml_node - (Hash.from_xml(request.raw_post) || {}).with_indifferent_access + data = Hash.from_xml(request.body) || {} + request.body.rewind if request.body.respond_to?(:rewind) + data.with_indifferent_access when :yaml YAML.load(request.raw_post) when :json - data = ActiveSupport::JSON.decode(request.raw_post) + data = ActiveSupport::JSON.decode(request.body) + request.body.rewind if request.body.respond_to?(:rewind) data = {:_json => data} unless data.is_a?(Hash) data.with_indifferent_access else @@ -72,4 +75,4 @@ module ActionDispatch defined?(Rails.logger) ? Rails.logger : Logger.new($stderr) end end -end \ No newline at end of file +end -- cgit v1.2.3 From d18ff1b7efd96e7c08bc1a15137735be45f87e07 Mon Sep 17 00:00:00 2001 From: Xavier Noria Date: Wed, 7 Apr 2010 13:04:52 -0700 Subject: new helpers #favicon_link_tag and #apple_touch_icon_link_tag --- .../lib/action_view/helpers/asset_tag_helper.rb | 38 ++++++++++++++++++++++ actionpack/test/template/asset_tag_helper_test.rb | 19 +++++++++++ 2 files changed, 57 insertions(+) diff --git a/actionpack/lib/action_view/helpers/asset_tag_helper.rb b/actionpack/lib/action_view/helpers/asset_tag_helper.rb index e4ec17467e..1ca95b7dd1 100644 --- a/actionpack/lib/action_view/helpers/asset_tag_helper.rb +++ b/actionpack/lib/action_view/helpers/asset_tag_helper.rb @@ -501,6 +501,44 @@ module ActionView end end + # Returns a link tag for a favicon. + # + # <%= favicon_link_tag %> + # + # generates + # + # + # + # You can specify a different icon file in the first argument: + # + # <%= favicon_link_tag 'favicon.ico' %> + # + # That's passed to +image_path+ as is, so the example above would render + # + # + # + # The helper accepts an additional options hash where you can override "rel" and "type". + def favicon_link_tag(source=nil, options={}) + tag('link', { + :rel => 'shortcut icon', + :type => 'image/vnd.microsoft.icon', + :href => image_path(source || '/favicon.ico') + }.merge(options.symbolize_keys)) + end + + # Returns a link tag for an icon targetted at iPod Touch, iPhone, and iPad. + # + # <%= apple_touch_icon_link_tag 'my_site.png' %> + # + # generates + # + # + # + # The source argument is passed to +image_path+ as is. + def apple_touch_icon_link_tag(source) + tag('link', :rel => 'apple-touch-icon', :href => image_path(source)) + end + # Computes the path to an image asset in the public images directory. # Full paths from the document root will be passed through. # Used internally by +image_tag+ to build the image path. diff --git a/actionpack/test/template/asset_tag_helper_test.rb b/actionpack/test/template/asset_tag_helper_test.rb index 223a430f92..71052fb22c 100644 --- a/actionpack/test/template/asset_tag_helper_test.rb +++ b/actionpack/test/template/asset_tag_helper_test.rb @@ -157,6 +157,17 @@ class AssetTagHelperTest < ActionView::TestCase %(image_tag("mouse.png", :mouseover => image_path("mouse_over.png"))) => %(Mouse) } + FaviconLinkToTag = { + %(favicon_link_tag) => %(), + %(favicon_link_tag 'favicon.ico') => %(), + %(favicon_link_tag 'favicon.ico', :rel => 'foo') => %(), + %(favicon_link_tag 'favicon.ico', :rel => 'foo', :type => 'bar') => %() + } + + AppleTouchIconLinkToTag = { + %(apple_touch_icon_link_tag 'my_site.png') => %() + } + VideoPathToTag = { %(video_path("xml")) => %(/videos/xml), %(video_path("xml.ogg")) => %(/videos/xml.ogg), @@ -331,6 +342,14 @@ class AssetTagHelperTest < ActionView::TestCase ImageLinkToTag.each { |method, tag| assert_dom_equal(tag, eval(method)) } end + def test_favicon_link_tag + FaviconLinkToTag.each { |method, tag| assert_dom_equal(tag, eval(method)) } + end + + def test_apple_touch_link_tag + AppleTouchIconLinkToTag.each { |method, tag| assert_dom_equal(tag, eval(method)) } + end + def test_image_tag_windows_behaviour old_asset_id, ENV["RAILS_ASSET_ID"] = ENV["RAILS_ASSET_ID"], "1" # This simulates the behaviour of File#exist? on windows when testing a file ending in "." -- cgit v1.2.3 From eed89e65b6320a59115da0c5ef004c727e0f9cbf Mon Sep 17 00:00:00 2001 From: Joshua Peek Date: Wed, 7 Apr 2010 15:07:40 -0500 Subject: Make sure MemCacheStore logger exists --- activesupport/lib/active_support/cache/mem_cache_store.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/activesupport/lib/active_support/cache/mem_cache_store.rb b/activesupport/lib/active_support/cache/mem_cache_store.rb index d84a62ca2d..c56fedc12e 100644 --- a/activesupport/lib/active_support/cache/mem_cache_store.rb +++ b/activesupport/lib/active_support/cache/mem_cache_store.rb @@ -64,7 +64,7 @@ module ActiveSupport @data.get(key, raw?(options)) end rescue MemCache::MemCacheError => e - logger.error("MemCacheError (#{e}): #{e.message}") + logger.error("MemCacheError (#{e}): #{e.message}") if logger nil end @@ -85,7 +85,7 @@ module ActiveSupport response == Response::STORED end rescue MemCache::MemCacheError => e - logger.error("MemCacheError (#{e}): #{e.message}") + logger.error("MemCacheError (#{e}): #{e.message}") if logger false end @@ -95,7 +95,7 @@ module ActiveSupport response == Response::DELETED end rescue MemCache::MemCacheError => e - logger.error("MemCacheError (#{e}): #{e.message}") + logger.error("MemCacheError (#{e}): #{e.message}") if logger false end -- cgit v1.2.3 From ec8610cfdc32d0fe816fb22405e00ef1b6c90d73 Mon Sep 17 00:00:00 2001 From: Xavier Noria Date: Wed, 7 Apr 2010 13:19:55 -0700 Subject: adds a default source to #apple_touch_icon_link_tag --- actionpack/lib/action_view/helpers/asset_tag_helper.rb | 18 ++++++++++++------ actionpack/test/template/asset_tag_helper_test.rb | 1 + 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/actionpack/lib/action_view/helpers/asset_tag_helper.rb b/actionpack/lib/action_view/helpers/asset_tag_helper.rb index 1ca95b7dd1..47abf1e41c 100644 --- a/actionpack/lib/action_view/helpers/asset_tag_helper.rb +++ b/actionpack/lib/action_view/helpers/asset_tag_helper.rb @@ -518,24 +518,30 @@ module ActionView # # # The helper accepts an additional options hash where you can override "rel" and "type". - def favicon_link_tag(source=nil, options={}) + def favicon_link_tag(source='/favicon.ico', options={}) tag('link', { :rel => 'shortcut icon', :type => 'image/vnd.microsoft.icon', - :href => image_path(source || '/favicon.ico') + :href => image_path(source) }.merge(options.symbolize_keys)) end # Returns a link tag for an icon targetted at iPod Touch, iPhone, and iPad. # - # <%= apple_touch_icon_link_tag 'my_site.png' %> + # <%= apple_touch_icon_link_tag %> # # generates # - # + # + # + # You can specify a different icon file: + # + # <%= apple_touch_icon_link_tag "my_site.png" %> # - # The source argument is passed to +image_path+ as is. - def apple_touch_icon_link_tag(source) + # That's passed to +image_path+ as is, so the example above would render + # + # + def apple_touch_icon_link_tag(source='/apple-touch-icon.png') tag('link', :rel => 'apple-touch-icon', :href => image_path(source)) end diff --git a/actionpack/test/template/asset_tag_helper_test.rb b/actionpack/test/template/asset_tag_helper_test.rb index 71052fb22c..10ee9c7881 100644 --- a/actionpack/test/template/asset_tag_helper_test.rb +++ b/actionpack/test/template/asset_tag_helper_test.rb @@ -165,6 +165,7 @@ class AssetTagHelperTest < ActionView::TestCase } AppleTouchIconLinkToTag = { + %(apple_touch_icon_link_tag) => %(), %(apple_touch_icon_link_tag 'my_site.png') => %() } -- cgit v1.2.3 From 6891f46d10957f21f200fc4dc2b6076ff411b1da Mon Sep 17 00:00:00 2001 From: Xavier Noria Date: Wed, 7 Apr 2010 15:07:07 -0700 Subject: adds #favicon_link_tag and #apple_touch_icon_link_tag to AP's CHANGELOG --- actionpack/CHANGELOG | 2 ++ 1 file changed, 2 insertions(+) diff --git a/actionpack/CHANGELOG b/actionpack/CHANGELOG index 84481d0194..3c765933ef 100644 --- a/actionpack/CHANGELOG +++ b/actionpack/CHANGELOG @@ -1,5 +1,7 @@ *Rails 3.0.0 [Edge] (pending)* +* New helpers #favicon_link_tag and #apple_touch_icon_link_tag [fxn] + * Added all the new HTML5 form types as individual form tag methods (search, url, number, etc) #3646 [Stephen Celis] * Changed the object used in routing constraints to be an instance of -- cgit v1.2.3 From 336cb3c0bf3d38400f6c774ca78376117b899985 Mon Sep 17 00:00:00 2001 From: Mikel Lindsaar Date: Thu, 8 Apr 2010 15:52:35 +1000 Subject: Adding Rails.env= to railties to allow changing of rails env on the fly for rake tasks etc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: José Valim --- railties/lib/rails.rb | 4 ++++ railties/test/railties/railtie_test.rb | 11 +++++++++++ 2 files changed, 15 insertions(+) diff --git a/railties/lib/rails.rb b/railties/lib/rails.rb index 9d02da104d..085b82c154 100644 --- a/railties/lib/rails.rb +++ b/railties/lib/rails.rb @@ -79,6 +79,10 @@ module Rails @_env ||= ActiveSupport::StringInquirer.new(ENV["RAILS_ENV"] || ENV["RACK_ENV"] || "development") end + def env=(environment) + @_env = ActiveSupport::StringInquirer.new(environment) + end + def cache RAILS_CACHE end diff --git a/railties/test/railties/railtie_test.rb b/railties/test/railties/railtie_test.rb index 546bf5e143..2accaca855 100644 --- a/railties/test/railties/railtie_test.rb +++ b/railties/test/railties/railtie_test.rb @@ -125,5 +125,16 @@ module RailtiesTest require "#{app_path}/config/environment" assert $ran_block end + + test "we can change our environment if we want to" do + begin + original_env = Rails.env + Rails.env = 'foo' + assert_equal('foo', Rails.env) + ensure + Rails.env = original_env + assert_equal(original_env, Rails.env) + end + end end end -- cgit v1.2.3 From 4e92134dfa15ae198c714b85376838ffec5a7773 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Thu, 8 Apr 2010 12:52:37 +0200 Subject: Fix a bug in ActionDispatch::Static where Rails cannot find assets if started in another directory which is not the RAILS_ROOT. --- actionpack/lib/action_controller/caching/pages.rb | 4 ++-- actionpack/lib/action_controller/metal/compatibility.rb | 2 -- actionpack/lib/action_controller/railtie.rb | 6 ++++++ railties/lib/rails.rb | 5 +++-- railties/lib/rails/application/configuration.rb | 2 +- railties/test/application/configuration_test.rb | 9 +++++++++ 6 files changed, 21 insertions(+), 7 deletions(-) diff --git a/actionpack/lib/action_controller/caching/pages.rb b/actionpack/lib/action_controller/caching/pages.rb index fe95f0e0d7..2a0a1107eb 100644 --- a/actionpack/lib/action_controller/caching/pages.rb +++ b/actionpack/lib/action_controller/caching/pages.rb @@ -38,22 +38,22 @@ module ActionController #:nodoc: extend ActiveSupport::Concern included do - @@page_cache_directory = defined?(Rails.public_path) ? Rails.public_path : "" ## # :singleton-method: # The cache directory should be the document root for the web server and is set using Base.page_cache_directory = "/document/root". # For Rails, this directory has already been set to Rails.public_path (which is usually set to RAILS_ROOT + "/public"). Changing # this setting can be useful to avoid naming conflicts with files in public/, but doing so will likely require configuring your # web server to look in the new location for cached files. + @@page_cache_directory = '' cattr_accessor :page_cache_directory - @@page_cache_extension = '.html' ## # :singleton-method: # Most Rails requests do not have an extension, such as /weblog/new. In these cases, the page caching mechanism will add one in # order to make it easy for the cached files to be picked up properly by the web server. By default, this cache extension is .html. # If you want something else, like .php or .shtml, just set Base.page_cache_extension. In cases where a request already has an # extension, such as .xml or .rss, page caching will not add an extension. This allows it to work well with RESTful apps. + @@page_cache_extension = '.html' cattr_accessor :page_cache_extension end diff --git a/actionpack/lib/action_controller/metal/compatibility.rb b/actionpack/lib/action_controller/metal/compatibility.rb index e6cea483bb..02722360f1 100644 --- a/actionpack/lib/action_controller/metal/compatibility.rb +++ b/actionpack/lib/action_controller/metal/compatibility.rb @@ -32,8 +32,6 @@ module ActionController def rescue_action(env) raise env["action_dispatch.rescue.exception"] end - - self.page_cache_directory = defined?(Rails.public_path) ? Rails.public_path : "" end # For old tests diff --git a/actionpack/lib/action_controller/railtie.rb b/actionpack/lib/action_controller/railtie.rb index 030ba4ec48..b029434004 100644 --- a/actionpack/lib/action_controller/railtie.rb +++ b/actionpack/lib/action_controller/railtie.rb @@ -44,6 +44,12 @@ module ActionController ActiveSupport.on_load(:action_controller) { self.logger ||= Rails.logger } end + initializer "action_controller.page_cache_directory" do + ActiveSupport.on_load(:action_controller) do + self.page_cache_directory = Rails.public_path + end + end + initializer "action_controller.set_configs" do |app| paths = app.config.paths ac = app.config.action_controller diff --git a/railties/lib/rails.rb b/railties/lib/rails.rb index 085b82c154..0611b2a9f5 100644 --- a/railties/lib/rails.rb +++ b/railties/lib/rails.rb @@ -92,11 +92,12 @@ module Rails end def public_path - @@public_path ||= self.root ? File.join(self.root, "public") : "public" + application && application.paths.public.to_a.first end def public_path=(path) - @@public_path = path + ActiveSupport::Deprecation.warn "Setting Rails.public_path= is deprecated. " << + "Please set paths.public = in config/application.rb instead.", caller end end end diff --git a/railties/lib/rails/application/configuration.rb b/railties/lib/rails/application/configuration.rb index f9f47ef679..7ce3494fa6 100644 --- a/railties/lib/rails/application/configuration.rb +++ b/railties/lib/rails/application/configuration.rb @@ -137,7 +137,7 @@ module Rails def default_middleware_stack ActionDispatch::MiddlewareStack.new.tap do |middleware| - middleware.use('::ActionDispatch::Static', lambda { Rails.public_path }, :if => lambda { serve_static_assets }) + middleware.use('::ActionDispatch::Static', lambda { paths.public.to_a.first }, :if => lambda { serve_static_assets }) middleware.use('::Rack::Lock', :if => lambda { !allow_concurrency }) middleware.use('::Rack::Runtime') middleware.use('::Rails::Rack::Logger') diff --git a/railties/test/application/configuration_test.rb b/railties/test/application/configuration_test.rb index 97d5f64708..8bf0f09d6b 100644 --- a/railties/test/application/configuration_test.rb +++ b/railties/test/application/configuration_test.rb @@ -184,6 +184,15 @@ module ApplicationTests end end + test "config.paths.public sets Rails.public_path" do + add_to_config <<-RUBY + config.paths.public = "somewhere" + RUBY + + require "#{app_path}/config/application" + assert_equal File.join(app_path, "somewhere"), Rails.public_path + end + def make_basic_app require "rails" require "action_controller/railtie" -- cgit v1.2.3 From 91d1012a98975979473709adf723a94057bda295 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Thu, 8 Apr 2010 13:53:18 +0200 Subject: Update rails.js to the latest one at http://github.com/rails/prototype-ujs --- .../app/templates/public/javascripts/rails.js | 73 ++++++++++++---------- 1 file changed, 41 insertions(+), 32 deletions(-) diff --git a/railties/lib/rails/generators/rails/app/templates/public/javascripts/rails.js b/railties/lib/rails/generators/rails/app/templates/public/javascripts/rails.js index 7342e1b830..c5fa02ae35 100644 --- a/railties/lib/rails/generators/rails/app/templates/public/javascripts/rails.js +++ b/railties/lib/rails/generators/rails/app/templates/public/javascripts/rails.js @@ -1,15 +1,8 @@ document.observe("dom:loaded", function() { - var authToken = $$('meta[name=csrf-token]').first().readAttribute('content'), - authParam = $$('meta[name=csrf-param]').first().readAttribute('content'), - formTemplate = '
\ - #{realmethod}\ -
', - realmethodTemplate = ''; - function handleRemote(element) { var method, url, params; - if (element.tagName.toLowerCase() == 'form') { + if (element.tagName.toLowerCase() === 'form') { method = element.readAttribute('method') || 'post'; url = element.readAttribute('action'); params = element.serialize(true); @@ -39,65 +32,81 @@ document.observe("dom:loaded", function() { element.fire("ajax:after"); } + function handleMethod(element) { + var method, url, token_name, token; + + method = element.readAttribute('data-method'); + url = element.readAttribute('href'); + csrf_param = $$('meta[name=csrf-param]').first(); + csrf_token = $$('meta[name=csrf-token]').first(); + + var form = new Element('form', { method: "POST", action: url, style: "display: none;" }); + element.parentNode.appendChild(form); + + if (method != 'post') { + var field = new Element('input', { type: 'hidden', name: '_method', value: method }); + form.appendChild(field); + } + + if (csrf_param) { + var param = csrf_param.readAttribute('content'); + var token = csrf_token.readAttribute('content'); + var field = new Element('input', { type: 'hidden', name: param, value: token }); + form.appendChild(field); + } + + form.submit(); + } + $(document.body).observe("click", function(event) { - var message = event.element().readAttribute('data-confirm'); + var message = event.findElement().readAttribute('data-confirm'); if (message && !confirm(message)) { event.stop(); return false; } - var element = event.findElement("a[data-remote=true]"); + var element = event.findElement("a[data-remote]"); if (element) { handleRemote(element); event.stop(); + return true; } var element = event.findElement("a[data-method]"); - if (element && element.readAttribute('data-remote') != 'true') { - var method = element.readAttribute('data-method'), - piggyback = method.toLowerCase() != 'post', - formHTML = formTemplate.interpolate({ - method: 'POST', - realmethod: piggyback ? realmethodTemplate.interpolate({ method: method }) : '', - action: element.readAttribute('href'), - token: authToken, - param: authParam - }); - - var form = new Element('div').update(formHTML).down().hide(); - this.insert({ bottom: form }); - - form.submit(); + if (element) { + handleMethod(element); event.stop(); + return true; } }); // TODO: I don't think submit bubbles in IE $(document.body).observe("submit", function(event) { - var message = event.element().readAttribute('data-confirm'); + var element = event.findElement(), + message = element.readAttribute('data-confirm'); if (message && !confirm(message)) { event.stop(); return false; } - var inputs = event.element().select("input[type=submit][data-disable-with]"); + var inputs = element.select("input[type=submit][data-disable-with]"); inputs.each(function(input) { input.disabled = true; input.writeAttribute('data-original-value', input.value); input.value = input.readAttribute('data-disable-with'); }); - var element = event.findElement("form[data-remote=true]"); + var element = event.findElement("form[data-remote]"); if (element) { handleRemote(element); event.stop(); } }); - $(document.body).observe("ajax:complete", function(event) { - var element = event.element(); + $(document.body).observe("ajax:after", function(event) { + var element = event.findElement(); - if (element.tagName.toLowerCase() == 'form') { + if (element.tagName.toLowerCase() === 'form') { var inputs = element.select("input[type=submit][disabled=true][data-disable-with]"); inputs.each(function(input) { input.value = input.readAttribute('data-original-value'); @@ -106,4 +115,4 @@ document.observe("dom:loaded", function() { }); } }); -}); +}); \ No newline at end of file -- cgit v1.2.3 From 2c27e3d336df0600581c01b794d90cd09efd6b09 Mon Sep 17 00:00:00 2001 From: Pratik Naik Date: Thu, 8 Apr 2010 16:49:38 +0100 Subject: Some doc updates reflecting the new query API --- .../associations/association_collection.rb | 2 +- activerecord/lib/active_record/base.rb | 68 ++++++++++------------ 2 files changed, 33 insertions(+), 37 deletions(-) diff --git a/activerecord/lib/active_record/associations/association_collection.rb b/activerecord/lib/active_record/associations/association_collection.rb index c1ec98a9c6..b808f8c306 100644 --- a/activerecord/lib/active_record/associations/association_collection.rb +++ b/activerecord/lib/active_record/associations/association_collection.rb @@ -147,7 +147,7 @@ module ActiveRecord # has_many :books # end # - # Author.find(:first).books.transaction do + # Author.first.books.transaction do # # same effect as calling Book.transaction # end def transaction(*args) diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb index f0b107255c..2df1024a1b 100755 --- a/activerecord/lib/active_record/base.rb +++ b/activerecord/lib/active_record/base.rb @@ -56,15 +56,15 @@ module ActiveRecord #:nodoc: # # class User < ActiveRecord::Base # def self.authenticate_unsafely(user_name, password) - # find(:first, :conditions => "user_name = '#{user_name}' AND password = '#{password}'") + # where("user_name = '#{user_name}' AND password = '#{password}'").first # end # # def self.authenticate_safely(user_name, password) - # find(:first, :conditions => [ "user_name = ? AND password = ?", user_name, password ]) + # where("user_name = ? AND password = ?", user_name, password).first # end # # def self.authenticate_safely_simply(user_name, password) - # find(:first, :conditions => { :user_name => user_name, :password => password }) + # where(:user_name => user_name, :password => password).first # end # end # @@ -77,30 +77,30 @@ module ActiveRecord #:nodoc: # question mark is supposed to represent. In those cases, you can resort to named bind variables instead. That's done by replacing # the question marks with symbols and supplying a hash with values for the matching symbol keys: # - # Company.find(:first, :conditions => [ + # Company.where( # "id = :id AND name = :name AND division = :division AND created_at > :accounting_date", # { :id => 3, :name => "37signals", :division => "First", :accounting_date => '2005-01-01' } - # ]) + # ).first # # Similarly, a simple hash without a statement will generate conditions based on equality with the SQL AND # operator. For instance: # - # Student.find(:all, :conditions => { :first_name => "Harvey", :status => 1 }) - # Student.find(:all, :conditions => params[:student]) + # Student.where(:first_name => "Harvey", :status => 1) + # Student.where(params[:student]) # # A range may be used in the hash to use the SQL BETWEEN operator: # - # Student.find(:all, :conditions => { :grade => 9..12 }) + # Student.where(:grade => 9..12) # # An array may be used in the hash to use the SQL IN operator: # - # Student.find(:all, :conditions => { :grade => [9,11,12] }) + # Student.where(:grade => [9,11,12]) # # When joining tables, nested hashes or keys written in the form 'table_name.column_name' can be used to qualify the table name of a # particular condition. For instance: # - # Student.find(:all, :conditions => { :schools => { :type => 'public' }}, :joins => :schools) - # Student.find(:all, :conditions => { 'schools.type' => 'public' }, :joins => :schools) + # Student.joins(:schools).where(:schools => { :type => 'public' }) + # Student.joins(:schools).where('schools.type' => 'public' ) # # == Overwriting default accessors # @@ -153,18 +153,18 @@ module ActiveRecord #:nodoc: # Dynamic attribute-based finders are a cleaner way of getting (and/or creating) objects by simple queries without turning to SQL. They work by # appending the name of an attribute to find_by_, find_last_by_, or find_all_by_, so you get finders like Person.find_by_user_name, # Person.find_all_by_last_name, and Payment.find_by_transaction_id. So instead of writing - # Person.find(:first, :conditions => ["user_name = ?", user_name]), you just do Person.find_by_user_name(user_name). - # And instead of writing Person.find(:all, :conditions => ["last_name = ?", last_name]), you just do Person.find_all_by_last_name(last_name). + # Person.where(:user_name => user_name).first, you just do Person.find_by_user_name(user_name). + # And instead of writing Person.where(:last_name => last_name).all, you just do Person.find_all_by_last_name(last_name). # # It's also possible to use multiple attributes in the same find by separating them with "_and_", so you get finders like # Person.find_by_user_name_and_password or even Payment.find_by_purchaser_and_state_and_country. So instead of writing - # Person.find(:first, :conditions => ["user_name = ? AND password = ?", user_name, password]), you just do + # Person.where(:user_name => user_name, :password => password).first, you just do # Person.find_by_user_name_and_password(user_name, password). # - # It's even possible to use all the additional parameters to find. For example, the full interface for Payment.find_all_by_amount - # is actually Payment.find_all_by_amount(amount, options). And the full interface to Person.find_by_user_name is - # actually Person.find_by_user_name(user_name, options). So you could call Payment.find_all_by_amount(50, :order => "created_on"). - # Also you may call Payment.find_last_by_amount(amount, options) returning the last record matching that amount and options. + # It's even possible to call these dynamic finder methods on relations and named scopes. For example : + # + # Payment.order("created_on").find_all_by_amount(50) + # Payment.pending.find_last_by_amount(100) # # The same dynamic finder style can be used to create the object if it doesn't already exist. This dynamic finder is called with # find_or_create_by_ and will return the object if it already exists and otherwise creates it, then returns it. Protected attributes won't be set unless they are given in a block. For example: @@ -224,7 +224,7 @@ module ActiveRecord #:nodoc: # class PriorityClient < Client; end # # When you do Firm.create(:name => "37signals"), this record will be saved in the companies table with type = "Firm". You can then - # fetch this row again using Company.find(:first, "name = '37signals'") and it will return a Firm object. + # fetch this row again using Company.where(:name => '37signals').first and it will return a Firm object. # # If you don't have a type column defined in your table, single-table inheritance won't be triggered. In that case, it'll work just # like normal subclasses with no special magic for differentiating between them or reloading the right type with find. @@ -1117,10 +1117,6 @@ module ActiveRecord #:nodoc: # It's even possible to use all the additional parameters to +find+. For example, the full interface for +find_all_by_amount+ # is actually find_all_by_amount(amount, options). # - # Also enables dynamic scopes like scoped_by_user_name(user_name) and scoped_by_user_name_and_password(user_name, password) that - # are turned into scoped(:conditions => ["user_name = ?", user_name]) and scoped(:conditions => ["user_name = ? AND password = ?", user_name, password]) - # respectively. - # # Each dynamic finder, scope or initializer/creator is also defined in the class after it is first invoked, so that future # attempts to use it do not run through method_missing. def method_missing(method_id, *arguments, &block) @@ -1196,12 +1192,12 @@ module ActiveRecord #:nodoc: protected # Scope parameters to method calls within the block. Takes a hash of method_name => parameters hash. - # method_name may be :find or :create. :find parameters may include the :conditions, :joins, - # :include, :offset, :limit, and :readonly options. :create parameters are an attributes hash. + # method_name may be :find or :create. :find parameter is Relation while + # :create parameters are an attributes hash. # # class Article < ActiveRecord::Base # def self.create_with_scope - # with_scope(:find => { :conditions => "blog_id = 1" }, :create => { :blog_id => 1 }) do + # with_scope(:find => where(:blog_id => 1), :create => { :blog_id => 1 }) do # find(1) # => SELECT * from articles WHERE blog_id = 1 AND id = 1 # a = create(1) # a.blog_id # => 1 @@ -1210,20 +1206,20 @@ module ActiveRecord #:nodoc: # end # # In nested scopings, all previous parameters are overwritten by the innermost rule, with the exception of - # :conditions, :include, and :joins options in :find, which are merged. + # where, includes, and joins operations in Relation, which are merged. # - # :joins options are uniqued so multiple scopes can join in the same table without table aliasing + # joins operations are uniqued so multiple scopes can join in the same table without table aliasing # problems. If you need to join multiple tables, but still want one of the tables to be uniqued, use the # array of strings format for your joins. # # class Article < ActiveRecord::Base # def self.find_with_scope - # with_scope(:find => { :conditions => "blog_id = 1", :limit => 1 }, :create => { :blog_id => 1 }) do - # with_scope(:find => { :limit => 10 }) do - # find(:all) # => SELECT * from articles WHERE blog_id = 1 LIMIT 10 + # with_scope(:find => where(:blog_id => 1).limit(1), :create => { :blog_id => 1 }) do + # with_scope(:find => limit(10)) do + # all # => SELECT * from articles WHERE blog_id = 1 LIMIT 10 # end - # with_scope(:find => { :conditions => "author_id = 3" }) do - # find(:all) # => SELECT * from articles WHERE blog_id = 1 AND author_id = 3 LIMIT 1 + # with_scope(:find => where(:author_id => 3)) do + # all # => SELECT * from articles WHERE blog_id = 1 AND author_id = 3 LIMIT 1 # end # end # end @@ -1233,9 +1229,9 @@ module ActiveRecord #:nodoc: # # class Article < ActiveRecord::Base # def self.find_with_exclusive_scope - # with_scope(:find => { :conditions => "blog_id = 1", :limit => 1 }) do - # with_exclusive_scope(:find => { :limit => 10 }) - # find(:all) # => SELECT * from articles LIMIT 10 + # with_scope(:find => where(:blog_id => 1).limit(1)) do + # with_exclusive_scope(:find => limit(10)) + # all # => SELECT * from articles LIMIT 10 # end # end # end -- cgit v1.2.3 From 36129f21b86db4bd69e932e586129e246c2a5ca8 Mon Sep 17 00:00:00 2001 From: Kristopher Murata Date: Thu, 8 Apr 2010 03:39:46 -0400 Subject: Dirty datetime attributes should be aware of time zone info [#3658 state:resolved] Signed-off-by: Jeremy Kemper --- .../lib/active_record/attribute_methods/dirty.rb | 6 ++ activerecord/test/cases/dirty_test.rb | 95 ++++++++++++++++++++++ 2 files changed, 101 insertions(+) diff --git a/activerecord/lib/active_record/attribute_methods/dirty.rb b/activerecord/lib/active_record/attribute_methods/dirty.rb index 435aea9b09..36f2a9777c 100644 --- a/activerecord/lib/active_record/attribute_methods/dirty.rb +++ b/activerecord/lib/active_record/attribute_methods/dirty.rb @@ -52,6 +52,8 @@ module ActiveRecord @changed_attributes.delete(attr) unless field_changed?(attr, old, value) else old = clone_attribute_value(:read_attribute, attr) + # Save Time objects as TimeWithZone if time_zone_aware_attributes == true + old = old.in_time_zone if clone_with_time_zone_conversion_attribute?(attr, old) @changed_attributes[attr] = old if field_changed?(attr, old, value) end @@ -84,6 +86,10 @@ module ActiveRecord old != value end + + def clone_with_time_zone_conversion_attribute?(attr, old) + old.class.name == "Time" && time_zone_aware_attributes && !skip_time_zone_conversion_for_attributes.include?(attr.to_sym) + end end end end diff --git a/activerecord/test/cases/dirty_test.rb b/activerecord/test/cases/dirty_test.rb index a64ccb2120..7a17ef1ee0 100644 --- a/activerecord/test/cases/dirty_test.rb +++ b/activerecord/test/cases/dirty_test.rb @@ -54,6 +54,89 @@ class DirtyTest < ActiveRecord::TestCase assert_nil pirate.catchphrase_change end + def test_time_attributes_changes_with_time_zone + in_time_zone 'Paris' do + target = Class.new(ActiveRecord::Base) + target.table_name = 'pirates' + + # New record - no changes. + pirate = target.new + assert !pirate.created_on_changed? + assert_nil pirate.created_on_change + + # Saved - no changes. + pirate.catchphrase = 'arrrr, time zone!!' + pirate.save! + assert !pirate.created_on_changed? + assert_nil pirate.created_on_change + + # Change created_on. + old_created_on = pirate.created_on + pirate.created_on = Time.now - 1.day + assert pirate.created_on_changed? + assert_kind_of ActiveSupport::TimeWithZone, pirate.created_on_was + assert_equal old_created_on, pirate.created_on_was + end + end + + def test_time_attributes_changes_without_time_zone_by_skip + in_time_zone 'Paris' do + target = Class.new(ActiveRecord::Base) + target.table_name = 'pirates' + + target.skip_time_zone_conversion_for_attributes = [:created_on] + + # New record - no changes. + pirate = target.new + assert !pirate.created_on_changed? + assert_nil pirate.created_on_change + + # Saved - no changes. + pirate.catchphrase = 'arrrr, time zone!!' + pirate.save! + assert !pirate.created_on_changed? + assert_nil pirate.created_on_change + + # Change created_on. + old_created_on = pirate.created_on + pirate.created_on = Time.now + 1.day + assert pirate.created_on_changed? + # kind_of does not work because + # ActiveSupport::TimeWithZone.name == 'Time' + assert_equal Time, pirate.created_on_was.class + assert_equal old_created_on, pirate.created_on_was + end + end + + def test_time_attributes_changes_without_time_zone + + target = Class.new(ActiveRecord::Base) + target.table_name = 'pirates' + + target.time_zone_aware_attributes = false + + # New record - no changes. + pirate = target.new + assert !pirate.created_on_changed? + assert_nil pirate.created_on_change + + # Saved - no changes. + pirate.catchphrase = 'arrrr, time zone!!' + pirate.save! + assert !pirate.created_on_changed? + assert_nil pirate.created_on_change + + # Change created_on. + old_created_on = pirate.created_on + pirate.created_on = Time.now + 1.day + assert pirate.created_on_changed? + # kind_of does not work because + # ActiveSupport::TimeWithZone.name == 'Time' + assert_equal Time, pirate.created_on_was.class + assert_equal old_created_on, pirate.created_on_was + end + + def test_aliased_attribute_changes # the actual attribute here is name, title is an # alias setup via alias_attribute @@ -406,4 +489,16 @@ class DirtyTest < ActiveRecord::TestCase assert_equal %w(parrot_id), pirate.changed assert_nil pirate.parrot_id_was end + + def in_time_zone(zone) + old_zone = Time.zone + old_tz = ActiveRecord::Base.time_zone_aware_attributes + + Time.zone = zone ? ActiveSupport::TimeZone[zone] : nil + ActiveRecord::Base.time_zone_aware_attributes = !zone.nil? + yield + ensure + Time.zone = old_zone + ActiveRecord::Base.time_zone_aware_attributes = old_tz + end end -- cgit v1.2.3 From e7f0d37c91c91a6b2f2a1232c1a670e59165dc19 Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Thu, 8 Apr 2010 11:38:25 -0700 Subject: Remove superfluous condition --- actionpack/lib/action_view/helpers/form_tag_helper.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/actionpack/lib/action_view/helpers/form_tag_helper.rb b/actionpack/lib/action_view/helpers/form_tag_helper.rb index 081c317e0c..67b4e842b1 100644 --- a/actionpack/lib/action_view/helpers/form_tag_helper.rb +++ b/actionpack/lib/action_view/helpers/form_tag_helper.rb @@ -386,7 +386,7 @@ module ActionView options.stringify_keys! if disable_with = options.delete("disable_with") - options["data-disable-with"] = disable_with if disable_with + options["data-disable-with"] = disable_with end if confirm = options.delete("confirm") -- cgit v1.2.3 From 00ee9b33698715fb9265a227715a443e21762ea1 Mon Sep 17 00:00:00 2001 From: David Heinemeier Hansson Date: Thu, 8 Apr 2010 11:46:56 -0700 Subject: Revert "adds #favicon_link_tag and #apple_touch_icon_link_tag" -- these tags are too specific. This reverts commit 6891f46d10957f21f200fc4dc2b6076ff411b1da, ec8610cfdc32d0fe816fb22405e00ef1b6c90d73, and d18ff1b7efd96e7c08bc1a15137735be45f87e07. --- actionpack/CHANGELOG | 2 - .../lib/action_view/helpers/asset_tag_helper.rb | 44 ---------------------- actionpack/test/template/asset_tag_helper_test.rb | 20 ---------- 3 files changed, 66 deletions(-) diff --git a/actionpack/CHANGELOG b/actionpack/CHANGELOG index 3c765933ef..84481d0194 100644 --- a/actionpack/CHANGELOG +++ b/actionpack/CHANGELOG @@ -1,7 +1,5 @@ *Rails 3.0.0 [Edge] (pending)* -* New helpers #favicon_link_tag and #apple_touch_icon_link_tag [fxn] - * Added all the new HTML5 form types as individual form tag methods (search, url, number, etc) #3646 [Stephen Celis] * Changed the object used in routing constraints to be an instance of diff --git a/actionpack/lib/action_view/helpers/asset_tag_helper.rb b/actionpack/lib/action_view/helpers/asset_tag_helper.rb index 47abf1e41c..e4ec17467e 100644 --- a/actionpack/lib/action_view/helpers/asset_tag_helper.rb +++ b/actionpack/lib/action_view/helpers/asset_tag_helper.rb @@ -501,50 +501,6 @@ module ActionView end end - # Returns a link tag for a favicon. - # - # <%= favicon_link_tag %> - # - # generates - # - # - # - # You can specify a different icon file in the first argument: - # - # <%= favicon_link_tag 'favicon.ico' %> - # - # That's passed to +image_path+ as is, so the example above would render - # - # - # - # The helper accepts an additional options hash where you can override "rel" and "type". - def favicon_link_tag(source='/favicon.ico', options={}) - tag('link', { - :rel => 'shortcut icon', - :type => 'image/vnd.microsoft.icon', - :href => image_path(source) - }.merge(options.symbolize_keys)) - end - - # Returns a link tag for an icon targetted at iPod Touch, iPhone, and iPad. - # - # <%= apple_touch_icon_link_tag %> - # - # generates - # - # - # - # You can specify a different icon file: - # - # <%= apple_touch_icon_link_tag "my_site.png" %> - # - # That's passed to +image_path+ as is, so the example above would render - # - # - def apple_touch_icon_link_tag(source='/apple-touch-icon.png') - tag('link', :rel => 'apple-touch-icon', :href => image_path(source)) - end - # Computes the path to an image asset in the public images directory. # Full paths from the document root will be passed through. # Used internally by +image_tag+ to build the image path. diff --git a/actionpack/test/template/asset_tag_helper_test.rb b/actionpack/test/template/asset_tag_helper_test.rb index 10ee9c7881..223a430f92 100644 --- a/actionpack/test/template/asset_tag_helper_test.rb +++ b/actionpack/test/template/asset_tag_helper_test.rb @@ -157,18 +157,6 @@ class AssetTagHelperTest < ActionView::TestCase %(image_tag("mouse.png", :mouseover => image_path("mouse_over.png"))) => %(Mouse) } - FaviconLinkToTag = { - %(favicon_link_tag) => %(), - %(favicon_link_tag 'favicon.ico') => %(), - %(favicon_link_tag 'favicon.ico', :rel => 'foo') => %(), - %(favicon_link_tag 'favicon.ico', :rel => 'foo', :type => 'bar') => %() - } - - AppleTouchIconLinkToTag = { - %(apple_touch_icon_link_tag) => %(), - %(apple_touch_icon_link_tag 'my_site.png') => %() - } - VideoPathToTag = { %(video_path("xml")) => %(/videos/xml), %(video_path("xml.ogg")) => %(/videos/xml.ogg), @@ -343,14 +331,6 @@ class AssetTagHelperTest < ActionView::TestCase ImageLinkToTag.each { |method, tag| assert_dom_equal(tag, eval(method)) } end - def test_favicon_link_tag - FaviconLinkToTag.each { |method, tag| assert_dom_equal(tag, eval(method)) } - end - - def test_apple_touch_link_tag - AppleTouchIconLinkToTag.each { |method, tag| assert_dom_equal(tag, eval(method)) } - end - def test_image_tag_windows_behaviour old_asset_id, ENV["RAILS_ASSET_ID"] = ENV["RAILS_ASSET_ID"], "1" # This simulates the behaviour of File#exist? on windows when testing a file ending in "." -- cgit v1.2.3 From 0e44eb35d6e1b99ed624aaec839a03c12147f123 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Thu, 8 Apr 2010 12:01:15 -0700 Subject: fisting stack trace [#4349 state:resolved] Signed-off-by: Jeremy Kemper --- activesupport/lib/active_support/core_ext/module/delegation.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/activesupport/lib/active_support/core_ext/module/delegation.rb b/activesupport/lib/active_support/core_ext/module/delegation.rb index b73f4c2b59..40a1866428 100644 --- a/activesupport/lib/active_support/core_ext/module/delegation.rb +++ b/activesupport/lib/active_support/core_ext/module/delegation.rb @@ -126,7 +126,7 @@ class Module %(raise "#{self}##{prefix}#{method} delegated to #{to}.#{method}, but #{to} is nil: \#{self.inspect}") end - module_eval(<<-EOS, file, line) + module_eval(<<-EOS, file, line - 5) if instance_methods(false).map(&:to_s).include?("#{prefix}#{method}") remove_possible_method("#{prefix}#{method}") end -- cgit v1.2.3 From 5f808b865cc0bbb10af7733cc0c4da3add572a95 Mon Sep 17 00:00:00 2001 From: David Heinemeier Hansson Date: Thu, 8 Apr 2010 12:17:46 -0700 Subject: Consistently use lowercase instead of camelCase for all JS class names in Rails --- .../lib/action_view/helpers/form_tag_helper.rb | 20 ++++++++++---------- actionpack/lib/action_view/helpers/url_helper.rb | 10 +++++----- actionpack/test/template/url_helper_test.rb | 20 ++++++++++---------- 3 files changed, 25 insertions(+), 25 deletions(-) diff --git a/actionpack/lib/action_view/helpers/form_tag_helper.rb b/actionpack/lib/action_view/helpers/form_tag_helper.rb index 67b4e842b1..388d6813ef 100644 --- a/actionpack/lib/action_view/helpers/form_tag_helper.rb +++ b/actionpack/lib/action_view/helpers/form_tag_helper.rb @@ -199,8 +199,8 @@ module ActionView # file_field_tag 'attachment' # # => # - # file_field_tag 'avatar', :class => 'profile-input' - # # => + # file_field_tag 'avatar', :class => 'profile_input' + # # => # # file_field_tag 'picture', :disabled => true # # => @@ -244,8 +244,8 @@ module ActionView # password_field_tag 'confirm_pass', nil, :disabled => true # # => # - # password_field_tag 'pin', '1234', :maxlength => 4, :size => 6, :class => "pin-input" - # # => + # password_field_tag 'pin', '1234', :maxlength => 4, :size => 6, :class => "pin_input" + # # => def password_field_tag(name = "password", value = nil, options = {}) text_field_tag(name, value, options.update("type" => "password")) end @@ -374,8 +374,8 @@ module ActionView # submit_tag nil, :class => "form_submit" # # => # - # submit_tag "Edit", :disable_with => "Editing...", :class => "edit-button" - # # => "Editing...", :class => "edit_button" + # # => # # submit_tag "Save", :confirm => "Are you sure?" @@ -414,11 +414,11 @@ module ActionView # image_submit_tag("purchase.png", :disabled => true) # # => # - # image_submit_tag("search.png", :class => 'search-button') - # # => + # image_submit_tag("search.png", :class => 'search_button') + # # => # - # image_submit_tag("agree.png", :disabled => true, :class => "agree-disagree-button") - # # => + # image_submit_tag("agree.png", :disabled => true, :class => "agree_disagree_button") + # # => def image_submit_tag(source, options = {}) options.stringify_keys! diff --git a/actionpack/lib/action_view/helpers/url_helper.rb b/actionpack/lib/action_view/helpers/url_helper.rb index 5925faf810..0b748d700b 100644 --- a/actionpack/lib/action_view/helpers/url_helper.rb +++ b/actionpack/lib/action_view/helpers/url_helper.rb @@ -265,7 +265,7 @@ module ActionView # using the +link_to+ method with the :method modifier as described in # the +link_to+ documentation. # - # The generated form element has a class name of button-to + # The generated form element has a class name of button_to # to allow styling of the form itself and its children. You can control # the form submission and input element behavior using +html_options+. # This method accepts the :method and :confirm modifiers @@ -289,14 +289,14 @@ module ActionView # # ==== Examples # <%= button_to "New", :action => "new" %> - # # => "
+ # # => " # #
# #
" # # # <%= button_to "Delete Image", { :action => "delete", :id => @image.id }, # :confirm => "Are you sure?", :method => :delete %> - # # => "
+ # # => " # #
# # # # @@ -306,7 +306,7 @@ module ActionView # # <%= button_to('Destroy', 'http://www.example.com', :confirm => 'Are you sure?', # :method => "delete", :remote => true, :disable_with => 'loading...') %> - # # => " + # # => " # #
# # # # @@ -338,7 +338,7 @@ module ActionView html_options.merge!("type" => "submit", "value" => name) - ("
" + + ("
" + method_tag + tag("input", html_options) + request_token_tag + "
").html_safe end diff --git a/actionpack/test/template/url_helper_test.rb b/actionpack/test/template/url_helper_test.rb index 35e73fbf1e..de63030714 100644 --- a/actionpack/test/template/url_helper_test.rb +++ b/actionpack/test/template/url_helper_test.rb @@ -74,56 +74,56 @@ class UrlHelperTest < ActiveSupport::TestCase # todo: missing test cases def test_button_to_with_straight_url - assert_dom_equal "
", button_to("Hello", "http://www.example.com") + assert_dom_equal "
", button_to("Hello", "http://www.example.com") end def test_button_to_with_query - assert_dom_equal "
", button_to("Hello", "http://www.example.com/q1=v1&q2=v2") + assert_dom_equal "
", button_to("Hello", "http://www.example.com/q1=v1&q2=v2") end def test_button_to_with_escaped_query - assert_dom_equal "
", button_to("Hello", "http://www.example.com/q1=v1&q2=v2") + assert_dom_equal "
", button_to("Hello", "http://www.example.com/q1=v1&q2=v2") end def test_button_to_with_query_and_no_name - assert_dom_equal "
", button_to(nil, "http://www.example.com?q1=v1&q2=v2") + assert_dom_equal "
", button_to(nil, "http://www.example.com?q1=v1&q2=v2") end def test_button_to_with_javascript_confirm assert_dom_equal( - "
", + "
", button_to("Hello", "http://www.example.com", :confirm => "Are you sure?") ) end def test_button_to_with_remote_and_javascript_confirm assert_dom_equal( - "
", + "
", button_to("Hello", "http://www.example.com", :remote => true, :confirm => "Are you sure?") ) end def test_button_to_enabled_disabled assert_dom_equal( - "
", + "
", button_to("Hello", "http://www.example.com", :disabled => false) ) assert_dom_equal( - "
", + "
", button_to("Hello", "http://www.example.com", :disabled => true) ) end def test_button_to_with_method_delete assert_dom_equal( - "
", + "
", button_to("Hello", "http://www.example.com", :method => :delete) ) end def test_button_to_with_method_get assert_dom_equal( - "
", + "
", button_to("Hello", "http://www.example.com", :method => :get) ) end -- cgit v1.2.3 From 82514c2897a43ab58239af1fb24f8f0de2a0d989 Mon Sep 17 00:00:00 2001 From: Michael Koziarski Date: Fri, 9 Apr 2010 11:28:19 +1200 Subject: Add accessors for request and response so tests don't have to mess with internal ivars --- actionpack/lib/action_controller/test_case.rb | 2 ++ actionpack/test/controller/test_test.rb | 6 ++++++ 2 files changed, 8 insertions(+) diff --git a/actionpack/lib/action_controller/test_case.rb b/actionpack/lib/action_controller/test_case.rb index 2d4cf2fafb..dfd8e75bcc 100644 --- a/actionpack/lib/action_controller/test_case.rb +++ b/actionpack/lib/action_controller/test_case.rb @@ -284,6 +284,8 @@ module ActionController include ActionDispatch::TestProcess include ActionController::TemplateAssertions + attr_reader :response, :request + # Executes a request simulating GET HTTP method and set/volley the response def get(action, parameters = nil, session = nil, flash = nil) process(action, parameters, session, flash, "GET") diff --git a/actionpack/test/controller/test_test.rb b/actionpack/test/controller/test_test.rb index 8910454b8b..6f1ce2fef7 100644 --- a/actionpack/test/controller/test_test.rb +++ b/actionpack/test/controller/test_test.rb @@ -189,6 +189,12 @@ XML assert_equal Hash.new, @request.session.to_hash end + def test_response_and_request_have_nice_accessors + process :no_op + assert_equal @response, response + assert_equal @request, request + end + def test_process_with_request_uri_with_no_params process :test_uri assert_equal "/test_test/test/test_uri", @response.body -- cgit v1.2.3 From 1e3dce08e11bd11e7d774512ea599166c4c45378 Mon Sep 17 00:00:00 2001 From: Michael Koziarski Date: Fri, 9 Apr 2010 11:29:53 +1200 Subject: Revert "When creating database with rake, create schemas in schema_search_path if it doesn't exist." This reverts commit 6c2a0675f11a9b5b8e88ed7dbccd65cb51be8029. Reverting because it breaks the ability to run tests using a non-superuser. Conflicts: activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb activerecord/lib/active_record/railties/databases.rake --- .../connection_adapters/postgresql_adapter.rb | 21 --------------------- .../lib/active_record/railties/databases.rake | 8 +------- .../test/cases/active_schema_test_postgresql.rb | 7 ------- activerecord/test/cases/adapter_test.rb | 6 ------ 4 files changed, 1 insertion(+), 41 deletions(-) diff --git a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb index 2395a744a3..68ee88bba4 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb @@ -658,27 +658,6 @@ module ActiveRecord end end - # Creates a schema for the given user - # - # Example: - # create_schema('products', 'postgres') - def create_schema(schema_name, pg_username) - execute("CREATE SCHEMA \"#{schema_name}\" AUTHORIZATION \"#{pg_username}\"") - end - - # Drops a schema - # - # Example: - # drop_schema('products') - def drop_schema(schema_name) - execute("DROP SCHEMA \"#{schema_name}\"") - end - - # Returns an array of all schemas in the database - def all_schemas - query('SELECT schema_name FROM information_schema.schemata').flatten - end - # Returns the list of all tables in the schema search path or a specified schema. def tables(name = nil) query(<<-SQL, name).map { |row| row[0] } diff --git a/activerecord/lib/active_record/railties/databases.rake b/activerecord/lib/active_record/railties/databases.rake index a107befef3..0229793a9a 100644 --- a/activerecord/lib/active_record/railties/databases.rake +++ b/activerecord/lib/active_record/railties/databases.rake @@ -84,15 +84,9 @@ namespace :db do end end when 'postgresql' - @encoding = config['encoding'] || ENV['CHARSET'] || 'utf8' - schema_search_path = config['schema_search_path'] || 'public' - first_in_schema_search_path = schema_search_path.split(',').first.strip + @encoding = config[:encoding] || ENV['CHARSET'] || 'utf8' begin ActiveRecord::Base.establish_connection(config.merge('database' => 'postgres', 'schema_search_path' => 'public')) - unless ActiveRecord::Base.connection.all_schemas.include?(first_in_schema_search_path) - ActiveRecord::Base.connection.create_schema(first_in_schema_search_path, config['username']) - $stderr.puts "Schema #{first_in_schema_search_path} has been created." - end ActiveRecord::Base.connection.create_database(config['database'], config.merge('encoding' => @encoding)) ActiveRecord::Base.establish_connection(config) rescue diff --git a/activerecord/test/cases/active_schema_test_postgresql.rb b/activerecord/test/cases/active_schema_test_postgresql.rb index 67c662d694..af80f724f2 100644 --- a/activerecord/test/cases/active_schema_test_postgresql.rb +++ b/activerecord/test/cases/active_schema_test_postgresql.rb @@ -17,13 +17,6 @@ class PostgresqlActiveSchemaTest < Test::Unit::TestCase assert_equal %(CREATE DATABASE "aimonetti" ENCODING = 'latin1'), create_database(:aimonetti, :encoding => :latin1) end - def test_create_schema - assert_equal %(CREATE SCHEMA "rizwan" AUTHORIZATION "postgres"), create_schema(:rizwan, :postgres) - end - - def test_drop_schema - assert_equal %(DROP SCHEMA "rizwan"), drop_schema(:rizwan) - end private def method_missing(method_symbol, *arguments) ActiveRecord::Base.connection.send(method_symbol, *arguments) diff --git a/activerecord/test/cases/adapter_test.rb b/activerecord/test/cases/adapter_test.rb index 9f78ae008c..9b28766405 100644 --- a/activerecord/test/cases/adapter_test.rb +++ b/activerecord/test/cases/adapter_test.rb @@ -81,12 +81,6 @@ class AdapterTest < ActiveRecord::TestCase def test_encoding assert_not_nil @connection.encoding end - - def test_all_schemas - @connection.create_schema(:test_schema, :postgres) - assert @connection.all_schemas.include?('test_schema') - @connection.drop_schema(:test_schema) - end end def test_table_alias -- cgit v1.2.3 From 99d54599215c2a8cea7e57f609e8e578043d71b2 Mon Sep 17 00:00:00 2001 From: Carl Lerche Date: Thu, 8 Apr 2010 18:11:26 -0700 Subject: Fixed that default locale templates should be used if the current locale template is missing [DHH] --- actionpack/CHANGELOG | 2 ++ actionpack/lib/action_view/lookup_context.rb | 4 ++-- .../test/controller/localized_templates_test.rb | 22 ++++++++++++++++++++++ .../test/fixtures/localized/hello_world.de.html | 1 + .../test/fixtures/localized/hello_world.en.html | 1 + 5 files changed, 28 insertions(+), 2 deletions(-) create mode 100644 actionpack/test/controller/localized_templates_test.rb create mode 100644 actionpack/test/fixtures/localized/hello_world.de.html create mode 100644 actionpack/test/fixtures/localized/hello_world.en.html diff --git a/actionpack/CHANGELOG b/actionpack/CHANGELOG index 84481d0194..49ca36cc26 100644 --- a/actionpack/CHANGELOG +++ b/actionpack/CHANGELOG @@ -1,5 +1,7 @@ *Rails 3.0.0 [Edge] (pending)* +* Fixed that default locale templates should be used if the current locale template is missing [DHH] + * Added all the new HTML5 form types as individual form tag methods (search, url, number, etc) #3646 [Stephen Celis] * Changed the object used in routing constraints to be an instance of diff --git a/actionpack/lib/action_view/lookup_context.rb b/actionpack/lib/action_view/lookup_context.rb index 9b59aac0eb..6e61d85dcc 100644 --- a/actionpack/lib/action_view/lookup_context.rb +++ b/actionpack/lib/action_view/lookup_context.rb @@ -38,7 +38,7 @@ module ActionView end register_detail(:formats) { Mime::SET.symbols } - register_detail(:locale) { [I18n.locale] } + register_detail(:locale) { [I18n.locale, I18n.default_locale] } class DetailsKey #:nodoc: alias :eql? :equal? @@ -160,7 +160,7 @@ module ActionView config = I18n.config.respond_to?(:i18n_config) ? I18n.config.i18n_config : I18n.config config.locale = value end - super(I18n.locale) + super(_locale_defaults) end # Update the details keys by merging the given hash into the current diff --git a/actionpack/test/controller/localized_templates_test.rb b/actionpack/test/controller/localized_templates_test.rb new file mode 100644 index 0000000000..41ff2f3809 --- /dev/null +++ b/actionpack/test/controller/localized_templates_test.rb @@ -0,0 +1,22 @@ +require 'abstract_unit' + +class LocalizedController < ActionController::Base + def hello_world + end +end + +class LocalizedTemplatesTest < ActionController::TestCase + tests LocalizedController + + def test_localized_template_is_used + I18n.locale = :de + get :hello_world + assert_equal "Gutten Tag", @response.body + end + + def test_default_locale_template_is_used_when_locale_is_missing + I18n.locale = :dk + get :hello_world + assert_equal "Hello World", @response.body + end +end \ No newline at end of file diff --git a/actionpack/test/fixtures/localized/hello_world.de.html b/actionpack/test/fixtures/localized/hello_world.de.html new file mode 100644 index 0000000000..4727d7a7e0 --- /dev/null +++ b/actionpack/test/fixtures/localized/hello_world.de.html @@ -0,0 +1 @@ +Gutten Tag \ No newline at end of file diff --git a/actionpack/test/fixtures/localized/hello_world.en.html b/actionpack/test/fixtures/localized/hello_world.en.html new file mode 100644 index 0000000000..5e1c309dae --- /dev/null +++ b/actionpack/test/fixtures/localized/hello_world.en.html @@ -0,0 +1 @@ +Hello World \ No newline at end of file -- cgit v1.2.3 From fd7202a75653570693c6fe423faad96019fe0ea1 Mon Sep 17 00:00:00 2001 From: Xavier Noria Date: Thu, 8 Apr 2010 18:11:08 -0700 Subject: adds #favicon_link_tag back, rdoc explains why it is useful, and how to get a link for Mobile Safari with it --- .../lib/action_view/helpers/asset_tag_helper.rb | 34 ++++++++++++++++++++++ actionpack/test/template/asset_tag_helper_test.rb | 12 ++++++++ 2 files changed, 46 insertions(+) diff --git a/actionpack/lib/action_view/helpers/asset_tag_helper.rb b/actionpack/lib/action_view/helpers/asset_tag_helper.rb index e4ec17467e..85401ad561 100644 --- a/actionpack/lib/action_view/helpers/asset_tag_helper.rb +++ b/actionpack/lib/action_view/helpers/asset_tag_helper.rb @@ -501,6 +501,40 @@ module ActionView end end + # Web browsers cache favicons. If you just throw a favicon.ico into the document + # root of your application and it changes later, clients that have it in their cache + # won't see the update. Using this helper prevents that because it appends an asset ID: + # + # <%= favicon_link_tag %> + # + # generates + # + # + # + # You may specify a different file in the first argument: + # + # <%= favicon_link_tag 'favicon.ico' %> + # + # That's passed to +image_path+ as is, so it gives + # + # + # + # The helper accepts an additional options hash where you can override "rel" and "type". + # + # For example, Mobile Safari looks for a different LINK tag, pointing to an image that + # will be used if you add the page to the home screen of an iPod Touch, iPhone, or iPad. + # The following call would generate such a tag: + # + # <%= favicon_link_tag 'mb-icon.png', :rel => 'apple-touch-icon', :type => 'image/png' %> + # + def favicon_link_tag(source='/favicon.ico', options={}) + tag('link', { + :rel => 'shortcut icon', + :type => 'image/vnd.microsoft.icon', + :href => image_path(source) + }.merge(options.symbolize_keys)) + end + # Computes the path to an image asset in the public images directory. # Full paths from the document root will be passed through. # Used internally by +image_tag+ to build the image path. diff --git a/actionpack/test/template/asset_tag_helper_test.rb b/actionpack/test/template/asset_tag_helper_test.rb index 223a430f92..124bf734ac 100644 --- a/actionpack/test/template/asset_tag_helper_test.rb +++ b/actionpack/test/template/asset_tag_helper_test.rb @@ -157,6 +157,14 @@ class AssetTagHelperTest < ActionView::TestCase %(image_tag("mouse.png", :mouseover => image_path("mouse_over.png"))) => %(Mouse) } + FaviconLinkToTag = { + %(favicon_link_tag) => %(), + %(favicon_link_tag 'favicon.ico') => %(), + %(favicon_link_tag 'favicon.ico', :rel => 'foo') => %(), + %(favicon_link_tag 'favicon.ico', :rel => 'foo', :type => 'bar') => %(), + %(favicon_link_tag 'mb-icon.png', :rel => 'apple-touch-icon', :type => 'image/png') => %() + } + VideoPathToTag = { %(video_path("xml")) => %(/videos/xml), %(video_path("xml.ogg")) => %(/videos/xml.ogg), @@ -331,6 +339,10 @@ class AssetTagHelperTest < ActionView::TestCase ImageLinkToTag.each { |method, tag| assert_dom_equal(tag, eval(method)) } end + def test_favicon_link_tag + FaviconLinkToTag.each { |method, tag| assert_dom_equal(tag, eval(method)) } + end + def test_image_tag_windows_behaviour old_asset_id, ENV["RAILS_ASSET_ID"] = ENV["RAILS_ASSET_ID"], "1" # This simulates the behaviour of File#exist? on windows when testing a file ending in "." -- cgit v1.2.3 From bd2bf5390d892a1c11bcaa2143f557b82611015e Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Thu, 8 Apr 2010 19:27:22 -0700 Subject: Expect an incompatible encoding exception when a template doesn't have a magic comment and its source encoding doesn't match the default external encoding --- actionpack/test/fixtures/test/utf8.html.erb | 2 +- actionpack/test/fixtures/test/utf8_magic.html.erb | 2 +- actionpack/test/template/render_test.rb | 61 +++++++++++++---------- 3 files changed, 38 insertions(+), 27 deletions(-) diff --git a/actionpack/test/fixtures/test/utf8.html.erb b/actionpack/test/fixtures/test/utf8.html.erb index 14fe12debc..551c24e354 100644 --- a/actionpack/test/fixtures/test/utf8.html.erb +++ b/actionpack/test/fixtures/test/utf8.html.erb @@ -1,4 +1,4 @@ -Русский текст +Русский <%= "текст" %> <%= "日".encoding %> <%= @output_buffer.encoding %> <%= __ENCODING__ %> diff --git a/actionpack/test/fixtures/test/utf8_magic.html.erb b/actionpack/test/fixtures/test/utf8_magic.html.erb index 58cd03b439..e2aa85e66a 100644 --- a/actionpack/test/fixtures/test/utf8_magic.html.erb +++ b/actionpack/test/fixtures/test/utf8_magic.html.erb @@ -1,5 +1,5 @@ <%# encoding: utf-8 -%> -Русский текст +Русский <%= "текст" %> <%= "日".encoding %> <%= @output_buffer.encoding %> <%= __ENCODING__ %> diff --git a/actionpack/test/template/render_test.rb b/actionpack/test/template/render_test.rb index 5f33c933db..647c673902 100644 --- a/actionpack/test/template/render_test.rb +++ b/actionpack/test/template/render_test.rb @@ -245,31 +245,6 @@ module RenderTestCases assert_equal %(\ntitle\n\n), @view.render(:file => "test/layout_render_file.erb") end - - if '1.9'.respond_to?(:force_encoding) - def test_render_utf8_template_with_magic_comment - with_external_encoding Encoding::ASCII_8BIT do - result = @view.render(:file => "test/utf8_magic.html.erb", :layouts => "layouts/yield") - assert_equal "Русский текст\nUTF-8\nUTF-8\nUTF-8\n", result - assert_equal Encoding::UTF_8, result.encoding - end - end - - def test_render_utf8_template_with_default_external_encoding - with_external_encoding Encoding::UTF_8 do - result = @view.render(:file => "test/utf8.html.erb", :layouts => "layouts/yield") - assert_equal "Русский текст\nUTF-8\nUTF-8\nUTF-8\n", result - assert_equal Encoding::UTF_8, result.encoding - end - end - - def with_external_encoding(encoding) - old, Encoding.default_external = Encoding.default_external, encoding - yield - ensure - Encoding.default_external = old - end - end end class CachedViewRenderTest < ActiveSupport::TestCase @@ -302,4 +277,40 @@ class LazyViewRenderTest < ActiveSupport::TestCase def teardown GC.start end + + if '1.9'.respond_to?(:force_encoding) + def test_render_utf8_template_with_magic_comment + with_external_encoding Encoding::ASCII_8BIT do + result = @view.render(:file => "test/utf8_magic.html.erb", :layouts => "layouts/yield") + assert_equal Encoding::UTF_8, result.encoding + assert_equal "Русский текст\nUTF-8\nUTF-8\nUTF-8\n", result + end + end + + def test_render_utf8_template_with_default_external_encoding + with_external_encoding Encoding::UTF_8 do + result = @view.render(:file => "test/utf8.html.erb", :layouts => "layouts/yield") + assert_equal Encoding::UTF_8, result.encoding + assert_equal "Русский текст\nUTF-8\nUTF-8\nUTF-8\n", result + end + end + + def test_render_utf8_template_with_incompatible_external_encoding + with_external_encoding Encoding::SJIS do + begin + result = @view.render(:file => "test/utf8.html.erb", :layouts => "layouts/yield") + flunk 'Should have raised incompatible encoding error' + rescue ActionView::Template::Error => error + assert_match 'invalid byte sequence in Shift_JIS', error.original_exception.message + end + end + end + + def with_external_encoding(encoding) + old, Encoding.default_external = Encoding.default_external, encoding + yield + ensure + Encoding.default_external = old + end + end end -- cgit v1.2.3 From 4691c696b0cda985c5d868312555cd538328a99c Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Thu, 8 Apr 2010 20:22:07 -0700 Subject: Expect an incompatible encoding exception when a template with a magic comment renders a partial without one and its source encoding doesn't match the default external encoding --- actionpack/test/fixtures/test/_utf8_partial.html.erb | 1 + .../test/fixtures/test/_utf8_partial_magic.html.erb | 2 ++ actionpack/test/fixtures/test/utf8.html.erb | 2 +- actionpack/test/fixtures/test/utf8_magic.html.erb | 2 +- .../fixtures/test/utf8_magic_with_bare_partial.html.erb | 5 +++++ actionpack/test/template/render_test.rb | 15 +++++++++++++-- 6 files changed, 23 insertions(+), 4 deletions(-) create mode 100644 actionpack/test/fixtures/test/_utf8_partial.html.erb create mode 100644 actionpack/test/fixtures/test/_utf8_partial_magic.html.erb create mode 100644 actionpack/test/fixtures/test/utf8_magic_with_bare_partial.html.erb diff --git a/actionpack/test/fixtures/test/_utf8_partial.html.erb b/actionpack/test/fixtures/test/_utf8_partial.html.erb new file mode 100644 index 0000000000..8d717fd427 --- /dev/null +++ b/actionpack/test/fixtures/test/_utf8_partial.html.erb @@ -0,0 +1 @@ +<%= "текст" %> diff --git a/actionpack/test/fixtures/test/_utf8_partial_magic.html.erb b/actionpack/test/fixtures/test/_utf8_partial_magic.html.erb new file mode 100644 index 0000000000..4e2224610a --- /dev/null +++ b/actionpack/test/fixtures/test/_utf8_partial_magic.html.erb @@ -0,0 +1,2 @@ +<%# encoding: utf-8 -%> +<%= "текст" %> diff --git a/actionpack/test/fixtures/test/utf8.html.erb b/actionpack/test/fixtures/test/utf8.html.erb index 551c24e354..ac98c2f012 100644 --- a/actionpack/test/fixtures/test/utf8.html.erb +++ b/actionpack/test/fixtures/test/utf8.html.erb @@ -1,4 +1,4 @@ -Русский <%= "текст" %> +Русский <%= render :partial => 'test/utf8_partial' %> <%= "日".encoding %> <%= @output_buffer.encoding %> <%= __ENCODING__ %> diff --git a/actionpack/test/fixtures/test/utf8_magic.html.erb b/actionpack/test/fixtures/test/utf8_magic.html.erb index e2aa85e66a..257279c29f 100644 --- a/actionpack/test/fixtures/test/utf8_magic.html.erb +++ b/actionpack/test/fixtures/test/utf8_magic.html.erb @@ -1,5 +1,5 @@ <%# encoding: utf-8 -%> -Русский <%= "текст" %> +Русский <%= render :partial => 'test/utf8_partial_magic' %> <%= "日".encoding %> <%= @output_buffer.encoding %> <%= __ENCODING__ %> diff --git a/actionpack/test/fixtures/test/utf8_magic_with_bare_partial.html.erb b/actionpack/test/fixtures/test/utf8_magic_with_bare_partial.html.erb new file mode 100644 index 0000000000..cb22692f9a --- /dev/null +++ b/actionpack/test/fixtures/test/utf8_magic_with_bare_partial.html.erb @@ -0,0 +1,5 @@ +<%# encoding: utf-8 -%> +Русский <%= render :partial => 'test/utf8_partial' %> +<%= "日".encoding %> +<%= @output_buffer.encoding %> +<%= __ENCODING__ %> diff --git a/actionpack/test/template/render_test.rb b/actionpack/test/template/render_test.rb index 647c673902..c9a50da418 100644 --- a/actionpack/test/template/render_test.rb +++ b/actionpack/test/template/render_test.rb @@ -283,7 +283,7 @@ class LazyViewRenderTest < ActiveSupport::TestCase with_external_encoding Encoding::ASCII_8BIT do result = @view.render(:file => "test/utf8_magic.html.erb", :layouts => "layouts/yield") assert_equal Encoding::UTF_8, result.encoding - assert_equal "Русский текст\nUTF-8\nUTF-8\nUTF-8\n", result + assert_equal "Русский текст\n\nUTF-8\nUTF-8\nUTF-8\n", result end end @@ -291,7 +291,7 @@ class LazyViewRenderTest < ActiveSupport::TestCase with_external_encoding Encoding::UTF_8 do result = @view.render(:file => "test/utf8.html.erb", :layouts => "layouts/yield") assert_equal Encoding::UTF_8, result.encoding - assert_equal "Русский текст\nUTF-8\nUTF-8\nUTF-8\n", result + assert_equal "Русский текст\n\nUTF-8\nUTF-8\nUTF-8\n", result end end @@ -306,6 +306,17 @@ class LazyViewRenderTest < ActiveSupport::TestCase end end + def test_render_utf8_template_with_partial_with_incompatible_encoding + with_external_encoding Encoding::SJIS do + begin + result = @view.render(:file => "test/utf8_magic_with_bare_partial.html.erb", :layouts => "layouts/yield") + flunk 'Should have raised incompatible encoding error' + rescue ActionView::Template::Error => error + assert_match 'invalid byte sequence in Shift_JIS', error.original_exception.message + end + end + end + def with_external_encoding(encoding) old, Encoding.default_external = Encoding.default_external, encoding yield -- cgit v1.2.3 From 808847792c84e6d21ed7a2fb24b7e711b0007171 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Fri, 9 Apr 2010 00:40:48 -0300 Subject: db:test:prepare for tasks only if AR is loaded --- activerecord/lib/active_record/railties/databases.rake | 2 ++ railties/lib/rails/test_unit/testing.rake | 18 +++++++++++------- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/activerecord/lib/active_record/railties/databases.rake b/activerecord/lib/active_record/railties/databases.rake index 0229793a9a..2b53afc68b 100644 --- a/activerecord/lib/active_record/railties/databases.rake +++ b/activerecord/lib/active_record/railties/databases.rake @@ -446,6 +446,8 @@ namespace :db do end end +task 'test:prepare' => 'db:test:prepare' + def drop_database(config) case config['adapter'] when 'mysql' diff --git a/railties/lib/rails/test_unit/testing.rake b/railties/lib/rails/test_unit/testing.rake index 57857fb911..23b8f92abd 100644 --- a/railties/lib/rails/test_unit/testing.rake +++ b/railties/lib/rails/test_unit/testing.rake @@ -52,7 +52,11 @@ task :test do end namespace :test do - Rake::TestTask.new(:recent => "db:test:prepare") do |t| + task :prepare do + # Placeholder task for other Railtie and plugins to enhance. See Active Record for an example. + end + + Rake::TestTask.new(:recent => "test:prepare") do |t| since = TEST_CHANGES_SINCE touched = FileList['test/**/*_test.rb'].select { |path| File.mtime(path) > since } + recent_tests('app/models/**/*.rb', 'test/unit', since) + @@ -63,7 +67,7 @@ namespace :test do end Rake::Task['test:recent'].comment = "Test recent changes" - Rake::TestTask.new(:uncommitted => "db:test:prepare") do |t| + Rake::TestTask.new(:uncommitted => "test:prepare") do |t| def t.file_list if File.directory?(".svn") changed_since_checkin = silence_stderr { `svn status` }.map { |path| path.chomp[7 .. -1] } @@ -86,32 +90,32 @@ namespace :test do end Rake::Task['test:uncommitted'].comment = "Test changes since last checkin (only Subversion and Git)" - Rake::TestTask.new(:units => "db:test:prepare") do |t| + Rake::TestTask.new(:units => "test:prepare") do |t| t.libs << "test" t.pattern = 'test/unit/**/*_test.rb' end Rake::Task['test:units'].comment = "Run the unit tests in test/unit" - Rake::TestTask.new(:functionals => "db:test:prepare") do |t| + Rake::TestTask.new(:functionals => "test:prepare") do |t| t.libs << "test" t.pattern = 'test/functional/**/*_test.rb' end Rake::Task['test:functionals'].comment = "Run the functional tests in test/functional" - Rake::TestTask.new(:integration => "db:test:prepare") do |t| + Rake::TestTask.new(:integration => "test:prepare") do |t| t.libs << "test" t.pattern = 'test/integration/**/*_test.rb' end Rake::Task['test:integration'].comment = "Run the integration tests in test/integration" - Rake::TestTask.new(:benchmark => 'db:test:prepare') do |t| + Rake::TestTask.new(:benchmark => 'test:prepare') do |t| t.libs << 'test' t.pattern = 'test/performance/**/*_test.rb' t.options = '-- --benchmark' end Rake::Task['test:benchmark'].comment = 'Benchmark the performance tests' - Rake::TestTask.new(:profile => 'db:test:prepare') do |t| + Rake::TestTask.new(:profile => 'test:prepare') do |t| t.libs << 'test' t.pattern = 'test/performance/**/*_test.rb' end -- cgit v1.2.3 From a654ef2ee11142f3764fb312aa84a979adb890d9 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Fri, 9 Apr 2010 01:06:41 -0300 Subject: Don't include fixtures if --skip-activerecord is given --- railties/lib/rails/generators/rails/app/app_generator.rb | 12 +++++++++++- .../rails/generators/rails/app/templates/test/test_helper.rb | 2 ++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/railties/lib/rails/generators/rails/app/app_generator.rb b/railties/lib/rails/generators/rails/app/app_generator.rb index df6e98f38d..6d085f0935 100644 --- a/railties/lib/rails/generators/rails/app/app_generator.rb +++ b/railties/lib/rails/generators/rails/app/app_generator.rb @@ -157,7 +157,17 @@ module Rails::Generators def create_test_files return if options[:skip_testunit] - directory "test" + empty_directory "test" + + inside "test" do + template "test_helper.rb" + + directory "fixtures" + directory "functional" + directory "integration" + directory "performance" + directory "unit" + end end def create_tmp_files diff --git a/railties/lib/rails/generators/rails/app/templates/test/test_helper.rb b/railties/lib/rails/generators/rails/app/templates/test/test_helper.rb index 8bf1192ffe..c5e9cc2fc3 100644 --- a/railties/lib/rails/generators/rails/app/templates/test/test_helper.rb +++ b/railties/lib/rails/generators/rails/app/templates/test/test_helper.rb @@ -7,7 +7,9 @@ class ActiveSupport::TestCase # # Note: You'll currently still have to declare fixtures explicitly in integration tests # -- they do not yet inherit this setting +<% unless options[:skip_activerecord] -%> fixtures :all +<% end -%> # Add more helper methods to be used by all tests here... end -- cgit v1.2.3 From cb8fa3573c7cfcbc8a59acb6cfbde99f71dcccaa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Fri, 9 Apr 2010 08:47:19 +0200 Subject: Still use the directory command and also remove the fixture comments. --- railties/lib/rails/generators/rails/app/app_generator.rb | 12 +----------- .../generators/rails/app/templates/test/test_helper.rb | 15 --------------- .../generators/rails/app/templates/test/test_helper.rb.tt | 15 +++++++++++++++ 3 files changed, 16 insertions(+), 26 deletions(-) delete mode 100644 railties/lib/rails/generators/rails/app/templates/test/test_helper.rb create mode 100644 railties/lib/rails/generators/rails/app/templates/test/test_helper.rb.tt diff --git a/railties/lib/rails/generators/rails/app/app_generator.rb b/railties/lib/rails/generators/rails/app/app_generator.rb index 6d085f0935..df6e98f38d 100644 --- a/railties/lib/rails/generators/rails/app/app_generator.rb +++ b/railties/lib/rails/generators/rails/app/app_generator.rb @@ -157,17 +157,7 @@ module Rails::Generators def create_test_files return if options[:skip_testunit] - empty_directory "test" - - inside "test" do - template "test_helper.rb" - - directory "fixtures" - directory "functional" - directory "integration" - directory "performance" - directory "unit" - end + directory "test" end def create_tmp_files diff --git a/railties/lib/rails/generators/rails/app/templates/test/test_helper.rb b/railties/lib/rails/generators/rails/app/templates/test/test_helper.rb deleted file mode 100644 index c5e9cc2fc3..0000000000 --- a/railties/lib/rails/generators/rails/app/templates/test/test_helper.rb +++ /dev/null @@ -1,15 +0,0 @@ -ENV["RAILS_ENV"] = "test" -require File.expand_path('../../config/environment', __FILE__) -require 'rails/test_help' - -class ActiveSupport::TestCase - # Setup all fixtures in test/fixtures/*.(yml|csv) for all tests in alphabetical order. - # - # Note: You'll currently still have to declare fixtures explicitly in integration tests - # -- they do not yet inherit this setting -<% unless options[:skip_activerecord] -%> - fixtures :all -<% end -%> - - # Add more helper methods to be used by all tests here... -end diff --git a/railties/lib/rails/generators/rails/app/templates/test/test_helper.rb.tt b/railties/lib/rails/generators/rails/app/templates/test/test_helper.rb.tt new file mode 100644 index 0000000000..86564031f5 --- /dev/null +++ b/railties/lib/rails/generators/rails/app/templates/test/test_helper.rb.tt @@ -0,0 +1,15 @@ +ENV["RAILS_ENV"] = "test" +require File.expand_path('../../config/environment', __FILE__) +require 'rails/test_help' + +class ActiveSupport::TestCase +<% unless options[:skip_activerecord] -%> + # Setup all fixtures in test/fixtures/*.(yml|csv) for all tests in alphabetical order. + # + # Note: You'll currently still have to declare fixtures explicitly in integration tests + # -- they do not yet inherit this setting + fixtures :all + +<% end -%> + # Add more helper methods to be used by all tests here... +end -- cgit v1.2.3 From 773b2f0c9bdb7d27c0c18e000183c0ca8e56063d Mon Sep 17 00:00:00 2001 From: Xavier Noria Date: Fri, 9 Apr 2010 04:06:14 -0700 Subject: adds an entry for #favicon_link_tag in AP's CHANGELOG --- actionpack/CHANGELOG | 2 ++ 1 file changed, 2 insertions(+) diff --git a/actionpack/CHANGELOG b/actionpack/CHANGELOG index 49ca36cc26..6efed4a995 100644 --- a/actionpack/CHANGELOG +++ b/actionpack/CHANGELOG @@ -1,5 +1,7 @@ *Rails 3.0.0 [Edge] (pending)* +* Added #favicon_link_tag, it uses #image_path so in particular the favicon gets an asset ID [fxn] + * Fixed that default locale templates should be used if the current locale template is missing [DHH] * Added all the new HTML5 form types as individual form tag methods (search, url, number, etc) #3646 [Stephen Celis] -- cgit v1.2.3 From 42d3764b3ddc67ac5818deff06b7dfbcdd95e834 Mon Sep 17 00:00:00 2001 From: James Miller Date: Tue, 6 Apr 2010 16:36:43 -0700 Subject: ERB update for AC overview guide --- railties/guides/source/action_controller_overview.textile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/railties/guides/source/action_controller_overview.textile b/railties/guides/source/action_controller_overview.textile index bedca59c12..e193c57935 100644 --- a/railties/guides/source/action_controller_overview.textile +++ b/railties/guides/source/action_controller_overview.textile @@ -492,10 +492,10 @@ The way this is done is to add a non-guessable token which is only known to your If you generate a form like this: -<% form_for @user do |f| -%> +<%= form_for @user do |f| %> <%= f.text_field :username %> <%= f.text_field :password -%> -<% end -%> +<% end %> You will see how the token gets added as a hidden field: -- cgit v1.2.3 From 4f0982db91f4e67b36aec7f1e7445655e7bce8ce Mon Sep 17 00:00:00 2001 From: James Miller Date: Tue, 6 Apr 2010 16:52:39 -0700 Subject: More on the new ERB syntax in the guides --- .../source/action_controller_overview.textile | 10 +++++----- .../guides/source/action_view_overview.textile | 22 +++++++++++----------- .../activerecord_validations_callbacks.textile | 2 +- railties/guides/source/getting_started.textile | 2 +- .../guides/source/layouts_and_rendering.textile | 6 +++--- railties/guides/source/nested_model_forms.textile | 6 +++--- railties/guides/source/testing.textile | 2 +- 7 files changed, 25 insertions(+), 25 deletions(-) diff --git a/railties/guides/source/action_controller_overview.textile b/railties/guides/source/action_controller_overview.textile index e193c57935..caa7646b7f 100644 --- a/railties/guides/source/action_controller_overview.textile +++ b/railties/guides/source/action_controller_overview.textile @@ -255,12 +255,12 @@ The +destroy+ action redirects to the application's +root_url+, where the messag - <% if flash[:notice] -%> + <% if flash[:notice] %>

<%= flash[:notice] %>

- <% end -%> - <% if flash[:error] -%> + <% end %> + <% if flash[:error] %>

<%= flash[:error] %>

- <% end -%> + <% end %> @@ -494,7 +494,7 @@ If you generate a form like this: <%= form_for @user do |f| %> <%= f.text_field :username %> - <%= f.text_field :password -%> + <%= f.text_field :password %> <% end %> diff --git a/railties/guides/source/action_view_overview.textile b/railties/guides/source/action_view_overview.textile index df8cf4dc29..43ebe87875 100644 --- a/railties/guides/source/action_view_overview.textile +++ b/railties/guides/source/action_view_overview.textile @@ -135,7 +135,7 @@ The +post+ partial wraps the post's +body+ in a +div+ with the +id+ of the post *posts/_post.html.erb* -<% div_for(post) do %> +<%= div_for(post) do %>

<%= post.body %>

<% end %>
@@ -158,7 +158,7 @@ You can also render a block of code within a partial layout instead of calling + <% render(:layout => 'box', :locals => {:post => @post}) do %> - <% div_for(post) do %> + <%= div_for(post) do %>

<%= post.body %>

<% end %> <% end %> @@ -654,7 +654,7 @@ The core method of this helper, form_for, gives you the ability to create a form # Note: a @person variable will have been created in the controller (e.g. @person = Person.new) -<% form_for :person, @person, :url => { :action => "create" } do |f| %> +<%= form_for :person, @person, :url => { :action => "create" } do |f| %> <%= f.text_field :first_name %> <%= f.text_field :last_name %> <%= submit_tag 'Create' %> @@ -695,7 +695,7 @@ h5. fields_for Creates a scope around a specific model object like form_for, but doesn‘t create the form tags themselves. This makes fields_for suitable for specifying additional model objects in the same form: -<% form_for @person, :url => { :action => "update" } do |person_form| %> +<%= form_for @person, :url => { :action => "update" } do |person_form| %> First name: <%= person_form.text_field :first_name %> Last name : <%= person_form.text_field :last_name %> @@ -719,7 +719,7 @@ h5. form_for Creates a form and a scope around a specific model object that is used as a base for questioning about values for the fields. -<% form_for @post do |f| %> +<%= form_for @post do |f| %> <%= f.label :title, 'Title' %>: <%= f.text_field :title %>
<%= f.label :body, 'Body' %>: @@ -957,7 +957,7 @@ h5. field_set_tag Creates a field set for grouping HTML form elements. -<% field_set_tag do %> +<%= field_set_tag do %>

<%= text_field_tag 'name' %>

<% end %> # =>

@@ -970,10 +970,10 @@ Creates a file upload field. If you are using file uploads then you will also need to set the multipart option for the form tag: -<%= form_tag { :action => "post" }, { :multipart => true } %> +<%= form_tag { :action => "post" }, { :multipart => true } do %> <%= file_field_tag "file" %> <%= submit_tag %> -<%= end_form_tag %> +<% end %> Example output: @@ -988,9 +988,9 @@ h5. form_tag Starts a form tag that points the action to an url configured with +url_for_options+ just like +ActionController::Base#url_for+. -<% form_tag '/posts' do -%> +<%= form_tag '/posts' do %>
<%= submit_tag 'Save' %>
-<% end -%> +<% end %> # =>
@@ -1251,7 +1251,7 @@ h5. remote_form_for Creates a form that will submit using XMLHttpRequest in the background instead of the regular reloading POST arrangement and a scope around a specific resource that is used as a base for questioning about values for the fields. -<% remote_form_for(@post) do |f| %> +<%= remote_form_for(@post) do |f| %> ... <% end %> diff --git a/railties/guides/source/activerecord_validations_callbacks.textile b/railties/guides/source/activerecord_validations_callbacks.textile index 6575612bee..126a6efff5 100644 --- a/railties/guides/source/activerecord_validations_callbacks.textile +++ b/railties/guides/source/activerecord_validations_callbacks.textile @@ -712,7 +712,7 @@ end
-<% form_for(@product) do |f| %> +<%= form_for(@product) do |f| %> <%= f.error_messages %>

<%= f.label :description %>
diff --git a/railties/guides/source/getting_started.textile b/railties/guides/source/getting_started.textile index 17279146a7..2bbb4dc252 100644 --- a/railties/guides/source/getting_started.textile +++ b/railties/guides/source/getting_started.textile @@ -974,7 +974,7 @@ Once we have made the new comment, we send the user back to the +post_path(@post <% end %>

Add a comment:

-<% form_for([@post, @post.comments.build]) do |f| %> +<%= form_for([@post, @post.comments.build]) do |f| %> <%= f.error_messages %>
diff --git a/railties/guides/source/layouts_and_rendering.textile b/railties/guides/source/layouts_and_rendering.textile index fad687466e..92b36ab3e4 100644 --- a/railties/guides/source/layouts_and_rendering.textile +++ b/railties/guides/source/layouts_and_rendering.textile @@ -1037,7 +1037,7 @@ You can also pass local variables into partials, making them even more powerful * +_form.html.erb+ -<% form_for(zone) do |f| %> +<%= form_for(zone) do |f| %>

Zone name
<%= f.text_field :name %> @@ -1181,11 +1181,11 @@ On pages generated by +NewsController+, you want to hide the top menu and add a <% content_for :stylesheets do %> #top_menu {display: none} #right_menu {float: right; background-color: yellow; color: black} -<% end -%> +<% end %> <% content_for :content do %>

Right menu items here
<%= yield(:news_content) or yield %> -<% end -%> +<% end %> <%= render :file => 'layouts/application' %>
diff --git a/railties/guides/source/nested_model_forms.textile b/railties/guides/source/nested_model_forms.textile index 4b685b214e..4a79902232 100644 --- a/railties/guides/source/nested_model_forms.textile +++ b/railties/guides/source/nested_model_forms.textile @@ -122,7 +122,7 @@ h5. Standard form Start out with a regular RESTful form: -<% form_for @person do |f| %> +<%= form_for @person do |f| %> <%= f.text_field :name %> <% end %> @@ -140,7 +140,7 @@ h5. Nested form for a single associated object Now add a nested form for the +address+ association: -<% form_for @person do |f| %> +<%= form_for @person do |f| %> <%= f.text_field :name %> <% f.fields_for :address do |af| %> @@ -181,7 +181,7 @@ h5. Nested form for a collection of associated objects The form code for an association collection is pretty similar to that of a single associated object: -<% form_for @person do |f| %> +<%= form_for @person do |f| %> <%= f.text_field :name %> <% f.fields_for :projects do |pf| %> diff --git a/railties/guides/source/testing.textile b/railties/guides/source/testing.textile index b291b541ba..6e25515fed 100644 --- a/railties/guides/source/testing.textile +++ b/railties/guides/source/testing.textile @@ -84,7 +84,7 @@ h5. ERb'in It Up ERb allows you embed ruby code within templates. Both the YAML and CSV fixture formats are pre-processed with ERb when you load fixtures. This allows you to use Ruby to help you generate some sample data. -<% earth_size = 20 -%> +<% earth_size = 20 %> mercury: size: <%= earth_size / 50 %> brightest_on: <%= 113.days.ago.to_s(:db) %> -- cgit v1.2.3 From 647addd8e022012b159bc2298c5e23b5c8ff315c Mon Sep 17 00:00:00 2001 From: Jaime Iniesta Date: Wed, 7 Apr 2010 17:56:51 +0200 Subject: Fixed duplicated IDs on associations_basics guide to validate XHTML 1.0 Strict --- railties/guides/source/association_basics.textile | 163 +++++++++++----------- 1 file changed, 82 insertions(+), 81 deletions(-) diff --git a/railties/guides/source/association_basics.textile b/railties/guides/source/association_basics.textile index 4256466bec..f13f6db6ee 100644 --- a/railties/guides/source/association_basics.textile +++ b/railties/guides/source/association_basics.textile @@ -603,11 +603,11 @@ The +belongs_to+ association supports these options: * +:touch+ * +:validate+ -h6. +:autosave+ +h6(#belongs_to-autosave). +:autosave+ If you set the +:autosave+ option to +true+, Rails will save any loaded members and destroy members that are marked for destruction whenever you save the parent object. -h6. +:class_name+ +h6(#belongs_to-class_name). +:class_name+ If the name of the other model cannot be derived from the association name, you can use the +:class_name+ option to supply the model name. For example, if an order belongs to a customer, but the actual name of the model containing customers is +Patron+, you'd set things up this way: @@ -617,7 +617,7 @@ class Order < ActiveRecord::Base end -h6. +:conditions+ +h6(#belongs_to-conditions). +:conditions+ The +:conditions+ option lets you specify the conditions that the associated object must meet (in the syntax used by a SQL +WHERE+ clause). @@ -666,13 +666,13 @@ end Counter cache columns are added to the containing model's list of read-only attributes through +attr_readonly+. -h6. +:dependent+ +h6(#belongs_to-dependent). +:dependent+ If you set the +:dependent+ option to +:destroy+, then deleting this object will call the +destroy+ method on the associated object to delete that object. If you set the +:dependent+ option to +:delete+, then deleting this object will delete the associated object _without_ calling its +destroy+ method. WARNING: You should not specify this option on a +belongs_to+ association that is connected with a +has_many+ association on the other class. Doing so can lead to orphaned records in your database. -h6. +:foreign_key+ +h6(#belongs_to-foreign_key). +:foreign_key+ By convention, Rails guesses that the column used to hold the foreign key on this model is the name of the association with the suffix +_id+ added. The +:foreign_key+ option lets you set the name of the foreign key directly: @@ -685,7 +685,7 @@ end TIP: In any case, Rails will not create foreign key columns for you. You need to explicitly define them as part of your migrations. -h6. +:include+ +h6(#belongs_to-includes). +:include+ You can use the +:include+ option to specify second-order associations that should be eager-loaded when this association is used. For example, consider these models: @@ -727,11 +727,11 @@ h6. +:polymorphic+ Passing +true+ to the +:polymorphic+ option indicates that this is a polymorphic association. Polymorphic associations were discussed in detail earlier in this guide. -h6. +:readonly+ +h6(#belongs_to-readonly). +:readonly+ If you set the +:readonly+ option to +true+, then the associated object will be read-only when retrieved via the association. -h6. +:select+ +h6(#belongs_to-select). +:select+ The +:select+ option lets you override the SQL +SELECT+ clause that is used to retrieve data about the associated object. By default, Rails retrieves all columns. @@ -759,11 +759,11 @@ class Order < ActiveRecord::Base end -h6. +:validate+ +h6(#belongs_to-validate). +:validate+ If you set the +:validate+ option to +true+, then associated objects will be validated whenever you save this object. By default, this is +false+: associated objects will not be validated when this object is saved. -h5. How To Know Whether There's an Associated Object? +h5(#belongs_to-how_to_know_whether_theres_an_associated_object). How To Know Whether There's an Associated Object? To know whether there's and associated object just check association.nil?: @@ -773,7 +773,7 @@ if @order.customer.nil? end -h5. When are Objects Saved? +h5(#belongs_to-when_are_objects_saved). When are Objects Saved? Assigning an object to a +belongs_to+ association does _not_ automatically save the object. It does not save the associated object either. @@ -869,15 +869,15 @@ The +has_one+ association supports these options: * +:through+ * +:validate+ -h6. +:as+ +h6(#has_one-as). +:as+ Setting the +:as+ option indicates that this is a polymorphic association. Polymorphic associations were discussed in detail earlier in this guide. -h6. +:autosave+ +h6(#has_one-autosave). +:autosave+ If you set the +:autosave+ option to +true+, Rails will save any loaded members and destroy members that are marked for destruction whenever you save the parent object. -h6. +:class_name+ +h6(#has_one-class_name). +:class_name+ If the name of the other model cannot be derived from the association name, you can use the +:class_name+ option to supply the model name. For example, if a supplier has an account, but the actual name of the model containing accounts is +Billing+, you'd set things up this way: @@ -887,7 +887,7 @@ class Supplier < ActiveRecord::Base end -h6. +:conditions+ +h6(#has_one-conditions). +:conditions+ The +:conditions+ option lets you specify the conditions that the associated object must meet (in the syntax used by a SQL +WHERE+ clause). @@ -897,11 +897,11 @@ class Supplier < ActiveRecord::Base end -h6. +:dependent+ +h6(#has_one-dependent). +:dependent+ If you set the +:dependent+ option to +:destroy+, then deleting this object will call the +destroy+ method on the associated object to delete that object. If you set the +:dependent+ option to +:delete+, then deleting this object will delete the associated object _without_ calling its +destroy+ method. If you set the +:dependent+ option to +:nullify+, then deleting this object will set the foreign key in the association object to +NULL+. -h6. +:foreign_key+ +h6(#has_one-foreign_key). +:foreign_key+ By convention, Rails guesses that the column used to hold the foreign key on the other model is the name of this model with the suffix +_id+ added. The +:foreign_key+ option lets you set the name of the foreign key directly: @@ -913,7 +913,7 @@ end TIP: In any case, Rails will not create foreign key columns for you. You need to explicitly define them as part of your migrations. -h6. +:include+ +h6(#has_one-include). +:include+ You can use the +:include+ option to specify second-order associations that should be eager-loaded when this association is used. For example, consider these models: @@ -949,39 +949,39 @@ class Representative < ActiveRecord::Base end -h6. +:order+ +h6(#has_one-order). +:order+ The +:order+ option dictates the order in which associated objects will be received (in the syntax used by a SQL +ORDER BY+ clause). Because a +has_one+ association will only retrieve a single associated object, this option should not be needed. -h6. +:primary_key+ +h6(#has_one-primary_key). +:primary_key+ By convention, Rails guesses that the column used to hold the primary key of this model is +id+. You can override this and explicitly specify the primary key with the +:primary_key+ option. -h6. +:readonly+ +h6(#has_one-readonly). +:readonly+ If you set the +:readonly+ option to +true+, then the associated object will be read-only when retrieved via the association. -h6. +:select+ +h6(#has_one-select). +:select+ The +:select+ option lets you override the SQL +SELECT+ clause that is used to retrieve data about the associated object. By default, Rails retrieves all columns. -h6. +:source+ +h6(#has_one-source). +:source+ The +:source+ option specifies the source association name for a +has_one :through+ association. -h6. +:source_type+ +h6(#has_one-source_type). +:source_type+ The +:source_type+ option specifies the source association type for a +has_one :through+ association that proceeds through a polymorphic association. -h6. +:through+ +h6(#has_one-through). +:through+ The +:through+ option specifies a join model through which to perform the query. +has_one :through+ associations were discussed in detail earlier in this guide. -h6. +:validate+ +h6(#has_one-validate). +:validate+ If you set the +:validate+ option to +true+, then associated objects will be validated whenever you save this object. By default, this is +false+: associated objects will not be validated when this object is saved. -h5. How To Know Whether There's an Associated Object? +h5(#has_one-how_to_know_whether_theres_an_associated_object). How To Know Whether There's an Associated Object? To know whether there's and associated object just check association.nil?: @@ -991,7 +991,7 @@ if @supplier.account.nil? end -h5. When are Objects Saved? +h5(#has_one-when_are_objects_saved). When are Objects Saved? When you assign an object to a +has_one+ association, that object is automatically saved (in order to update its foreign key). In addition, any object being replaced is also automatically saved, because its foreign key will change too. @@ -1005,7 +1005,7 @@ h4. +has_many+ Association Reference The +has_many+ association creates a one-to-many relationship with another model. In database terms, this association says that the other class will have a foreign key that refers to instances of this class. -h5. Methods Added +h5. Methods Added by +has_many+ When you declare a +has_many+ association, the declaring class automatically gains 13 methods related to the association: @@ -1049,7 +1049,7 @@ orders.build(attributes = {}, ...) orders.create(attributes = {}) -h6. collection(force_reload = false) +h6(#has_many-collection). collection(force_reload = false) The collection method returns an array of all of the associated objects. If there are no associated objects, it returns an empty array. @@ -1057,7 +1057,7 @@ The collection method returns an array of all of the associate @orders = @customer.orders -h6. collection<<(object, ...) +h6(#has_many-collection-lt_lt). collection<<(object, ...) The collection<< method adds one or more objects to the collection by setting their foreign keys to the primary key of the calling model. @@ -1065,7 +1065,7 @@ The collection<< method adds one or more objects to the collec @customer.orders << @order1 -h6. collection.delete(object, ...) +h6(#has_many-collection-delete). collection.delete(object, ...) The collection.delete method removes one or more objects from the collection by setting their foreign keys to +NULL+. @@ -1076,11 +1076,11 @@ The collection.delete method removes one or more objects from WARNING: Objects will be in addition destroyed if they're associated with +:dependent => :destroy+, and deleted if they're associated with +:dependent => :delete_all+. -h6. collection=objects +h6(#has_many-collection_equal). collection=objects The collection= method makes the collection contain only the supplied objects, by adding and deleting as appropriate. -h6. collection_singular_ids +h6(#has_many-collection_singular). collection_singular_ids The collection_singular_ids method returns an array of the ids of the objects in the collection. @@ -1088,11 +1088,11 @@ The collection_singular_ids method returns an array of the ids @order_ids = @customer.order_ids -h6. collection_singular_ids=ids +h6(#has_many-collection_singular_ids_ids). collection_singular_ids=ids The collection_singular_ids= method makes the collection contain only the objects identified by the supplied primary key values, by adding and deleting as appropriate. -h6. collection.clear +h6(#has_many-collection_clear). collection.clear The collection.clear method removes every object from the collection. This destroys the associated objects if they are associated with +:dependent => :destroy+, deletes them directly from the database if +:dependent => :delete_all+, and otherwise sets their foreign keys to +NULL+. @@ -1179,7 +1179,7 @@ The +has_many+ association supports these options: * +:uniq+ * +:validate+ -h6. +:as+ +h6(#has_many-as). +:as+ Setting the +:as+ option indicates that this is a polymorphic association, as discussed earlier in this guide. @@ -1187,7 +1187,7 @@ h6. +:autosave+ If you set the +:autosave+ option to +true+, Rails will save any loaded members and destroy members that are marked for destruction whenever you save the parent object. -h6. +:class_name+ +h6(#has_many-class_name). +:class_name+ If the name of the other model cannot be derived from the association name, you can use the +:class_name+ option to supply the model name. For example, if a customer has many orders, but the actual name of the model containing orders is +Transaction+, you'd set things up this way: @@ -1197,7 +1197,7 @@ class Customer < ActiveRecord::Base end -h6. +:conditions+ +h6(#has_many-conditions). +:conditions+ The +:conditions+ option lets you specify the conditions that the associated object must meet (in the syntax used by a SQL +WHERE+ clause). @@ -1230,27 +1230,27 @@ end Be sure to use single quotes. -h6. +:counter_sql+ +h6(#has_many-counter_sql). +:counter_sql+ Normally Rails automatically generates the proper SQL to count the association members. With the +:counter_sql+ option, you can specify a complete SQL statement to count them yourself. NOTE: If you specify +:finder_sql+ but not +:counter_sql+, then the counter SQL will be generated by substituting +SELECT COUNT(*) FROM+ for the +SELECT ... FROM+ clause of your +:finder_sql+ statement. -h6. +:dependent+ +h6(#has_many-dependent). +:dependent+ If you set the +:dependent+ option to +:destroy+, then deleting this object will call the +destroy+ method on the associated objects to delete those objects. If you set the +:dependent+ option to +:delete_all+, then deleting this object will delete the associated objects _without_ calling their +destroy+ method. If you set the +:dependent+ option to +:nullify+, then deleting this object will set the foreign key in the associated objects to +NULL+. NOTE: This option is ignored when you use the +:through+ option on the association. -h6. +:extend+ +h6(#has_many-extend). +:extend+ The +:extend+ option specifies a named module to extend the association proxy. Association extensions are discussed in detail later in this guide. -h6. +:finder_sql+ +h6(#has_many-finder_sql). +:finder_sql+ Normally Rails automatically generates the proper SQL to fetch the association members. With the +:finder_sql+ option, you can specify a complete SQL statement to fetch them yourself. If fetching objects requires complex multi-table SQL, this may be necessary. -h6. +:foreign_key+ +h6(#has_many-foreign_key). +:foreign_key+ By convention, Rails guesses that the column used to hold the foreign key on the other model is the name of this model with the suffix +_id+ added. The +:foreign_key+ option lets you set the name of the foreign key directly: @@ -1262,7 +1262,7 @@ end TIP: In any case, Rails will not create foreign key columns for you. You need to explicitly define them as part of your migrations. -h6. +:group+ +h6(:has_many-group). +:group+ The +:group+ option supplies an attribute name to group the result set by, using a +GROUP BY+ clause in the finder SQL. @@ -1272,7 +1272,7 @@ class Customer < ActiveRecord::Base end -h6. +:include+ +h6(#has_many-include). +:include+ You can use the +:include+ option to specify second-order associations that should be eager-loaded when this association is used. For example, consider these models: @@ -1308,7 +1308,7 @@ class LineItem < ActiveRecord::Base end -h6. +:limit+ +h6(#has_many-limit). +:limit+ The +:limit+ option lets you restrict the total number of objects that will be fetched through an association. @@ -1319,11 +1319,11 @@ class Customer < ActiveRecord::Base end -h6. +:offset+ +h6(#has_many-offset). +:offset+ The +:offset+ option lets you specify the starting offset for fetching objects via an association. For example, if you set +:offset => 11+, it will skip the first 11 records. -h6. +:order+ +h6(#has_many-order). +:order+ The +:order+ option dictates the order in which associated objects will be received (in the syntax used by a SQL +ORDER BY+ clause). @@ -1333,41 +1333,41 @@ class Customer < ActiveRecord::Base end -h6. +:primary_key+ +h6(#has_many-primary_key). +:primary_key+ By convention, Rails guesses that the column used to hold the primary key of the association is +id+. You can override this and explicitly specify the primary key with the +:primary_key+ option. -h6. +:readonly+ +h6(#has_many-readonly). +:readonly+ If you set the +:readonly+ option to +true+, then the associated objects will be read-only when retrieved via the association. -h6. +:select+ +h6(#has_many-select). +:select+ The +:select+ option lets you override the SQL +SELECT+ clause that is used to retrieve data about the associated objects. By default, Rails retrieves all columns. WARNING: If you specify your own +:select+, be sure to include the primary key and foreign key columns of the associated model. If you do not, Rails will throw an error. -h6. +:source+ +h6(#has_many-source). +:source+ The +:source+ option specifies the source association name for a +has_many :through+ association. You only need to use this option if the name of the source association cannot be automatically inferred from the association name. -h6. +:source_type+ +h6(#has_many-source_type). +:source_type+ The +:source_type+ option specifies the source association type for a +has_many :through+ association that proceeds through a polymorphic association. -h6. +:through+ +h6(#has_many-through). +:through+ The +:through+ option specifies a join model through which to perform the query. +has_many :through+ associations provide a way to implement many-to-many relationships, as discussed earlier in this guide. -h6. +:uniq+ +h6(#has_many-uniq). +:uniq+ Specify the +:uniq => true+ option to remove duplicates from the collection. This is most useful in conjunction with the +:through+ option. -h6. +:validate+ +h6(#has_many-validate). +:validate+ If you set the +:validate+ option to +false+, then associated objects will not be validated whenever you save this object. By default, this is +true+: associated objects will be validated when this object is saved. -h5. When are Objects Saved? +h5(#has_many-when_are_objects_saved). When are Objects Saved? When you assign an object to a +has_many+ association, that object is automatically saved (in order to update its foreign key). If you assign multiple objects in one statement, then they are all saved. @@ -1381,7 +1381,7 @@ h4. +has_and_belongs_to_many+ Association Reference The +has_and_belongs_to_many+ association creates a many-to-many relationship with another model. In database terms, this associates two classes via an intermediate join table that includes foreign keys referring to each of the classes. -h5. Methods Added +h5. Methods Added by +has_and_belongs_to_many+ When you declare a +has_and_belongs_to_many+ association, the declaring class automatically gains 13 methods related to the association: @@ -1478,7 +1478,7 @@ h6. collection.clear The collection.clear method removes every object from the collection by deleting the rows from the joining table. This does not destroy the associated objects. -h6. collection.empty? +h6(#has_and_belongs_to_many-collection-empty). collection.empty? The collection.empty? method returns +true+ if the collection does not contain any associated objects. @@ -1488,7 +1488,7 @@ The collection.empty? method returns +true+ if the collection <% end %> -h6. collection.size +h6(#has_and_belongs_to_many-collection-size). collection.size The collection.size method returns the number of objects in the collection. @@ -1496,7 +1496,7 @@ The collection.size method returns the number of objects in th @assembly_count = @part.assemblies.size -h6. collection.find(...) +h6(#has_and_belongs_to_many-collection-find). collection.find(...) The collection.find method finds objects within the collection. It uses the same syntax and options as +ActiveRecord::Base.find+. It also adds the additional condition that the object must be in the collection. @@ -1505,7 +1505,7 @@ The collection.find method finds objects within the collection :conditions => ["created_at > ?", 2.days.ago]) -h6. collection.exists?(...) +h6(#has_and_belongs_to_many-collection-exists). collection.exists?(...) The collection.exists? method checks whether an object meeting the supplied conditions exists in the collection. It uses the same syntax and options as +ActiveRecord::Base.exists?+. @@ -1518,7 +1518,7 @@ The collection.build method returns a new object of the associ {:assembly_name => "Transmission housing"}) -h6. collection.create(attributes = {}) +h6(#has_and_belongs_to_many-create-attributes). collection.create(attributes = {}) The collection.create method returns a new object of the associated type. This object will be instantiated from the passed attributes, the link through the join table will be created, and the associated object _will_ be saved (assuming that it passes any validations). @@ -1575,11 +1575,11 @@ class User < ActiveRecord::Base end -h6. +:autosave+ +h6(#has_and_belongs_to_many-autosave). +:autosave+ If you set the +:autosave+ option to +true+, Rails will save any loaded members and destroy members that are marked for destruction whenever you save the parent object. -h6. +:class_name+ +h6(#has_and_belongs_to_many-class_name). +:class_name+ If the name of the other model cannot be derived from the association name, you can use the +:class_name+ option to supply the model name. For example, if a part has many assemblies, but the actual name of the model containing assemblies is +Gadget+, you'd set things up this way: @@ -1589,7 +1589,7 @@ class Parts < ActiveRecord::Base end -h6. +:conditions+ +h6(#has_and_belongs_to_many-conditions). +:conditions+ The +:conditions+ option lets you specify the conditions that the associated object must meet (in the syntax used by a SQL +WHERE+ clause). @@ -1611,7 +1611,7 @@ end If you use a hash-style +:conditions+ option, then record creation via this association will be automatically scoped using the hash. In this case, using +@parts.assemblies.create+ or +@parts.assemblies.build+ will create orders where the +factory+ column has the value "Seattle". -h6. +:counter_sql+ +h6(#has_and_belongs_to_many-counter_sql). +:counter_sql+ Normally Rails automatically generates the proper SQL to count the association members. With the +:counter_sql+ option, you can specify a complete SQL statement to count them yourself. @@ -1621,15 +1621,15 @@ h6. +:delete_sql+ Normally Rails automatically generates the proper SQL to remove links between the associated classes. With the +:delete_sql+ option, you can specify a complete SQL statement to delete them yourself. -h6. +:extend+ +h6(#has_and_belongs_to_many-extend). +:extend+ The +:extend+ option specifies a named module to extend the association proxy. Association extensions are discussed in detail later in this guide. -h6. +:finder_sql+ +h6(#has_and_belongs_to_many-finder_sql). +:finder_sql+ Normally Rails automatically generates the proper SQL to fetch the association members. With the +:finder_sql+ option, you can specify a complete SQL statement to fetch them yourself. If fetching objects requires complex multi-table SQL, this may be necessary. -h6. +:foreign_key+ +h6(#has_and_belongs_to_many-foreign_key). +:foreign_key+ By convention, Rails guesses that the column in the join table used to hold the foreign key pointing to this model is the name of this model with the suffix +_id+ added. The +:foreign_key+ option lets you set the name of the foreign key directly: @@ -1641,7 +1641,7 @@ class User < ActiveRecord::Base end -h6. +:group+ +h6(#has_and_belongs_to_many-group). +:group+ The +:group+ option supplies an attribute name to group the result set by, using a +GROUP BY+ clause in the finder SQL. @@ -1651,7 +1651,7 @@ class Parts < ActiveRecord::Base end -h6. +:include+ +h6(#has_and_belongs_to_many-include). +:include+ You can use the +:include+ option to specify second-order associations that should be eager-loaded when this association is used. @@ -1663,7 +1663,7 @@ h6. +:join_table+ If the default name of the join table, based on lexical ordering, is not what you want, you can use the +:join_table+ option to override the default. -h6. +:limit+ +h6(#has_and_belongs_to_many-limit). +:limit+ The +:limit+ option lets you restrict the total number of objects that will be fetched through an association. @@ -1674,11 +1674,11 @@ class Parts < ActiveRecord::Base end -h6. +:offset+ +h6(#has_and_belongs_to_many-offset). +:offset+ The +:offset+ option lets you specify the starting offset for fetching objects via an association. For example, if you set +:offset => 11+, it will skip the first 11 records. -h6. +:order+ +h6(#has_and_belongs_to_many-order). +:order+ The +:order+ option dictates the order in which associated objects will be received (in the syntax used by a SQL +ORDER BY+ clause). @@ -1688,23 +1688,23 @@ class Parts < ActiveRecord::Base end -h6. +:readonly+ +h6(#has_and_belongs_to_many-readonly). +:readonly+ If you set the +:readonly+ option to +true+, then the associated objects will be read-only when retrieved via the association. -h6. +:select+ +h6(#has_and_belongs_to_many-select). +:select+ The +:select+ option lets you override the SQL +SELECT+ clause that is used to retrieve data about the associated objects. By default, Rails retrieves all columns. -h6. +:uniq+ +h6(#has_and_belongs_to_many-uniq). +:uniq+ Specify the +:uniq => true+ option to remove duplicates from the collection. -h6. +:validate+ +h6(#has_and_belongs_to_many-validate). +:validate+ If you set the +:validate+ option to +false+, then associated objects will not be validated whenever you save this object. By default, this is +true+: associated objects will be validated when this object is saved. -h5. When are Objects Saved? +h5(#has_and_belongs_to_many-when_are_objects_saved). When are Objects Saved? When you assign an object to a +has_and_belongs_to_many+ association, that object is automatically saved (in order to update the join table). If you assign multiple objects in one statement, then they are all saved. @@ -1809,6 +1809,7 @@ h3. Changelog "Lighthouse ticket":http://rails.lighthouseapp.com/projects/16213-rails-guides/tickets/11 +* April 7, 2010: Fixed document to validate XHTML 1.0 Strict. "Jaime Iniesta":http://jaimeiniesta.com * April 19, 2009: Added +:touch+ option to +belongs_to+ associations by "Mike Gunderloy":credits.html#mgunderloy * February 1, 2009: Added +:autosave+ option "Mike Gunderloy":credits.html#mgunderloy * September 28, 2008: Corrected +has_many :through+ diagram, added polymorphic diagram, some reorganization by "Mike Gunderloy":credits.html#mgunderloy . First release version. -- cgit v1.2.3 From 40e9cb6f4df3f10ef80284023595fe6a955e1740 Mon Sep 17 00:00:00 2001 From: Jaime Iniesta Date: Wed, 7 Apr 2010 18:19:17 +0200 Subject: Fixed duplicated IDs on active_record_querying guide to validate XHTML 1.0 Strict --- railties/guides/source/active_record_querying.textile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/railties/guides/source/active_record_querying.textile b/railties/guides/source/active_record_querying.textile index a993dad900..edd8ea3640 100644 --- a/railties/guides/source/active_record_querying.textile +++ b/railties/guides/source/active_record_querying.textile @@ -274,7 +274,7 @@ Client.where( This makes for clearer readability if you have a large number of variable conditions. -h5. Range Conditions +h5(#array-range_conditions). Range Conditions If you're looking for a range inside of a table (for example, users created in a certain timeframe) you can use the conditions option coupled with the +IN+ SQL statement for this. If you had two dates coming in from a controller you could do something like this to look for a range: @@ -353,7 +353,7 @@ The field name does not have to be a symbol it can also be a string: Client.where({ 'locked' => true }) -h5. Range Conditions +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. -- cgit v1.2.3 From 1133146679d4213bec05ff8d97938ec03414c52c Mon Sep 17 00:00:00 2001 From: Jaime Iniesta Date: Wed, 7 Apr 2010 18:21:31 +0200 Subject: update changelog --- railties/guides/source/active_record_querying.textile | 1 + 1 file changed, 1 insertion(+) diff --git a/railties/guides/source/active_record_querying.textile b/railties/guides/source/active_record_querying.textile index edd8ea3640..e47615f070 100644 --- a/railties/guides/source/active_record_querying.textile +++ b/railties/guides/source/active_record_querying.textile @@ -934,6 +934,7 @@ h3. Changelog "Lighthouse ticket":http://rails.lighthouseapp.com/projects/16213-rails-guides/tickets/16 +* April 7, 2010: Fixed document to validate XHTML 1.0 Strict. "Jaime Iniesta":http://jaimeiniesta.com * February 3, 2010: Update to Rails 3 by "James Miller":credits.html#bensie * February 7, 2009: Second version by "Pratik":credits.html#lifo * December 29 2008: Initial version by "Ryan Bigg":credits.html#radar -- cgit v1.2.3 From 5fa70e8ba96965b44a971908080e5506b495a0bd Mon Sep 17 00:00:00 2001 From: eparreno Date: Fri, 9 Apr 2010 04:45:04 -0700 Subject: CL guide: revises fonts in a few places --- railties/guides/source/command_line.textile | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/railties/guides/source/command_line.textile b/railties/guides/source/command_line.textile index c888212604..f2b53023a5 100644 --- a/railties/guides/source/command_line.textile +++ b/railties/guides/source/command_line.textile @@ -18,12 +18,12 @@ h3. Command Line Basics There are a few commands that are absolutely critical to your everyday usage of Rails. In the order of how much you'll probably use them are: -* rails console -* rails server -* rake -* rails generate -* rails dbconsole -* rails app_name +* rails console +* rails server +* rake +* rails generate +* rails dbconsole +* rails app_name Let's create a simple Rails application to step through each of these commands in context. @@ -246,9 +246,13 @@ $ rake db:migrate INFO: Let's talk about unit tests. Unit tests are code that tests and makes assertions about code. In unit testing, we take a little part of code, say a method of a model, and test its inputs and outputs. Unit tests are your friend. The sooner you make peace with the fact that your quality of life will drastically increase when you unit test your code, the better. Seriously. We'll make one in a moment. -Let's see the interface Rails created for us. rails server; http://localhost:3000/high_scores +Let's see the interface Rails created for us. -We can create new high scores (55,160 on Space Invaders!) + +$ rails server + + +Go to your browser and open "http://localhost:3000/high_scores":http://localhost:3000/high_scores, now we can create new high scores (55,160 on Space Invaders!) h4. +rails console+ @@ -260,12 +264,12 @@ h4. +rails dbconsole+ h4. +rails plugin+ -The +rails plugin+ command simplifies plugin management; think a miniature version of the Gem utility. Let's walk through installing a plugin. You can call the sub-command *discover*, which sifts through repositories looking for plugins, or call *source* to add a specific repository of plugins, or you can specify the plugin location directly. +The +rails plugin+ command simplifies plugin management; think a miniature version of the Gem utility. Let's walk through installing a plugin. You can call the sub-command +discover+, which sifts through repositories looking for plugins, or call +source+ to add a specific repository of plugins, or you can specify the plugin location directly. + +Let's say you're creating a website for a client who wants a small accounting system. Every event having to do with money must be logged, and must never be deleted. Wouldn't it be great if we could override the behavior of a model to never actually take its record out of the database, but instead, just set a field? -Let's say you're creating a website for a client who wants a small accounting system. Every event having to do with money must be logged, and must never be deleted. Wouldn't it be great if we could override the behavior of a model to never actually take its record out of the database, but *instead*, just set a field? +There is such a thing! The plugin we're installing is called +acts_as_paranoid+, and it lets models implement a +deleted_at+ column that gets set when you call destroy. Later, when calling find, the plugin will tack on a database check to filter out "deleted" things. -There is such a thing! The plugin we're installing is called "acts_as_paranoid", and it lets models implement a "deleted_at" column that gets set when you call destroy. Later, when calling find, the plugin will tack on a database check to filter out "deleted" things. -================================================================================== $ rails plugin install http://svn.techno-weenie.net/projects/plugins/acts_as_paranoid + ./CHANGELOG -- cgit v1.2.3 From b2a2d9f91b62564e30ab6e77a1347f51f90156f2 Mon Sep 17 00:00:00 2001 From: Ryan Bigg Date: Tue, 6 Apr 2010 08:46:57 +1000 Subject: Further expansion into how Bundler loads the gemfile. --- railties/guides/source/initialization.textile | 51 +++++++++++++++++++++++++-- 1 file changed, 49 insertions(+), 2 deletions(-) diff --git a/railties/guides/source/initialization.textile b/railties/guides/source/initialization.textile index 2d64510c2f..1b76034f82 100644 --- a/railties/guides/source/initialization.textile +++ b/railties/guides/source/initialization.textile @@ -2021,7 +2021,7 @@ This sets up a couple of important things initially. If you specify a gem like t gem 'rails', "2.3.4" -This sets +options+ to be an empty hash, but +version+ to be +"2.3.4"+. TODO: How does one pass options and versions? +This sets +options+ to be an empty hash, but +version+ to be +"2.3.4"+. TODO: How does one pass options and versions at the same time? In the Gemfile for a default Rails project, the first +gem+ line is: @@ -2054,7 +2054,54 @@ This line will check that +options+ contains no deprecated options by using the end -+_normalize_hash+ will convert all the keys in the +opts+ hash to strings. ++_normalize_hash+ will convert all the keys in the +opts+ hash to strings. There is neither a +git+ or a +path+ key in the +opts+ hash so the next couple of lines are ignored, then the +source+ and +group+ keys are set up. + +TODO: Maybe it is best to cover what would happen in the case these lines did exist? + +The next line goes about defining a dependency for this gem: + + + @dependencies << Dependency.new(name, version, options) + + +This class is defined like this: + + + module Bundler + class Dependency < Gem::Dependency + attr_reader :autorequire + attr_reader :groups + + def initialize(name, version, options = {}, &blk) + super(name, version) + + @autorequire = nil + @groups = Array(options["group"] || :default).map { |g| g.to_sym } + @source = options["source"] + + if options.key?('require') + @autorequire = Array(options['require'] || []) + end + end + end + end + + +The +initialize+ method in +Gem::Dependency+ is defined: + + + def initialize(name, version_requirements, type=:runtime) + @name = name + unless TYPES.include? type + raise ArgumentError, "Valid types are #{TYPES.inspect}, not #{@type.inspect}" + end + @type = type + @version_requirements = Gem::Requirement.create version_requirements + @version_requirement = nil # Avoid warnings. + end + + + -- cgit v1.2.3 From e35f05cc8e2c9362edb6065d8ad39c8ec3bce349 Mon Sep 17 00:00:00 2001 From: Ryan Bigg Date: Fri, 9 Apr 2010 06:45:49 +1000 Subject: Mention a way to turn off bundler and begin talking about version_requirements --- railties/guides/source/initialization.textile | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/railties/guides/source/initialization.textile b/railties/guides/source/initialization.textile index 1b76034f82..9b6727b740 100644 --- a/railties/guides/source/initialization.textile +++ b/railties/guides/source/initialization.textile @@ -1790,6 +1790,8 @@ Now that Rails has finished loading all the Railties by way of +require 'rails/a Bundler.require :default, Rails.env +NOTE: It is worth mentioning here that you are not tied to using Bundler with Rails 3, but it is (of course) advised that you do. To "turn off" Bundler, comment out or remove the corresponding lines in _config/application.rb_ and _config/boot.rb_. + Bundler was +require+'d back in _config/boot.rb_ and now we'll dive into the internals of Bundler to determine precisely what this line accomplishes. h4. +Bundler.require+ @@ -2101,6 +2103,8 @@ The +initialize+ method in +Gem::Dependency+ is defined: end +The +version_requirements+ that was passed in here + -- cgit v1.2.3 From c93580b48069a98aef1bef658c02bc393f173d99 Mon Sep 17 00:00:00 2001 From: Ryan Bigg Date: Fri, 9 Apr 2010 14:03:58 +1000 Subject: Further work on the bundler section. Almost there now. --- railties/guides/source/initialization.textile | 117 ++++++++++++++++++++++++-- 1 file changed, 111 insertions(+), 6 deletions(-) diff --git a/railties/guides/source/initialization.textile b/railties/guides/source/initialization.textile index 9b6727b740..e256503067 100644 --- a/railties/guides/source/initialization.textile +++ b/railties/guides/source/initialization.textile @@ -1911,15 +1911,13 @@ The next method to be called here would be +definition+ and it is defined like end -We do not have +settings[:disabled_shared_gems]+ set to true so this will execute the code under the +else+. The +ENV["GEM_PATH"]+ will resemble +/usr/local/lib/ruby/gems/1.9.1:/home/you/.gem/ruby/1.9.1:/usr/local/lib/ruby/gems/1.9.1+ - -TODO: Why the duplicates? Added an issue: http://github.com/carlhuda/bundler/issues#issue/249 +We do not have +settings[:disabled_shared_gems]+ set to true so this will execute the code under the +else+. The +ENV["GEM_PATH"]+ will resemble +/usr/local/lib/ruby/gems/1.9.1:/home/you/.gem/ruby/1.9.1+ And +ENV["GEM_HOME"]+ will be the path to the gems installed into your home directory by Bundler, something resembling +/home/you/.bundle/ruby/1.9.1+. After +configure_gem_home_and_path+ is done the +definition+ method goes about creating a +Definition+ from either +Gemfile.lock+ if it exists, or the +gemfile+ previously located. +Gemfile.lock+ only exists if +bundle lock+ has been ran and so far it has not. -+Definition.from_lock+ is defined in _lib/definition.rb_: ++Definition.from_gemfile+ is defined in _lib/bundler/definition.rb_: def self.from_gemfile(gemfile) @@ -1933,7 +1931,7 @@ After +configure_gem_home_and_path+ is done the +definition+ method goes about c end -Now that the +gemfile+ is located +Dsl.evaluate+ goes about loading it. The code for this can be found in _lib/dsl.rb_: +Now that the +gemfile+ is located +Dsl.evaluate+ goes about loading it. The code for this can be found in _lib/bundler/dsl.rb_: def self.evaluate(gemfile) @@ -2103,11 +2101,118 @@ The +initialize+ method in +Gem::Dependency+ is defined: end -The +version_requirements+ that was passed in here +The +version_requirements+ that was passed in here will be inspected by +Gem::Requirement.create+ and return, for our +3.0.0beta2+ version string a +Gem::Requirement+ object: + + + #]]> + + +Going back to +Bundler::Dependency+, the next line simply sets +@autorequire+ to +nil+ and the next line is a little more interesting: + + + @autorequire = nil + @groups = Array(options["group"] || :default).map { |g| g.to_sym } + + +Here, bundler sets the +groups+ variable to be whatever +group+ we've set for this gem and also demonstrates through code that the +group+ option allows for multiple groups, so in the _Gemfile_ we can specify the same gem for multiple groups: + + + group :test, :cucumber do + gem 'faker' + end + + +The final lines in +initialize+ work on the +require+ option which is not passed: + + + if options.key?('require') + @autorequire = Array(options['require'] || []) + end + + +If it were to be used in the _Gemfile_, it would look like this: + + + gem 'thinking-sphinx', :require => "thinking_sphinx" + + +So far, this is what simply loading the _Gemfile_ does. + +h3. Bring forth the gems + +Now that the _Gemfile_ has finished being parsed, the next line is: + + + builder.to_definition + + +This method is defined in _lib/bundler/dsl.rb_ and does this: + + + def to_definition + Definition.new(@dependencies, @sources) + end + + +The +Bundler::Definition#initialize+ method is this: + + + def initialize(dependencies, sources) + @dependencies = dependencies + @sources = sources + end + + +Now Bundler has a +Bundler::Definition+ object to be passed back to the +load+ method from _lib/bundler.rb_: + + + def load(gemfile = default_gemfile) + root = Pathname.new(gemfile).dirname + Runtime.new root, definition(gemfile) + end + + +The +Bundler::Runtime+ class inherits from +Bundler::Environment+ and the reason this is pointed out is because +super+ is used in the +initialize+ method in +Bundler::Runtime+: + + + super + if locked? + write_rb_lock + end + + +Thankfully, the +Bundler::Environment#initialize+ method is nothing too complex: + + + def initialize(root, definition) + @root = root + @definition = definition + end + + +The +locked?+ method checks if the _Gemfile.lock_ or _.bundler/environment.rb_ files exist: + + def locked? + File.exist?("#{root}/Gemfile.lock") || File.exist?("#{root}/.bundle/environment.rb") + end + +And if they do will call +write_rb_lock+: + + def write_rb_lock + shared_helpers = File.read(File.expand_path("../shared_helpers.rb", __FILE__)) + template = File.read(File.expand_path("../templates/environment.erb", __FILE__)) + erb = ERB.new(template, nil, '-') + FileUtils.mkdir_p(rb_lock_file.dirname) + File.open(rb_lock_file, 'w') do |f| + f.puts erb.result(binding) + end + end + +This will write out to _.bundler/environment.rb_ the state of the current environment. h3. Firing it up! -- cgit v1.2.3 From 69d525948058b3a0cc6c3401caa8e05532638c5a Mon Sep 17 00:00:00 2001 From: Ryan Bigg Date: Fri, 9 Apr 2010 15:34:13 +1000 Subject: Continue expanding on Bundler. --- railties/guides/source/initialization.textile | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/railties/guides/source/initialization.textile b/railties/guides/source/initialization.textile index e256503067..7013c3c324 100644 --- a/railties/guides/source/initialization.textile +++ b/railties/guides/source/initialization.textile @@ -2214,6 +2214,25 @@ And if they do will call +write_rb_lock+: This will write out to _.bundler/environment.rb_ the state of the current environment. +Now a quick refresher. Bundler is still evaulating the code for the +require+ in _lib/bundler.rb_, and the +groups+ variable here is an +Array+ containing two elements: +:default+ and the current Rails environment: +development+: + + + def require(*groups) + gemfile = default_gemfile + load(gemfile).require(*groups) + end + + +The second +require+ method here: + + + load(gemfile).require(*groups) + + +Is defined on _bundler/runtime.rb_ + + + h3. Firing it up! -- cgit v1.2.3 From da69c5d8bf5ac4a81de3870eb51a7833bbe79ef5 Mon Sep 17 00:00:00 2001 From: Ryan Bigg Date: Fri, 9 Apr 2010 17:52:34 +1000 Subject: Expansion on require method from runtime.rb --- railties/guides/source/initialization.textile | 37 ++++++++++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/railties/guides/source/initialization.textile b/railties/guides/source/initialization.textile index 7013c3c324..d8d119f608 100644 --- a/railties/guides/source/initialization.textile +++ b/railties/guides/source/initialization.textile @@ -2229,9 +2229,44 @@ The second +require+ method here: load(gemfile).require(*groups) -Is defined on _bundler/runtime.rb_ +Is defined on _bundler/runtime.rb_: + + def require(*groups) + groups.map! { |g| g.to_sym } + groups = [:default] if groups.empty? + autorequires = autorequires_for_groups(*groups) + + groups.each do |group| + (autorequires[group] || [[]]).each do |path, explicit| + if explicit + Kernel.require(path) + else + begin + Kernel.require(path) + rescue LoadError + end + end + end + end + end + + +This method does TODO: Describe what magic this undertakes. +The first method to be called here is +autorequires_for_groups+: + + + def autorequires_for_groups(*groups) + groups.map! { |g| g.to_sym } + autorequires = Hash.new { |h,k| h[k] = [] } + + ordered_deps = [] + specs_for(*groups).each do |g| + dep = @definition.dependencies.find{|d| d.name == g.name } + ordered_deps << dep if dep && !ordered_deps.include?(dep) + end + h3. Firing it up! -- cgit v1.2.3 From 157216b7b7dfc6fc61b03c75dcc372bbdf3e8b22 Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Fri, 9 Apr 2010 09:13:47 -0700 Subject: Trim application.html.erb fat --- .../rails/app/templates/app/views/layouts/application.html.erb | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/railties/lib/rails/generators/rails/app/templates/app/views/layouts/application.html.erb b/railties/lib/rails/generators/rails/app/templates/app/views/layouts/application.html.erb index 6b87d9d3ec..c812d45a57 100644 --- a/railties/lib/rails/generators/rails/app/templates/app/views/layouts/application.html.erb +++ b/railties/lib/rails/generators/rails/app/templates/app/views/layouts/application.html.erb @@ -1,16 +1,12 @@ - <%= controller_name.humanize %>: <%= action_name %> - <%= stylesheet_link_tag 'application' %> + <%= stylesheet_link_tag :all %> <%= javascript_include_tag :defaults %> <%= csrf_meta_tag %> -

<%= notice %>

-

<%= alert %>

- <%=raw yield %> -- cgit v1.2.3 From 19e6006636ecc071cc3b4ec3d339029626c06e72 Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Fri, 9 Apr 2010 09:14:02 -0700 Subject: Layout contents are html-safe --- actionpack/lib/action_view/render/layouts.rb | 2 +- .../rails/app/templates/app/views/layouts/application.html.erb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/actionpack/lib/action_view/render/layouts.rb b/actionpack/lib/action_view/render/layouts.rb index 7311730a19..31b09d9f0a 100644 --- a/actionpack/lib/action_view/render/layouts.rb +++ b/actionpack/lib/action_view/render/layouts.rb @@ -48,7 +48,7 @@ module ActionView # def _layout_for(name = nil, &block) #:nodoc: if !block || name - @_content_for[name || :layout] + @_content_for[name || :layout].html_safe else capture(&block) end diff --git a/railties/lib/rails/generators/rails/app/templates/app/views/layouts/application.html.erb b/railties/lib/rails/generators/rails/app/templates/app/views/layouts/application.html.erb index c812d45a57..705865ce19 100644 --- a/railties/lib/rails/generators/rails/app/templates/app/views/layouts/application.html.erb +++ b/railties/lib/rails/generators/rails/app/templates/app/views/layouts/application.html.erb @@ -7,7 +7,7 @@ -<%=raw yield %> +<%= yield %> -- cgit v1.2.3 From ea6a67cbdf5a05a78aedf214e5a7457d2b791567 Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Fri, 9 Apr 2010 09:22:16 -0700 Subject: Discourage << as public API, much less config --- railties/lib/rails/generators/rails/app/templates/config/application.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/railties/lib/rails/generators/rails/app/templates/config/application.rb b/railties/lib/rails/generators/rails/app/templates/config/application.rb index 377e607d2b..0066e2b0c2 100644 --- a/railties/lib/rails/generators/rails/app/templates/config/application.rb +++ b/railties/lib/rails/generators/rails/app/templates/config/application.rb @@ -50,6 +50,6 @@ module <%= app_const_base %> config.encoding = "utf-8" # Configure sensitive parameters which will be filtered from the log file. - config.filter_parameters << :password + config.filter_parameters += [:password] end end -- cgit v1.2.3 From c44cacb07077325d0434b571889ac032dfb026f6 Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Fri, 9 Apr 2010 09:49:46 -0700 Subject: Include app name in layout title --- railties/lib/rails/generators/rails/app/app_generator.rb | 7 ++++++- .../rails/app/templates/app/views/layouts/application.html.erb | 9 +++++---- railties/test/generators/app_generator_test.rb | 4 ++-- 3 files changed, 13 insertions(+), 7 deletions(-) diff --git a/railties/lib/rails/generators/rails/app/app_generator.rb b/railties/lib/rails/generators/rails/app/app_generator.rb index df6e98f38d..f7644c3280 100644 --- a/railties/lib/rails/generators/rails/app/app_generator.rb +++ b/railties/lib/rails/generators/rails/app/app_generator.rb @@ -78,7 +78,12 @@ module Rails::Generators end def create_app_files - directory "app" + directory "app/controllers" + directory "app/helpers" + directory "app/models" + inside "app/views/layouts" do + template "application.html.erb" + end end def create_config_files diff --git a/railties/lib/rails/generators/rails/app/templates/app/views/layouts/application.html.erb b/railties/lib/rails/generators/rails/app/templates/app/views/layouts/application.html.erb index 705865ce19..1dd112b4a6 100644 --- a/railties/lib/rails/generators/rails/app/templates/app/views/layouts/application.html.erb +++ b/railties/lib/rails/generators/rails/app/templates/app/views/layouts/application.html.erb @@ -1,13 +1,14 @@ - <%= stylesheet_link_tag :all %> - <%= javascript_include_tag :defaults %> - <%= csrf_meta_tag %> + <%= app_const_base %> + <%%= stylesheet_link_tag :all %> + <%%= javascript_include_tag :defaults %> + <%%= csrf_meta_tag %> -<%= yield %> +<%%= yield %> diff --git a/railties/test/generators/app_generator_test.rb b/railties/test/generators/app_generator_test.rb index 64579c1205..24e6d541c2 100644 --- a/railties/test/generators/app_generator_test.rb +++ b/railties/test/generators/app_generator_test.rb @@ -54,8 +54,8 @@ class AppGeneratorTest < Rails::Generators::TestCase def test_application_controller_and_layout_files run_generator assert_file "app/controllers/application_controller.rb", /layout 'application'/ - assert_file "app/views/layouts/application.html.erb", /stylesheet_link_tag 'application'/ - assert_file "public/stylesheets/application.css" + assert_file "app/views/layouts/application.html.erb", /stylesheet_link_tag :all/ + assert_no_file "public/stylesheets/application.css" end def test_name_collision_raises_an_error -- cgit v1.2.3 From ec8e747960da9c0413cb5da7834f458bc5dd8ce1 Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Fri, 9 Apr 2010 10:04:20 -0700 Subject: Partially revert "A new application now comes with a layout and a stylesheet." This reverts commit ea2c5fa8046e2f953b366adc94f0610ccfea0828. Conflicts: railties/lib/rails/generators/rails/app/templates/app/views/layouts/application.html.erb railties/test/generators/app_generator_test.rb --- railties/CHANGELOG | 2 - railties/lib/rails/generators.rb | 2 + .../rails/generators/rails/app/app_generator.rb | 2 +- .../templates/app/views/layouts/.empty_directory | 0 .../templates/public/stylesheets/.empty_directory | 0 .../templates/public/stylesheets/application.css | 65 ---------------------- .../rails/scaffold/scaffold_generator.rb | 1 + .../lib/rails/generators/rails/stylesheets/USAGE | 5 ++ .../rails/stylesheets/stylesheets_generator.rb | 9 +++ .../rails/stylesheets/templates/scaffold.css | 65 ++++++++++++++++++++++ .../scaffold_controller_generator_test.rb | 1 + .../test/generators/scaffold_generator_test.rb | 8 +++ .../test/generators/stylesheets_generator_test.rb | 17 ++++++ 13 files changed, 109 insertions(+), 68 deletions(-) create mode 100644 railties/lib/rails/generators/rails/app/templates/app/views/layouts/.empty_directory create mode 100644 railties/lib/rails/generators/rails/app/templates/public/stylesheets/.empty_directory delete mode 100644 railties/lib/rails/generators/rails/app/templates/public/stylesheets/application.css create mode 100644 railties/lib/rails/generators/rails/stylesheets/USAGE create mode 100644 railties/lib/rails/generators/rails/stylesheets/stylesheets_generator.rb create mode 100644 railties/lib/rails/generators/rails/stylesheets/templates/scaffold.css create mode 100644 railties/test/generators/stylesheets_generator_test.rb diff --git a/railties/CHANGELOG b/railties/CHANGELOG index 261333628d..82684e4614 100644 --- a/railties/CHANGELOG +++ b/railties/CHANGELOG @@ -1,5 +1,3 @@ -* A new application now comes with a layout and a stylesheet. [JV] - * Renamed config.cookie_secret to config.secret_token and pass it as env key. [JV] *Rails 3.0.0 [beta 2] (April 1st, 2010)* diff --git a/railties/lib/rails/generators.rb b/railties/lib/rails/generators.rb index 5f93dbf18f..9bc019b152 100644 --- a/railties/lib/rails/generators.rb +++ b/railties/lib/rails/generators.rb @@ -26,6 +26,7 @@ module Rails :orm => '-o', :resource_controller => '-c', :scaffold_controller => '-c', + :stylesheets => '-y', :template_engine => '-e', :test_framework => '-t' }, @@ -50,6 +51,7 @@ module Rails :resource_controller => :controller, :scaffold_controller => :scaffold_controller, :singleton => false, + :stylesheets => true, :test_framework => nil, :template_engine => :erb }, diff --git a/railties/lib/rails/generators/rails/app/app_generator.rb b/railties/lib/rails/generators/rails/app/app_generator.rb index f7644c3280..192792d078 100644 --- a/railties/lib/rails/generators/rails/app/app_generator.rb +++ b/railties/lib/rails/generators/rails/app/app_generator.rb @@ -142,7 +142,7 @@ module Rails::Generators end def create_public_stylesheets_files - directory "public/stylesheets" + empty_directory_with_gitkeep "public/stylesheets" end def create_prototype_files diff --git a/railties/lib/rails/generators/rails/app/templates/app/views/layouts/.empty_directory b/railties/lib/rails/generators/rails/app/templates/app/views/layouts/.empty_directory new file mode 100644 index 0000000000..e69de29bb2 diff --git a/railties/lib/rails/generators/rails/app/templates/public/stylesheets/.empty_directory b/railties/lib/rails/generators/rails/app/templates/public/stylesheets/.empty_directory new file mode 100644 index 0000000000..e69de29bb2 diff --git a/railties/lib/rails/generators/rails/app/templates/public/stylesheets/application.css b/railties/lib/rails/generators/rails/app/templates/public/stylesheets/application.css deleted file mode 100644 index ea3dc9b8b5..0000000000 --- a/railties/lib/rails/generators/rails/app/templates/public/stylesheets/application.css +++ /dev/null @@ -1,65 +0,0 @@ -body { background-color: #fff; color: #333; } - -body, 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; } -a:visited { color: #666; } -a:hover { color: #fff; background-color:#000; } - -div.field, div.actions { - margin-bottom: 10px; -} - -.notice { - color: green; -} - -.alert { - color: red; -} - -.fieldWithErrors { - padding: 2px; - background-color: red; - display: table; -} - -#errorExplanation { - width: 400px; - border: 2px solid red; - padding: 7px; - padding-bottom: 12px; - margin-bottom: 20px; - background-color: #f0f0f0; -} - -#errorExplanation h2 { - text-align: left; - font-weight: bold; - padding: 5px 5px 5px 15px; - font-size: 12px; - margin: -7px; - background-color: #c00; - color: #fff; -} - -#errorExplanation p { - color: #333; - margin-bottom: 0; - padding: 5px; -} - -#errorExplanation ul li { - font-size: 12px; - list-style: square; -} diff --git a/railties/lib/rails/generators/rails/scaffold/scaffold_generator.rb b/railties/lib/rails/generators/rails/scaffold/scaffold_generator.rb index bd156f399c..779f933785 100644 --- a/railties/lib/rails/generators/rails/scaffold/scaffold_generator.rb +++ b/railties/lib/rails/generators/rails/scaffold/scaffold_generator.rb @@ -7,6 +7,7 @@ module Rails remove_class_option :actions hook_for :scaffold_controller, :required => true + hook_for :stylesheets end end end diff --git a/railties/lib/rails/generators/rails/stylesheets/USAGE b/railties/lib/rails/generators/rails/stylesheets/USAGE new file mode 100644 index 0000000000..59e5495d0b --- /dev/null +++ b/railties/lib/rails/generators/rails/stylesheets/USAGE @@ -0,0 +1,5 @@ +Description: + Copies scaffold stylesheets to public/stylesheets/. + +Examples: + `rails generate stylesheets` diff --git a/railties/lib/rails/generators/rails/stylesheets/stylesheets_generator.rb b/railties/lib/rails/generators/rails/stylesheets/stylesheets_generator.rb new file mode 100644 index 0000000000..ce68443c39 --- /dev/null +++ b/railties/lib/rails/generators/rails/stylesheets/stylesheets_generator.rb @@ -0,0 +1,9 @@ +module Rails + module Generators + class StylesheetsGenerator < Base + def copy_stylesheets_file + template "scaffold.css", "public/stylesheets/scaffold.css" if behavior == :invoke + end + end + end +end diff --git a/railties/lib/rails/generators/rails/stylesheets/templates/scaffold.css b/railties/lib/rails/generators/rails/stylesheets/templates/scaffold.css new file mode 100644 index 0000000000..ea3dc9b8b5 --- /dev/null +++ b/railties/lib/rails/generators/rails/stylesheets/templates/scaffold.css @@ -0,0 +1,65 @@ +body { background-color: #fff; color: #333; } + +body, 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; } +a:visited { color: #666; } +a:hover { color: #fff; background-color:#000; } + +div.field, div.actions { + margin-bottom: 10px; +} + +.notice { + color: green; +} + +.alert { + color: red; +} + +.fieldWithErrors { + padding: 2px; + background-color: red; + display: table; +} + +#errorExplanation { + width: 400px; + border: 2px solid red; + padding: 7px; + padding-bottom: 12px; + margin-bottom: 20px; + background-color: #f0f0f0; +} + +#errorExplanation h2 { + text-align: left; + font-weight: bold; + padding: 5px 5px 5px 15px; + font-size: 12px; + margin: -7px; + background-color: #c00; + color: #fff; +} + +#errorExplanation p { + color: #333; + margin-bottom: 0; + padding: 5px; +} + +#errorExplanation ul li { + font-size: 12px; + list-style: square; +} diff --git a/railties/test/generators/scaffold_controller_generator_test.rb b/railties/test/generators/scaffold_controller_generator_test.rb index f5af137ced..8040b22fe6 100644 --- a/railties/test/generators/scaffold_controller_generator_test.rb +++ b/railties/test/generators/scaffold_controller_generator_test.rb @@ -66,6 +66,7 @@ class ScaffoldControllerGeneratorTest < Rails::Generators::TestCase new show ).each { |view| assert_file "app/views/users/#{view}.html.erb" } + assert_no_file "app/views/layouts/users.html.erb" end def test_functional_tests diff --git a/railties/test/generators/scaffold_generator_test.rb b/railties/test/generators/scaffold_generator_test.rb index 3cad65f503..e8e622fe5c 100644 --- a/railties/test/generators/scaffold_generator_test.rb +++ b/railties/test/generators/scaffold_generator_test.rb @@ -70,10 +70,14 @@ class ScaffoldGeneratorTest < Rails::Generators::TestCase show _form ).each { |view| assert_file "app/views/product_lines/#{view}.html.erb" } + assert_no_file "app/views/layouts/product_lines.html.erb" # Helpers assert_file "app/helpers/product_lines_helper.rb" assert_file "test/unit/helpers/product_lines_helper_test.rb" + + # Stylesheets + assert_file "public/stylesheets/scaffold.css" end def test_scaffold_on_revoke @@ -97,9 +101,13 @@ class ScaffoldGeneratorTest < Rails::Generators::TestCase # Views assert_no_file "app/views/product_lines" + assert_no_file "app/views/layouts/product_lines.html.erb" # Helpers assert_no_file "app/helpers/product_lines_helper.rb" assert_no_file "test/unit/helpers/product_lines_helper_test.rb" + + # Stylesheets (should not be removed) + assert_file "public/stylesheets/scaffold.css" end end diff --git a/railties/test/generators/stylesheets_generator_test.rb b/railties/test/generators/stylesheets_generator_test.rb new file mode 100644 index 0000000000..aaeb686daa --- /dev/null +++ b/railties/test/generators/stylesheets_generator_test.rb @@ -0,0 +1,17 @@ +require 'generators/generators_test_helper' +require 'rails/generators/rails/stylesheets/stylesheets_generator' + +class StylesheetsGeneratorTest < Rails::Generators::TestCase + include GeneratorsTestHelper + + def test_copy_stylesheets + run_generator + assert_file "public/stylesheets/scaffold.css" + end + + def test_stylesheets_are_not_deleted_on_revoke + run_generator + run_generator [], :behavior => :revoke + assert_file "public/stylesheets/scaffold.css" + end +end -- cgit v1.2.3 From ad22017bdcc77793f9103eb01ebb6b4232206b72 Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Fri, 9 Apr 2010 10:26:49 -0700 Subject: Use thor shorthand for indicating that application.html.erb is a template --- railties/lib/rails/generators/rails/app/app_generator.rb | 7 +------ .../rails/app/templates/app/views/layouts/.empty_directory | 0 .../app/templates/app/views/layouts/application.html.erb | 14 -------------- .../templates/app/views/layouts/application.html.erb.tt | 14 ++++++++++++++ 4 files changed, 15 insertions(+), 20 deletions(-) delete mode 100644 railties/lib/rails/generators/rails/app/templates/app/views/layouts/.empty_directory delete mode 100644 railties/lib/rails/generators/rails/app/templates/app/views/layouts/application.html.erb create mode 100644 railties/lib/rails/generators/rails/app/templates/app/views/layouts/application.html.erb.tt diff --git a/railties/lib/rails/generators/rails/app/app_generator.rb b/railties/lib/rails/generators/rails/app/app_generator.rb index 192792d078..bb2a080286 100644 --- a/railties/lib/rails/generators/rails/app/app_generator.rb +++ b/railties/lib/rails/generators/rails/app/app_generator.rb @@ -78,12 +78,7 @@ module Rails::Generators end def create_app_files - directory "app/controllers" - directory "app/helpers" - directory "app/models" - inside "app/views/layouts" do - template "application.html.erb" - end + directory 'app' end def create_config_files diff --git a/railties/lib/rails/generators/rails/app/templates/app/views/layouts/.empty_directory b/railties/lib/rails/generators/rails/app/templates/app/views/layouts/.empty_directory deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/railties/lib/rails/generators/rails/app/templates/app/views/layouts/application.html.erb b/railties/lib/rails/generators/rails/app/templates/app/views/layouts/application.html.erb deleted file mode 100644 index 1dd112b4a6..0000000000 --- a/railties/lib/rails/generators/rails/app/templates/app/views/layouts/application.html.erb +++ /dev/null @@ -1,14 +0,0 @@ - - - - <%= app_const_base %> - <%%= stylesheet_link_tag :all %> - <%%= javascript_include_tag :defaults %> - <%%= csrf_meta_tag %> - - - -<%%= yield %> - - - diff --git a/railties/lib/rails/generators/rails/app/templates/app/views/layouts/application.html.erb.tt b/railties/lib/rails/generators/rails/app/templates/app/views/layouts/application.html.erb.tt new file mode 100644 index 0000000000..1dd112b4a6 --- /dev/null +++ b/railties/lib/rails/generators/rails/app/templates/app/views/layouts/application.html.erb.tt @@ -0,0 +1,14 @@ + + + + <%= app_const_base %> + <%%= stylesheet_link_tag :all %> + <%%= javascript_include_tag :defaults %> + <%%= csrf_meta_tag %> + + + +<%%= yield %> + + + -- cgit v1.2.3 From e416f1d0ab71e3e720e147e5d0e7f6e8b36516a5 Mon Sep 17 00:00:00 2001 From: Norman Clarke Date: Wed, 7 Apr 2010 16:21:41 -0300 Subject: Make tidy_bytes work on 1.9 and improve its performance. [#4350 state:resolved] Signed-off-by: Jeremy Kemper --- activesupport/CHANGELOG | 5 ++ .../lib/active_support/multibyte/chars.rb | 85 +++++++++++++++++----- activesupport/test/multibyte_chars_test.rb | 73 ++++++++++++------- 3 files changed, 119 insertions(+), 44 deletions(-) diff --git a/activesupport/CHANGELOG b/activesupport/CHANGELOG index b9f565c71d..a5a7a9b904 100644 --- a/activesupport/CHANGELOG +++ b/activesupport/CHANGELOG @@ -1,3 +1,8 @@ +*Rails 3.0.0 [beta 3] (pending)* + +* Speed up and add Ruby 1.9 support for ActiveSupport::Multibyte::Chars#tidy_bytes. #4350 [Norman Clarke] + + *Rails 3.0.0 [beta 2] (April 1st, 2010)* * Reduced load time by deferring configuration of classes using diff --git a/activesupport/lib/active_support/multibyte/chars.rb b/activesupport/lib/active_support/multibyte/chars.rb index 3eb0bf31f8..38007fd4e7 100644 --- a/activesupport/lib/active_support/multibyte/chars.rb +++ b/activesupport/lib/active_support/multibyte/chars.rb @@ -19,7 +19,7 @@ module ActiveSupport #:nodoc: # bad.explicit_checking_method "T".mb_chars.downcase.to_s # # The default Chars implementation assumes that the encoding of the string is UTF-8, if you want to handle different - # encodings you can write your own multibyte string handler and configure it through + # encodings you can write your own multibyte string handler and configure it through # ActiveSupport::Multibyte.proxy_class. # # class CharsForUTF32 @@ -458,8 +458,10 @@ module ActiveSupport #:nodoc: end # Replaces all ISO-8859-1 or CP1252 characters by their UTF-8 equivalent resulting in a valid UTF-8 string. - def tidy_bytes - chars(self.class.tidy_bytes(@wrapped_string)) + # + # Passing +true+ will forcibly tidy all bytes, assuming that the string's encoding is entirely CP1252 or ISO-8859-1. + def tidy_bytes(force = false) + chars(self.class.tidy_bytes(@wrapped_string, force)) end %w(lstrip rstrip strip reverse upcase downcase tidy_bytes capitalize).each do |method| @@ -528,7 +530,7 @@ module ActiveSupport #:nodoc: unpacked << codepoints[marker..pos-1] marker = pos end - end + end unpacked end @@ -644,33 +646,80 @@ module ActiveSupport #:nodoc: codepoints end + def tidy_byte(byte) + if byte < 160 + [UCD.cp1252[byte] || byte].pack("U").unpack("C*") + elsif byte < 192 + [194, byte] + else + [195, byte - 64] + end + end + private :tidy_byte + # Replaces all ISO-8859-1 or CP1252 characters by their UTF-8 equivalent resulting in a valid UTF-8 string. - def tidy_bytes(string) - string.split(//u).map do |c| - c.force_encoding(Encoding::ASCII) if c.respond_to?(:force_encoding) - - if !ActiveSupport::Multibyte::VALID_CHARACTER['UTF-8'].match(c) - n = c.unpack('C')[0] - n < 128 ? n.chr : - n < 160 ? [UCD.cp1252[n] || n].pack('U') : - n < 192 ? "\xC2" + n.chr : "\xC3" + (n-64).chr + # + # Passing +true+ will forcibly tidy all bytes, assuming that the string's encoding is entirely CP-1252 or ISO-8859-1. + def tidy_bytes(string, force = false) + if force + return string.unpack("C*").map do |b| + tidy_byte(b) + end.flatten.compact.pack("C*").unpack("U*").pack("U*") + end + + bytes = string.unpack("C*") + conts_expected = 0 + last_lead = 0 + + bytes.each_index do |i| + + byte = bytes[i] + is_ascii = byte < 128 + is_cont = byte > 127 && byte < 192 + is_lead = byte > 191 && byte < 245 + is_unused = byte > 240 + is_restricted = byte > 244 + + # Impossible or highly unlikely byte? Clean it. + if is_unused || is_restricted + bytes[i] = tidy_byte(byte) + elsif is_cont + # Not expecting contination byte? Clean up. Otherwise, now expect one less. + conts_expected == 0 ? bytes[i] = tidy_byte(byte) : conts_expected -= 1 else - c + if conts_expected > 0 + # Expected continuation, but got ASCII or leading? Clean backwards up to + # the leading byte. + (1..(i - last_lead)).each {|j| bytes[i - j] = tidy_byte(bytes[i - j])} + conts_expected = 0 + end + if is_lead + # Final byte is leading? Clean it. + if i == bytes.length - 1 + bytes[i] = tidy_byte(bytes.last) + else + # Valid leading byte? Expect continuations determined by position of + # first zero bit, with max of 3. + conts_expected = byte < 224 ? 1 : byte < 240 ? 2 : 3 + last_lead = i + end + end end - end.join + end + bytes.empty? ? "" : bytes.flatten.compact.pack("C*").unpack("U*").pack("U*") end end protected - + def translate_offset(byte_offset) #:nodoc: return nil if byte_offset.nil? return 0 if @wrapped_string == '' - + if @wrapped_string.respond_to?(:force_encoding) @wrapped_string = @wrapped_string.dup.force_encoding(Encoding::ASCII_8BIT) end - + begin @wrapped_string[0...byte_offset].unpack('U*').length rescue ArgumentError => e diff --git a/activesupport/test/multibyte_chars_test.rb b/activesupport/test/multibyte_chars_test.rb index 0e489c10e1..1b8d13c024 100644 --- a/activesupport/test/multibyte_chars_test.rb +++ b/activesupport/test/multibyte_chars_test.rb @@ -107,7 +107,7 @@ class MultibyteCharsUTF8BehaviourTest < Test::Unit::TestCase # Ruby 1.9 only supports basic whitespace @whitespace = "\n\t ".force_encoding(Encoding::UTF_8) end - + @byte_order_mark = [65279].pack('U') end @@ -468,14 +468,6 @@ end class MultibyteCharsExtrasTest < Test::Unit::TestCase include MultibyteTestHelpers - if RUBY_VERSION >= '1.9' - def test_tidy_bytes_is_broken_on_1_9_0 - assert_raise(ArgumentError) do - assert_equal_codepoints [0xfffd].pack('U'), chars("\xef\xbf\xbd").tidy_bytes - end - end - end - def test_upcase_should_be_unicode_aware assert_equal "АБВГД\0F", chars("аБвгд\0f").upcase assert_equal 'こにちわ', chars('こにちわ').upcase @@ -504,7 +496,7 @@ class MultibyteCharsExtrasTest < Test::Unit::TestCase def test_limit_should_work_on_a_multibyte_string example = chars(UNICODE_STRING) bytesize = UNICODE_STRING.respond_to?(:bytesize) ? UNICODE_STRING.bytesize : UNICODE_STRING.size - + assert_equal UNICODE_STRING, example.limit(bytesize) assert_equal '', example.limit(0) assert_equal '', example.limit(1) @@ -531,7 +523,7 @@ class MultibyteCharsExtrasTest < Test::Unit::TestCase assert example.limit(limit).to_s.length <= limit end end - + def test_composition_exclusion_is_set_up_properly # Normalization of DEVANAGARI LETTER QA breaks when composition exclusion isn't used correctly qa = [0x915, 0x93c].pack('U*') @@ -607,28 +599,57 @@ class MultibyteCharsExtrasTest < Test::Unit::TestCase end def test_tidy_bytes_should_tidy_bytes + + single_byte_cases = { + "\x21" => "!", # Valid ASCII byte, low + "\x41" => "A", # Valid ASCII byte, mid + "\x7E" => "~", # Valid ASCII byte, high + "\x80" => "€", # Continuation byte, low (cp125) + "\x94" => "”", # Continuation byte, mid (cp125) + "\x9F" => "Ÿ", # Continuation byte, high (cp125) + "\xC0" => "À", # Overlong encoding, start of 2-byte sequence, but codepoint < 128 + "\xC1" => "Á", # Overlong encoding, start of 2-byte sequence, but codepoint < 128 + "\xC2" => "Â", # Start of 2-byte sequence, low + "\xC8" => "È", # Start of 2-byte sequence, mid + "\xDF" => "ß", # Start of 2-byte sequence, high + "\xE0" => "à", # Start of 3-byte sequence, low + "\xE8" => "è", # Start of 3-byte sequence, mid + "\xEF" => "ï", # Start of 3-byte sequence, high + "\xF0" => "ð", # Start of 4-byte sequence + "\xF1" => "ñ", # Unused byte + "\xFF" => "ÿ", # Restricted byte + "\x00" => "\x00" # null char + } + + single_byte_cases.each do |bad, good| + assert_equal good, chars(bad).tidy_bytes.to_s + assert_equal "#{good}#{good}", chars("#{bad}#{bad}").tidy_bytes + assert_equal "#{good}#{good}#{good}", chars("#{bad}#{bad}#{bad}").tidy_bytes + assert_equal "#{good}a", chars("#{bad}a").tidy_bytes + assert_equal "#{good}á", chars("#{bad}á").tidy_bytes + assert_equal "a#{good}a", chars("a#{bad}a").tidy_bytes + assert_equal "á#{good}á", chars("á#{bad}á").tidy_bytes + assert_equal "a#{good}", chars("a#{bad}").tidy_bytes + assert_equal "á#{good}", chars("á#{bad}").tidy_bytes + end + byte_string = "\270\236\010\210\245" tidy_string = [0xb8, 0x17e, 0x8, 0x2c6, 0xa5].pack('U*') - ascii_padding = 'aa' - utf8_padding = 'éé' - assert_equal_codepoints tidy_string, chars(byte_string).tidy_bytes - - assert_equal_codepoints ascii_padding.dup.insert(1, tidy_string), - chars(ascii_padding.dup.insert(1, byte_string)).tidy_bytes - assert_equal_codepoints utf8_padding.dup.insert(2, tidy_string), - chars(utf8_padding.dup.insert(2, byte_string)).tidy_bytes assert_nothing_raised { chars(byte_string).tidy_bytes.to_s.unpack('U*') } - assert_equal_codepoints "\xC3\xA7", chars("\xE7").tidy_bytes # iso_8859_1: small c cedilla - assert_equal_codepoints "\xE2\x80\x9C", chars("\x93").tidy_bytes # win_1252: left smart quote - assert_equal_codepoints "\xE2\x82\xAC", chars("\x80").tidy_bytes # win_1252: euro - assert_equal_codepoints "\x00", chars("\x00").tidy_bytes # null char - assert_equal_codepoints [0xfffd].pack('U'), chars("\xef\xbf\xbd").tidy_bytes # invalid char - rescue ArgumentError => e - raise e if RUBY_VERSION < '1.9' + # UTF-8 leading byte followed by too few continuation bytes + assert_equal_codepoints "\xc3\xb0\xc2\xa5\xc2\xa4\x21", chars("\xf0\xa5\xa4\x21").tidy_bytes + end + + def test_tidy_bytes_should_forcibly_tidy_bytes_if_specified + byte_string = "\xF0\xA5\xA4\xA4" # valid as both CP-1252 and UTF-8, but with different interpretations. + assert_not_equal "𥤤", chars(byte_string).tidy_bytes + # Forcible conversion to UTF-8 + assert_equal "𥤤", chars(byte_string).tidy_bytes(true) end + private def string_from_classes(classes) -- cgit v1.2.3 From 915a0ac420b986b0f7e9b392e1641d7149545b08 Mon Sep 17 00:00:00 2001 From: David Heinemeier Hansson Date: Fri, 9 Apr 2010 10:40:01 -0700 Subject: Notice/alert are out of the layout, so notice has to go back into show to make it work for scaffolding --- railties/lib/rails/generators/erb/scaffold/templates/show.html.erb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/railties/lib/rails/generators/erb/scaffold/templates/show.html.erb b/railties/lib/rails/generators/erb/scaffold/templates/show.html.erb index 24f13fc0f8..06b1365d20 100644 --- a/railties/lib/rails/generators/erb/scaffold/templates/show.html.erb +++ b/railties/lib/rails/generators/erb/scaffold/templates/show.html.erb @@ -1,3 +1,5 @@ +

<%= notice %>

+ <% for attribute in attributes -%>

<%= attribute.human_name %>: -- cgit v1.2.3 From 00ff3ba56f0e41a2f257a2d0f54f0037016f31cd Mon Sep 17 00:00:00 2001 From: David Heinemeier Hansson Date: Fri, 9 Apr 2010 10:52:28 -0700 Subject: Need a double escape there --- railties/lib/rails/generators/erb/scaffold/templates/show.html.erb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/railties/lib/rails/generators/erb/scaffold/templates/show.html.erb b/railties/lib/rails/generators/erb/scaffold/templates/show.html.erb index 06b1365d20..4dd2e6bf8c 100644 --- a/railties/lib/rails/generators/erb/scaffold/templates/show.html.erb +++ b/railties/lib/rails/generators/erb/scaffold/templates/show.html.erb @@ -1,4 +1,4 @@ -

<%= notice %>

+

<%%= notice %>

<% for attribute in attributes -%>

-- cgit v1.2.3 From 38f1d3543e1342f99913a5e578b57a8f633a11af Mon Sep 17 00:00:00 2001 From: David Heinemeier Hansson Date: Fri, 9 Apr 2010 11:05:26 -0700 Subject: Stray carrier returns --- actionpack/lib/action_view/helpers/form_options_helper.rb | 2 -- 1 file changed, 2 deletions(-) diff --git a/actionpack/lib/action_view/helpers/form_options_helper.rb b/actionpack/lib/action_view/helpers/form_options_helper.rb index 11c6351bd3..105f4565e6 100644 --- a/actionpack/lib/action_view/helpers/form_options_helper.rb +++ b/actionpack/lib/action_view/helpers/form_options_helper.rb @@ -217,8 +217,6 @@ module ActionView InstanceTag.new(object, method, self, options.delete(:object)).to_grouped_collection_select_tag(collection, group_method, group_label_method, option_key_method, option_value_method, options, html_options) end - - # Return select and option tags for the given object and method, using # #time_zone_options_for_select to generate the list of option tags. # -- cgit v1.2.3 From 8b2266a8dada979d72ff6eda4349a24be3b630eb Mon Sep 17 00:00:00 2001 From: Xavier Noria Date: Fri, 9 Apr 2010 11:09:55 -0700 Subject: image_path -> path_to_image in a couple of places, plus motivation for path_to_image in rdoc --- .../lib/action_view/helpers/asset_tag_helper.rb | 23 ++++++++++++---------- .../lib/action_view/helpers/form_tag_helper.rb | 2 +- 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/actionpack/lib/action_view/helpers/asset_tag_helper.rb b/actionpack/lib/action_view/helpers/asset_tag_helper.rb index 85401ad561..563d9ec319 100644 --- a/actionpack/lib/action_view/helpers/asset_tag_helper.rb +++ b/actionpack/lib/action_view/helpers/asset_tag_helper.rb @@ -515,7 +515,7 @@ module ActionView # # <%= favicon_link_tag 'favicon.ico' %> # - # That's passed to +image_path+ as is, so it gives + # That's passed to +path_to_image+ as is, so it gives # # # @@ -531,20 +531,23 @@ module ActionView tag('link', { :rel => 'shortcut icon', :type => 'image/vnd.microsoft.icon', - :href => image_path(source) + :href => path_to_image(source) }.merge(options.symbolize_keys)) end # Computes the path to an image asset in the public images directory. # Full paths from the document root will be passed through. - # Used internally by +image_tag+ to build the image path. + # Used internally by +image_tag+ to build the image path: # - # ==== Examples - # image_path("edit") # => /images/edit - # image_path("edit.png") # => /images/edit.png - # image_path("icons/edit.png") # => /images/icons/edit.png - # image_path("/icons/edit.png") # => /icons/edit.png - # image_path("http://www.railsapplication.com/img/edit.png") # => http://www.railsapplication.com/img/edit.png + # image_path("edit") # => "/images/edit" + # image_path("edit.png") # => "/images/edit.png" + # image_path("icons/edit.png") # => "/images/icons/edit.png" + # image_path("/icons/edit.png") # => "/icons/edit.png" + # image_path("http://www.railsapplication.com/img/edit.png") # => "http://www.railsapplication.com/img/edit.png" + # + # If you have images as application resources this method may conflict with their named routes. + # The alias +path_to_image+ is provided to avoid that. Rails uses the alias internally, and + # plugin authors are encouraged to do so. def image_path(source) compute_public_path(source, 'images') end @@ -624,7 +627,7 @@ module ActionView end if mouseover = options.delete(:mouseover) - options[:onmouseover] = "this.src='#{image_path(mouseover)}'" + options[:onmouseover] = "this.src='#{path_to_image(mouseover)}'" options[:onmouseout] = "this.src='#{src}'" end diff --git a/actionpack/lib/action_view/helpers/form_tag_helper.rb b/actionpack/lib/action_view/helpers/form_tag_helper.rb index 388d6813ef..b840f77fb5 100644 --- a/actionpack/lib/action_view/helpers/form_tag_helper.rb +++ b/actionpack/lib/action_view/helpers/form_tag_helper.rb @@ -398,7 +398,7 @@ module ActionView # Displays an image which when clicked will submit the form. # - # source is passed to AssetTagHelper#image_path + # source is passed to AssetTagHelper#path_to_image # # ==== Options # * :confirm => 'question?' - This will add a JavaScript confirm -- cgit v1.2.3 From 13e00ce6064fd1ce143071e3531e65f64047b013 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Fri, 9 Apr 2010 15:56:50 -0300 Subject: fix stack trace lines on class_eval MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: José Valim --- actionpack/lib/action_controller/polymorphic_routes.rb | 2 +- actionpack/lib/action_view/helpers/form_helper.rb | 4 ++-- actionpack/test/template/form_helper_test.rb | 4 ++-- activemodel/lib/active_model/attribute_methods.rb | 4 ++-- activemodel/lib/active_model/callbacks.rb | 6 +++--- .../lib/active_record/attribute_methods/time_zone_conversion.rb | 8 ++++---- activerecord/lib/active_record/base.rb | 8 ++++---- .../lib/active_record/connection_adapters/abstract/query_cache.rb | 2 +- activeresource/lib/active_resource/base.rb | 4 ++-- activeresource/lib/active_resource/http_mock.rb | 4 ++-- activesupport/lib/active_support/cache/strategy/local_cache.rb | 4 ++-- activesupport/lib/active_support/callbacks.rb | 2 +- activesupport/lib/active_support/core_ext/module/aliasing.rb | 2 +- .../active_support/core_ext/module/attr_accessor_with_default.rb | 2 +- .../lib/active_support/core_ext/module/synchronization.rb | 2 +- 15 files changed, 29 insertions(+), 29 deletions(-) diff --git a/actionpack/lib/action_controller/polymorphic_routes.rb b/actionpack/lib/action_controller/polymorphic_routes.rb index ae363e300c..7f2eb4306b 100644 --- a/actionpack/lib/action_controller/polymorphic_routes.rb +++ b/actionpack/lib/action_controller/polymorphic_routes.rb @@ -120,7 +120,7 @@ module ActionController end %w(edit new).each do |action| - module_eval <<-EOT, __FILE__, __LINE__ + module_eval <<-EOT, __FILE__, __LINE__ + 1 def #{action}_polymorphic_url(record_or_hash, options = {}) # def edit_polymorphic_url(record_or_hash, options = {}) polymorphic_url( # polymorphic_url( record_or_hash, # record_or_hash, diff --git a/actionpack/lib/action_view/helpers/form_helper.rb b/actionpack/lib/action_view/helpers/form_helper.rb index fc02d959d4..c0e84ce225 100644 --- a/actionpack/lib/action_view/helpers/form_helper.rb +++ b/actionpack/lib/action_view/helpers/form_helper.rb @@ -1105,7 +1105,7 @@ module ActionView end (field_helpers - %w(label check_box radio_button fields_for hidden_field)).each do |selector| - src, file, line = <<-end_src, __FILE__, __LINE__ + 1 + src, line = <<-end_src, __LINE__ + 1 def #{selector}(method, options = {}) # def text_field(method, options = {}) @template.send( # @template.send( #{selector.inspect}, # "text_field", @@ -1114,7 +1114,7 @@ module ActionView objectify_options(options)) # objectify_options(options)) end # end end_src - class_eval src, file, line + class_eval src, __FILE__, line end def fields_for(record_or_name_or_array, *args, &block) diff --git a/actionpack/test/template/form_helper_test.rb b/actionpack/test/template/form_helper_test.rb index 64dfbde0b0..abd50a3bf9 100644 --- a/actionpack/test/template/form_helper_test.rb +++ b/actionpack/test/template/form_helper_test.rb @@ -1314,12 +1314,12 @@ class FormHelperTest < ActionView::TestCase class LabelledFormBuilder < ActionView::Helpers::FormBuilder (field_helpers - %w(hidden_field)).each do |selector| - src = <<-END_SRC + src, line = <<-END_SRC, __LINE__ + 1 def #{selector}(field, *args, &proc) (" " + super + "
").html_safe end END_SRC - class_eval src, __FILE__, __LINE__ + class_eval src, __FILE__, line end end diff --git a/activemodel/lib/active_model/attribute_methods.rb b/activemodel/lib/active_model/attribute_methods.rb index f04829ef09..b7c368ad8d 100644 --- a/activemodel/lib/active_model/attribute_methods.rb +++ b/activemodel/lib/active_model/attribute_methods.rb @@ -221,7 +221,7 @@ module ActiveModel def alias_attribute(new_name, old_name) attribute_method_matchers.each do |matcher| - module_eval <<-STR, __FILE__, __LINE__+1 + module_eval <<-STR, __FILE__, __LINE__ + 1 def #{matcher.method_name(new_name)}(*args) send(:#{matcher.method_name(old_name)}, *args) end @@ -265,7 +265,7 @@ module ActiveModel else method_name = matcher.method_name(attr_name) - generated_attribute_methods.module_eval <<-STR, __FILE__, __LINE__+1 + generated_attribute_methods.module_eval <<-STR, __FILE__, __LINE__ + 1 if method_defined?(:#{method_name}) undef :#{method_name} end diff --git a/activemodel/lib/active_model/callbacks.rb b/activemodel/lib/active_model/callbacks.rb index d4e98de57b..ad12600d7c 100644 --- a/activemodel/lib/active_model/callbacks.rb +++ b/activemodel/lib/active_model/callbacks.rb @@ -105,7 +105,7 @@ module ActiveModel end def _define_before_model_callback(klass, callback) #:nodoc: - klass.class_eval <<-CALLBACK, __FILE__, __LINE__ + klass.class_eval <<-CALLBACK, __FILE__, __LINE__ + 1 def self.before_#{callback}(*args, &block) set_callback(:#{callback}, :before, *args, &block) end @@ -113,7 +113,7 @@ module ActiveModel end def _define_around_model_callback(klass, callback) #:nodoc: - klass.class_eval <<-CALLBACK, __FILE__, __LINE__ + klass.class_eval <<-CALLBACK, __FILE__, __LINE__ + 1 def self.around_#{callback}(*args, &block) set_callback(:#{callback}, :around, *args, &block) end @@ -121,7 +121,7 @@ module ActiveModel end def _define_after_model_callback(klass, callback) #:nodoc: - klass.class_eval <<-CALLBACK, __FILE__, __LINE__ + klass.class_eval <<-CALLBACK, __FILE__, __LINE__ + 1 def self.after_#{callback}(*args, &block) options = args.extract_options! options[:prepend] = true diff --git a/activerecord/lib/active_record/attribute_methods/time_zone_conversion.rb b/activerecord/lib/active_record/attribute_methods/time_zone_conversion.rb index a8e3e28a7a..783d61383b 100644 --- a/activerecord/lib/active_record/attribute_methods/time_zone_conversion.rb +++ b/activerecord/lib/active_record/attribute_methods/time_zone_conversion.rb @@ -17,7 +17,7 @@ module ActiveRecord # This enhanced read method automatically converts the UTC time stored in the database to the time zone stored in Time.zone. def define_method_attribute(attr_name) if create_time_zone_conversion_attribute?(attr_name, columns_hash[attr_name]) - method_body = <<-EOV + method_body, line = <<-EOV, __LINE__ + 1 def #{attr_name}(reload = false) cached = @attributes_cache['#{attr_name}'] return cached if cached && !reload @@ -25,7 +25,7 @@ module ActiveRecord @attributes_cache['#{attr_name}'] = time.acts_like?(:time) ? time.in_time_zone : time end EOV - generated_attribute_methods.module_eval(method_body, __FILE__, __LINE__) + generated_attribute_methods.module_eval(method_body, __FILE__, line) else super end @@ -35,7 +35,7 @@ module ActiveRecord # This enhanced write method will automatically convert the time passed to it to the zone stored in Time.zone. def define_method_attribute=(attr_name) if create_time_zone_conversion_attribute?(attr_name, columns_hash[attr_name]) - method_body = <<-EOV + method_body, line = <<-EOV, __LINE__ + 1 def #{attr_name}=(time) unless time.acts_like?(:time) time = time.is_a?(String) ? Time.zone.parse(time) : time.to_time rescue time @@ -44,7 +44,7 @@ module ActiveRecord write_attribute(:#{attr_name}, time) end EOV - generated_attribute_methods.module_eval(method_body, __FILE__, __LINE__) + generated_attribute_methods.module_eval(method_body, __FILE__, line) else super end diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb index 2df1024a1b..d544c48a4c 100755 --- a/activerecord/lib/active_record/base.rb +++ b/activerecord/lib/active_record/base.rb @@ -1134,7 +1134,7 @@ module ActiveRecord #:nodoc: attribute_names = match.attribute_names super unless all_attributes_exists?(attribute_names) if match.scope? - self.class_eval %{ + self.class_eval <<-METHOD, __FILE__, __LINE__ + 1 def self.#{method_id}(*args) # def self.scoped_by_user_name_and_password(*args) options = args.extract_options! # options = args.extract_options! attributes = construct_attributes_from_arguments( # attributes = construct_attributes_from_arguments( @@ -1143,7 +1143,7 @@ module ActiveRecord #:nodoc: # scoped(:conditions => attributes) # scoped(:conditions => attributes) end # end - }, __FILE__, __LINE__ + METHOD send(method_id, *arguments) end else @@ -1314,9 +1314,9 @@ module ActiveRecord #:nodoc: modularized_name = type_name_with_module(type_name) silence_warnings do begin - class_eval(modularized_name, __FILE__, __LINE__) + class_eval(modularized_name, __FILE__) rescue NameError - class_eval(type_name, __FILE__, __LINE__) + class_eval(type_name, __FILE__) end end end diff --git a/activerecord/lib/active_record/connection_adapters/abstract/query_cache.rb b/activerecord/lib/active_record/connection_adapters/abstract/query_cache.rb index 1e095110f2..e5d100b51b 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/query_cache.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/query_cache.rb @@ -15,7 +15,7 @@ module ActiveRecord def dirties_query_cache(base, *method_names) method_names.each do |method_name| - base.class_eval <<-end_code, __FILE__, __LINE__ + base.class_eval <<-end_code, __FILE__, __LINE__ + 1 def #{method_name}_with_query_dirty(*args) # def update_with_query_dirty(*args) clear_query_cache if @query_cache_enabled # clear_query_cache if @query_cache_enabled #{method_name}_without_query_dirty(*args) # update_without_query_dirty(*args) diff --git a/activeresource/lib/active_resource/base.rb b/activeresource/lib/active_resource/base.rb index 1e81fc099c..1dd5af8098 100644 --- a/activeresource/lib/active_resource/base.rb +++ b/activeresource/lib/active_resource/base.rb @@ -588,11 +588,11 @@ module ActiveResource @prefix_parameters = nil # Redefine the new methods. - code = <<-end_code + code, line = <<-end_code, __LINE__ + 1 def prefix_source() "#{value}" end def prefix(options={}) "#{prefix_call}" end end_code - silence_warnings { instance_eval code, __FILE__, __LINE__ } + silence_warnings { instance_eval code, __FILE__, line } rescue logger.error "Couldn't set prefix: #{$!}\n #{code}" if logger raise diff --git a/activeresource/lib/active_resource/http_mock.rb b/activeresource/lib/active_resource/http_mock.rb index e5891300a6..1ed3804017 100644 --- a/activeresource/lib/active_resource/http_mock.rb +++ b/activeresource/lib/active_resource/http_mock.rb @@ -57,7 +57,7 @@ module ActiveResource # def post(path, request_headers = {}, body = nil, status = 200, response_headers = {}) # @responses[Request.new(:post, path, nil, request_headers)] = Response.new(body || "", status, response_headers) # end - module_eval <<-EOE, __FILE__, __LINE__ + module_eval <<-EOE, __FILE__, __LINE__ + 1 def #{method}(path, request_headers = {}, body = nil, status = 200, response_headers = {}) @responses << [Request.new(:#{method}, path, nil, request_headers), Response.new(body || "", status, response_headers)] end @@ -125,7 +125,7 @@ module ActiveResource # self.class.requests << request # self.class.responses.assoc(request).try(:second) || raise(InvalidRequestError.new("No response recorded for #{request}")) # end - module_eval <<-EOE, __FILE__, __LINE__ + module_eval <<-EOE, __FILE__, __LINE__ + 1 def #{method}(path, #{'body, ' if has_body}headers) request = ActiveResource::Request.new(:#{method}, path, #{has_body ? 'body, ' : 'nil, '}headers) self.class.requests << request diff --git a/activesupport/lib/active_support/cache/strategy/local_cache.rb b/activesupport/lib/active_support/cache/strategy/local_cache.rb index 86c7703c27..1bbcaab302 100644 --- a/activesupport/lib/active_support/cache/strategy/local_cache.rb +++ b/activesupport/lib/active_support/cache/strategy/local_cache.rb @@ -18,8 +18,8 @@ module ActiveSupport def middleware @middleware ||= begin klass = Class.new - klass.class_eval(<<-EOS, __FILE__, __LINE__) - def initialize(app) + klass.class_eval(<<-EOS, __FILE__, __LINE__ + 1) + def initialize(app @app = app end diff --git a/activesupport/lib/active_support/callbacks.rb b/activesupport/lib/active_support/callbacks.rb index c669630e47..5a7b94ead7 100644 --- a/activesupport/lib/active_support/callbacks.rb +++ b/activesupport/lib/active_support/callbacks.rb @@ -387,7 +387,7 @@ module ActiveSupport send("_update_#{symbol}_superclass_callbacks") body = send("_#{symbol}_callbacks").compile(nil) - body, line = <<-RUBY_EVAL, __LINE__ + body, line = <<-RUBY_EVAL, __LINE__ + 1 def _run_#{symbol}_callbacks(key = nil, &blk) if self.class.send("_update_#{symbol}_superclass_callbacks") self.class.__define_runner(#{symbol.inspect}) diff --git a/activesupport/lib/active_support/core_ext/module/aliasing.rb b/activesupport/lib/active_support/core_ext/module/aliasing.rb index 3cad164148..ce481f0e84 100644 --- a/activesupport/lib/active_support/core_ext/module/aliasing.rb +++ b/activesupport/lib/active_support/core_ext/module/aliasing.rb @@ -61,7 +61,7 @@ class Module # e.subject = "Megastars" # e.title # => "Megastars" def alias_attribute(new_name, old_name) - module_eval <<-STR, __FILE__, __LINE__+1 + module_eval <<-STR, __FILE__, __LINE__ + 1 def #{new_name}; self.#{old_name}; end # def subject; self.title; end def #{new_name}?; self.#{old_name}?; end # def subject?; self.title?; end def #{new_name}=(v); self.#{old_name} = v; end # def subject=(v); self.title = v; end diff --git a/activesupport/lib/active_support/core_ext/module/attr_accessor_with_default.rb b/activesupport/lib/active_support/core_ext/module/attr_accessor_with_default.rb index 4d0198f028..28ac89dab9 100644 --- a/activesupport/lib/active_support/core_ext/module/attr_accessor_with_default.rb +++ b/activesupport/lib/active_support/core_ext/module/attr_accessor_with_default.rb @@ -21,7 +21,7 @@ class Module def attr_accessor_with_default(sym, default = nil, &block) raise 'Default value or block required' unless !default.nil? || block define_method(sym, block_given? ? block : Proc.new { default }) - module_eval(<<-EVAL, __FILE__, __LINE__) + module_eval(<<-EVAL, __FILE__, __LINE__ + 1) def #{sym}=(value) # def age=(value) class << self; attr_reader :#{sym} end # class << self; attr_reader :age end @#{sym} = value # @age = value diff --git a/activesupport/lib/active_support/core_ext/module/synchronization.rb b/activesupport/lib/active_support/core_ext/module/synchronization.rb index 115b8abd4e..de76a069d6 100644 --- a/activesupport/lib/active_support/core_ext/module/synchronization.rb +++ b/activesupport/lib/active_support/core_ext/module/synchronization.rb @@ -28,7 +28,7 @@ class Module raise ArgumentError, "#{method} is already synchronized. Double synchronization is not currently supported." end - module_eval(<<-EOS, __FILE__, __LINE__) + module_eval(<<-EOS, __FILE__, __LINE__ + 1) def #{aliased_method}_with_synchronization#{punctuation}(*args, &block) # def expire_with_synchronization(*args, &block) #{with}.synchronize do # @@lock.synchronize do #{aliased_method}_without_synchronization#{punctuation}(*args, &block) # expire_without_synchronization(*args, &block) -- cgit v1.2.3 From c09744bec9c606593535f42d50487d7d02cab504 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Fri, 9 Apr 2010 17:59:19 -0300 Subject: Fixed method sign error MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: José Valim --- activesupport/lib/active_support/cache/strategy/local_cache.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/activesupport/lib/active_support/cache/strategy/local_cache.rb b/activesupport/lib/active_support/cache/strategy/local_cache.rb index 1bbcaab302..bbbd643736 100644 --- a/activesupport/lib/active_support/cache/strategy/local_cache.rb +++ b/activesupport/lib/active_support/cache/strategy/local_cache.rb @@ -19,7 +19,7 @@ module ActiveSupport @middleware ||= begin klass = Class.new klass.class_eval(<<-EOS, __FILE__, __LINE__ + 1) - def initialize(app + def initialize(app) @app = app end -- cgit v1.2.3 From e77a0311e59048f9f11cfda0ce976a93f4629122 Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Fri, 9 Apr 2010 19:33:42 -0700 Subject: Refactor for readability --- activesupport/lib/active_support/ordered_hash.rb | 54 +++++++++++------------- 1 file changed, 24 insertions(+), 30 deletions(-) diff --git a/activesupport/lib/active_support/ordered_hash.rb b/activesupport/lib/active_support/ordered_hash.rb index 57ead35827..e1a2866863 100644 --- a/activesupport/lib/active_support/ordered_hash.rb +++ b/activesupport/lib/active_support/ordered_hash.rb @@ -1,13 +1,28 @@ require 'yaml' +YAML.add_builtin_type("omap") do |type, val| + ActiveSupport::OrderedHash[val.map(&:to_a).map(&:first)] +end + # OrderedHash is namespaced to prevent conflicts with other implementations module ActiveSupport - # Hash is ordered in Ruby 1.9! - if RUBY_VERSION >= '1.9' - class OrderedHash < ::Hash #:nodoc: + class OrderedHash < ::Hash #:nodoc: + def to_yaml_type + "!tag:yaml.org,2002:omap" end - else - class OrderedHash < Hash #:nodoc: + + def to_yaml(opts = {}) + YAML.quick_emit(self, opts) do |out| + out.seq(taguri, to_yaml_style) do |seq| + each do |k, v| + seq.add(k => v) + end + end + end + end + + # Hash is ordered in Ruby 1.9! + if RUBY_VERSION < '1.9' def initialize(*args, &block) super @keys = [] @@ -55,7 +70,7 @@ module ActiveSupport end super end - + def delete_if super sync_keys! @@ -134,31 +149,10 @@ module ActiveSupport "#" end - private - - def sync_keys! - @keys.delete_if {|k| !has_key?(k)} - end - end - end - - class OrderedHash #:nodoc: - def to_yaml_type - "!tag:yaml.org,2002:omap" - end - - def to_yaml(opts = {}) - YAML.quick_emit(self, opts) do |out| - out.seq(taguri, to_yaml_style) do |seq| - each do |k, v| - seq.add(k => v) - end + private + def sync_keys! + @keys.delete_if {|k| !has_key?(k)} end - end end end - - YAML.add_builtin_type("omap") do |type, val| - ActiveSupport::OrderedHash[val.map(&:to_a).map(&:first)] - end end -- cgit v1.2.3 From ac0280c39dab272710c25d54810b21c10fff9c52 Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Fri, 9 Apr 2010 21:48:35 -0700 Subject: Routes can be selectively namespaced by path or controller module --- actionpack/CHANGELOG | 19 ++++++++++++++++++- actionpack/lib/action_dispatch/routing/mapper.rb | 17 +++++++++++++++-- actionpack/test/dispatch/routing_test.rb | 24 ++++++++++++++++++++++++ 3 files changed, 57 insertions(+), 3 deletions(-) diff --git a/actionpack/CHANGELOG b/actionpack/CHANGELOG index 6efed4a995..9b18e43516 100644 --- a/actionpack/CHANGELOG +++ b/actionpack/CHANGELOG @@ -1,4 +1,21 @@ -*Rails 3.0.0 [Edge] (pending)* +*Rails 3.0.0 [beta 3] (pending)* + +* Routes can be selectively namespaced by path or controller module. [Jeremy Kemper] + + # /users => Admin::UsersController + namespace :controller => 'admin' do + resources :users + end + + # /admin/users => UsersController + namespace :path => 'admin' do + resources :users + end + + # /admin/users => Admin::UsersController + namespace :admin do + resources :users + end * Added #favicon_link_tag, it uses #image_path so in particular the favicon gets an asset ID [fxn] diff --git a/actionpack/lib/action_dispatch/routing/mapper.rb b/actionpack/lib/action_dispatch/routing/mapper.rb index 925e91f081..bf707f354a 100644 --- a/actionpack/lib/action_dispatch/routing/mapper.rb +++ b/actionpack/lib/action_dispatch/routing/mapper.rb @@ -323,8 +323,21 @@ module ActionDispatch scope(controller.to_sym) { yield } end - def namespace(path) - scope(path.to_s, :name_prefix => path.to_s, :controller_namespace => path.to_s) { yield } + def namespace(path_or_options) + options = + case path_or_options + when String, Symbol + path = path_or_options.to_s + { :path => path, + :name_prefix => path, + :controller_namespace => path } + when Hash + { :path => path_or_options[:path], + :controller_namespace => path_or_options[:controller] } + else + raise ArgumentError, "Unknown namespace: #{path_or_options.inspect}" + end + scope(options) { yield } end def constraints(constraints = {}) diff --git a/actionpack/test/dispatch/routing_test.rb b/actionpack/test/dispatch/routing_test.rb index 6ff478aec1..a95f93537b 100644 --- a/actionpack/test/dispatch/routing_test.rb +++ b/actionpack/test/dispatch/routing_test.rb @@ -186,6 +186,14 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest end resource :dashboard, :constraints => { :ip => /192\.168\.1\.\d{1,3}/ } + + namespace :controller => :api do + resource :token + end + + namespace :path => :api do + resource :me + end end end @@ -942,6 +950,22 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest end end + def test_controller_namespace + with_test_routes do + get '/token' + assert_equal 'api/tokens#show', @response.body + assert_equal '/token', token_path + end + end + + def test_path_namespace + with_test_routes do + get '/api/me' + assert_equal 'mes#show', @response.body + assert_equal '/api/me', me_path + end + end + private def with_test_routes yield -- cgit v1.2.3 From 561d9eff0c5702c449a2a0117ad9950ad8842dc2 Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Fri, 9 Apr 2010 22:12:06 -0700 Subject: Add test showing root match in path namespace --- actionpack/test/dispatch/routing_test.rb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/actionpack/test/dispatch/routing_test.rb b/actionpack/test/dispatch/routing_test.rb index a95f93537b..38341b5d8c 100644 --- a/actionpack/test/dispatch/routing_test.rb +++ b/actionpack/test/dispatch/routing_test.rb @@ -193,6 +193,7 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest namespace :path => :api do resource :me + match '/' => 'mes#index' end end end @@ -963,6 +964,9 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest get '/api/me' assert_equal 'mes#show', @response.body assert_equal '/api/me', me_path + + get '/api' + assert_equal 'mes#index', @response.body end end -- cgit v1.2.3 From 7353fc15957aa3b32eae8cf495701a7163cf8dbc Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Fri, 9 Apr 2010 23:09:15 -0700 Subject: Dial back from 'namespace :controller => ...' to 'scope :module => ...' --- actionpack/CHANGELOG | 18 ++++-------------- actionpack/lib/action_dispatch/routing/mapper.rb | 22 +++++----------------- actionpack/test/dispatch/routing_test.rb | 8 ++++---- 3 files changed, 13 insertions(+), 35 deletions(-) diff --git a/actionpack/CHANGELOG b/actionpack/CHANGELOG index 9b18e43516..21c6eb8c87 100644 --- a/actionpack/CHANGELOG +++ b/actionpack/CHANGELOG @@ -1,20 +1,10 @@ *Rails 3.0.0 [beta 3] (pending)* -* Routes can be selectively namespaced by path or controller module. [Jeremy Kemper] +* Routes can be scoped by controller module. [Jeremy Kemper] - # /users => Admin::UsersController - namespace :controller => 'admin' do - resources :users - end - - # /admin/users => UsersController - namespace :path => 'admin' do - resources :users - end - - # /admin/users => Admin::UsersController - namespace :admin do - resources :users + # /session => Auth::SessionsController + scope :module => 'auth' do + resource :session end * Added #favicon_link_tag, it uses #image_path so in particular the favicon gets an asset ID [fxn] diff --git a/actionpack/lib/action_dispatch/routing/mapper.rb b/actionpack/lib/action_dispatch/routing/mapper.rb index bf707f354a..61256e8df1 100644 --- a/actionpack/lib/action_dispatch/routing/mapper.rb +++ b/actionpack/lib/action_dispatch/routing/mapper.rb @@ -323,21 +323,9 @@ module ActionDispatch scope(controller.to_sym) { yield } end - def namespace(path_or_options) - options = - case path_or_options - when String, Symbol - path = path_or_options.to_s - { :path => path, - :name_prefix => path, - :controller_namespace => path } - when Hash - { :path => path_or_options[:path], - :controller_namespace => path_or_options[:controller] } - else - raise ArgumentError, "Unknown namespace: #{path_or_options.inspect}" - end - scope(options) { yield } + def namespace(path) + path = path.to_s + scope(:path => path, :name_prefix => path, :module => path) { yield } end def constraints(constraints = {}) @@ -376,12 +364,12 @@ module ActionDispatch parent ? "#{parent}_#{child}" : child end - def merge_controller_namespace_scope(parent, child) + def merge_module_scope(parent, child) parent ? "#{parent}/#{child}" : child end def merge_controller_scope(parent, child) - @scope[:controller_namespace] ? "#{@scope[:controller_namespace]}/#{child}" : child + @scope[:module] ? "#{@scope[:module]}/#{child}" : child end def merge_resources_path_names_scope(parent, child) diff --git a/actionpack/test/dispatch/routing_test.rb b/actionpack/test/dispatch/routing_test.rb index 38341b5d8c..d38c48bfd4 100644 --- a/actionpack/test/dispatch/routing_test.rb +++ b/actionpack/test/dispatch/routing_test.rb @@ -187,11 +187,11 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest resource :dashboard, :constraints => { :ip => /192\.168\.1\.\d{1,3}/ } - namespace :controller => :api do + scope :module => 'api' do resource :token end - namespace :path => :api do + scope :path => 'api' do resource :me match '/' => 'mes#index' end @@ -951,7 +951,7 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest end end - def test_controller_namespace + def test_module_scope with_test_routes do get '/token' assert_equal 'api/tokens#show', @response.body @@ -959,7 +959,7 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest end end - def test_path_namespace + def test_path_scope with_test_routes do get '/api/me' assert_equal 'mes#show', @response.body -- cgit v1.2.3 From 13bbf98d85029fd4e3563ac46413c7b72625bc25 Mon Sep 17 00:00:00 2001 From: wycats Date: Sat, 10 Apr 2010 02:56:28 -0400 Subject: Use path_names, not resource_path_names, consistently --- actionpack/lib/action_dispatch/routing/mapper.rb | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/actionpack/lib/action_dispatch/routing/mapper.rb b/actionpack/lib/action_dispatch/routing/mapper.rb index 61256e8df1..8a3f602576 100644 --- a/actionpack/lib/action_dispatch/routing/mapper.rb +++ b/actionpack/lib/action_dispatch/routing/mapper.rb @@ -372,7 +372,7 @@ module ActionDispatch @scope[:module] ? "#{@scope[:module]}/#{child}" : child end - def merge_resources_path_names_scope(parent, child) + def merge_path_names_scope(parent, child) merge_options_scope(parent, child) end @@ -521,7 +521,7 @@ module ActionDispatch def initialize(*args) #:nodoc: super - @scope[:resources_path_names] = @set.resources_path_names + @scope[:path_names] = @set.resources_path_names end def resource(*resources, &block) @@ -637,7 +637,7 @@ module ActionDispatch return self end - resources_path_names = options.delete(:path_names) + path_names = options.delete(:path_names) if args.first.is_a?(Symbol) action = args.first @@ -654,7 +654,7 @@ module ActionDispatch end else with_exclusive_name_prefix(action) do - return match("#{action_path(action, resources_path_names)}(.:format)", options.reverse_merge(:to => action)) + return match("#{action_path(action, path_names)}(.:format)", options.reverse_merge(:to => action)) end end end @@ -682,7 +682,7 @@ module ActionDispatch private def action_path(name, path_names = nil) - path_names ||= @scope[:resources_path_names] + path_names ||= @scope[:path_name] path_names[name.to_sym] || name.to_s end @@ -693,7 +693,7 @@ module ActionDispatch end if path_names = options.delete(:path_names) - scope(:resources_path_names => path_names) do + scope(:path_names => path_names) do send(method, resources.pop, options, &block) end return true -- cgit v1.2.3 From d3ec4b1ba6528a081f5124fd71cc026b1f8abe9c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Sat, 10 Apr 2010 10:47:40 +0200 Subject: Revert "Use path_names, not resource_path_names, consistently" Breaks tests on Ruby 1.8.7. This reverts commit 13bbf98d85029fd4e3563ac46413c7b72625bc25. --- actionpack/lib/action_dispatch/routing/mapper.rb | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/actionpack/lib/action_dispatch/routing/mapper.rb b/actionpack/lib/action_dispatch/routing/mapper.rb index 8a3f602576..61256e8df1 100644 --- a/actionpack/lib/action_dispatch/routing/mapper.rb +++ b/actionpack/lib/action_dispatch/routing/mapper.rb @@ -372,7 +372,7 @@ module ActionDispatch @scope[:module] ? "#{@scope[:module]}/#{child}" : child end - def merge_path_names_scope(parent, child) + def merge_resources_path_names_scope(parent, child) merge_options_scope(parent, child) end @@ -521,7 +521,7 @@ module ActionDispatch def initialize(*args) #:nodoc: super - @scope[:path_names] = @set.resources_path_names + @scope[:resources_path_names] = @set.resources_path_names end def resource(*resources, &block) @@ -637,7 +637,7 @@ module ActionDispatch return self end - path_names = options.delete(:path_names) + resources_path_names = options.delete(:path_names) if args.first.is_a?(Symbol) action = args.first @@ -654,7 +654,7 @@ module ActionDispatch end else with_exclusive_name_prefix(action) do - return match("#{action_path(action, path_names)}(.:format)", options.reverse_merge(:to => action)) + return match("#{action_path(action, resources_path_names)}(.:format)", options.reverse_merge(:to => action)) end end end @@ -682,7 +682,7 @@ module ActionDispatch private def action_path(name, path_names = nil) - path_names ||= @scope[:path_name] + path_names ||= @scope[:resources_path_names] path_names[name.to_sym] || name.to_s end @@ -693,7 +693,7 @@ module ActionDispatch end if path_names = options.delete(:path_names) - scope(:path_names => path_names) do + scope(:resources_path_names => path_names) do send(method, resources.pop, options, &block) end return true -- cgit v1.2.3 From 3401b9ba6dc4aa148b5e35cc987f243622ad61d6 Mon Sep 17 00:00:00 2001 From: wycats Date: Sat, 10 Apr 2010 04:51:41 -0400 Subject: Update the routing guide for style and to add information on new routing features --- railties/guides/assets/stylesheets/main.css | 2 +- railties/guides/source/routing.textile | 824 +++++++++++++--------------- 2 files changed, 391 insertions(+), 435 deletions(-) diff --git a/railties/guides/assets/stylesheets/main.css b/railties/guides/assets/stylesheets/main.css index 7ccae2c87e..bab0b7a9d9 100644 --- a/railties/guides/assets/stylesheets/main.css +++ b/railties/guides/assets/stylesheets/main.css @@ -437,7 +437,7 @@ div.code_container, div.important, div.caution, div.warning, div.note, div.info /* Remove bottom margin of paragraphs in special boxes, otherwise they get a spurious blank area below with the box background. */ div.important p, div.caution p, div.warning p, div.note p, div.info p { - margin-bottom: 0px; + margin-bottom: 1em; } /* Edge Badge diff --git a/railties/guides/source/routing.textile b/railties/guides/source/routing.textile index cf71e700dc..92d38c4aa7 100644 --- a/railties/guides/source/routing.textile +++ b/railties/guides/source/routing.textile @@ -2,180 +2,111 @@ h2. Rails Routing from the Outside In This guide covers the user-facing features of Rails routing. By referring to this guide, you will be able to: -* Understand the purpose of routing -* Decipher the code in +routes.rb+ -* Construct your own routes, using either the @match@ method or the preferred RESTful style -* Identify how a route will map to a controller and action +* Understand the code in +routes.rb+ +* Construct your own routes, using either the preferred resourceful style or with the @match@ method +* Identify what parameters to expect an action to receive +* Automatically create URLs using route helpers +* Use advanced techniques such as constraints and Rack endpoints endprologue. -h3. The Dual Purpose of Routing +h3. The Purpose of the Rails Router -Rails routing is a two-way piece of machinery - rather as if you could turn trees into paper, and then turn paper back into trees. Specifically, it both connects incoming HTTP requests to the code in your application's controllers, and helps you generate URLs without having to hard-code them as strings. +The Rails router recognizes URLs and dispatches them to a controller's action. It can also generate URLs, avoiding the need to hardcode URL strings in your views. h4. Connecting URLs to Code -When your Rails application receives an incoming HTTP request, say +When your Rails application receives an incoming request -

+
 GET /patients/17
-
- -the routing engine within Rails is the piece of code that dispatches the request to the appropriate spot in your application. In this case, the application would most likely end up running the +show+ action within the +patients+ controller, displaying the details of the patient whose ID is 17. - -h4. Generating URLs from Code + -Routing also works in reverse. If your application contains this code: +it asks the router to match it to a controller action. If the first matching route is -@patient = Patient.find(17) +match "/patients/:id" => "patients#show" - -<%= link_to "Patient Record", patient_path(@patient) %> - - -Then the routing engine is the piece that translates that to a link to a URL such as +http://example.com/patients/17+. By using routing in this way, you can reduce the brittleness of your application as compared to one with hard-coded URLs, and make your code easier to read and understand. - -NOTE: Patient needs to be declared as a Restful resource for this style of translation to be available. +the request is dispatched to the +patients+ controller's +show+ action with { :id => "17" } in +params+. -h3. Quick Tour of +routes.rb+ - -There are two components to routing in Rails: the routing engine itself, which is supplied as part of Rails, and the file +config/routes.rb+, which contains the actual routes that will be used by your application. Learning exactly what you can put in +routes.rb+ is the main topic of this guide, but before we dig in let's get a quick overview. - -h4. Processing the File - -In format, +routes.rb+ is nothing more than one big block sent to +ApplicationName::Application.routes.draw+. Within this block, you can have comments, but it's likely that most of your content will be individual lines of code - each line being a route in your application. You'll find five main types of content in this file: - -* RESTful Routes -* Named Routes -* Nested Routes -* Regular Routes -* Default Routes - -Each of these types of route is covered in more detail later in this guide. - -The +routes.rb+ file is processed from top to bottom when a request comes in. The request will be dispatched to the first matching route, and then proceeds to the next. If there is no matching route, then Rails returns HTTP status 404 to the caller. - -h4. RESTful Routes - -RESTful routes take advantage of the built-in REST orientation of Rails to wrap up a lot of routing information with a single declaration. A RESTful route looks like this: - - -resources :books - - -h4(#quick-tour-named-routes). Named Routes - -Named routes give you very readable links in your code, as well as handling incoming requests. Here's a typical named route: - - -match 'login' => 'sessions#new', :as => 'login' - +h4. Generating URLs from Code -If you're coming from Rails 2, this route will be equivalent to: +You can also generate routes. If your application contains this code: -map.login '/login', :controller => 'sessions', :action => 'new' +@patient = Patient.find(17) -You will also notice that +sessions#new+ is a shorthand for +:controller => 'sessions', :action => 'new'+. By declaring a named route such as this, you can use +login_path+ or +login_url+ in your controllers and views to generate the URLs for this route. A RESTful generates named routes without the need to explicitly generate a named route via +as+ key. + +<%= link_to "Patient Record", patients_path(@patient.id) %> + -h4. Nested Routes +The router will generate the path +/patients/17+. This reduces the brittleness of your view and makes your code easier to understand. -Nested routes let you declare that one resource is contained within another resource. You'll see later on how this translates to URLs and paths in your code. For example, if your application includes parts, each of which belongs to an assembly, you might have this nested route declaration: +h3. Resource Routing: the Rails Default - -resources :assemblies do - resources :parts -end - +Resource routing allows you to quickly declare all of the common routes for a given resourceful controller. Instead of declaring separate routes for your +index+, +show+, +new+, +edit+, +create+, +update+ and +destroy+ actions, a resourceful route declares them in a single line of code. -h4(#quick-tour-regular-routes). Regular Routes +h4. Resources on the Web -In many applications, you'll also see non-RESTful routing, which explicitly connects the parts of a URL to a particular action. For example, +Browsers request pages from Rails by making a request for a URL using a specific HTTP method, such as +GET+, +POST+, +PUT+ and +DELETE+. Each method is a request to perform an operation on the resource. A resource route maps a number of related request to the actions in a single controller. - -match 'parts/:number' => 'inventory#show' - +When your Rails application receives an incoming request for -h4. Default Routes + +DELETE /photos/17 + -The default route is a safety net that catches otherwise-unrouted requests. Many Rails applications will contain this default route: +it asks the router to map it to a controller action. If the first matching route is -match ':controller(/:action(/:id(.:format)))' +resources :photos -In Rails 3, this route is commented out advising to use RESTful routes as much as possible. So if you're using RESTful routing for everything in your application, you will probably want to leave it like that. - -h3. RESTful Routing: the Rails Default - -RESTful routing is the current standard for routing in Rails, and it's the one that you should prefer for new applications. It can take a little while to understand how RESTful routing works, but it's worth the effort; your code will be easier to read and you'll be working with Rails, rather than fighting against it, when you use this style of routing. - -h4. What is REST? - -The foundation of RESTful routing is generally considered to be Roy Fielding's doctoral thesis, "Architectural Styles and the Design of Network-based Software Architectures":http://www.ics.uci.edu/~fielding/pubs/dissertation/top.htm. Fortunately, you need not read this entire document to understand how REST works in Rails. REST, an acronym for Representational State Transfer, boils down to two main principles for our purposes: - -* Using resource identifiers (which, for the purposes of discussion, you can think of as URLs) to represent resources -* Transferring representations of the state of that resource between system components. - -For example, to a Rails application a request such as this: - -
-DELETE /photos/17
-
- -would be understood to refer to a photo resource with the ID of 17, and to indicate a desired action - deleting that resource. REST is a natural style for the architecture of web applications, and Rails makes it even more natural by using conventions to shield you from some of the RESTful complexities. +Rails would dispatch that request to the +destroy+ method on the +photos+ controller with { :id => "17" } in +params+. h4. CRUD, Verbs, and Actions -In Rails, a RESTful route provides a mapping between HTTP verbs, controller actions, and (implicitly) CRUD operations in a database. A single entry in the routing file, such as +In Rails, a resourceful route provides a mapping between HTTP verbs and URLs and controller actions. By convention, each action also maps to particular CRUD operations in a database. A single entry in the routing file, such as resources :photos -creates seven different routes in your application: +creates seven different routes in your application, all mapping to the +Photos+ controller: -|_.HTTP verb|_.URL |_.controller|_.action |_.used for| -|GET |/photos |Photos |index |display a list of all photos| -|GET |/photos/new |Photos |new |return an HTML form for creating a new photo| -|POST |/photos |Photos |create |create a new photo| -|GET |/photos/1 |Photos |show |display a specific photo| -|GET |/photos/1/edit |Photos |edit |return an HTML form for editing a photo| -|PUT |/photos/1 |Photos |update |update a specific photo| -|DELETE |/photos/1 |Photos |destroy |delete a specific photo| - -For the specific routes (those that reference just a single resource), the identifier for the resource will be available within the corresponding controller action as +params[:id]+. +|_. Verb |_.URL |_.action |_.used for| +|GET |/photos |index |display a list of all photos| +|GET |/photos/new |new |return an HTML form for creating a new photo| +|POST |/photos |create |create a new photo| +|GET |/photos/:id |show |display a specific photo| +|GET |/photos/:id/edit |edit |return an HTML form for editing a photo| +|PUT |/photos/:id |update |update a specific photo| +|DELETE |/photos/:id |destroy |delete a specific photo| h4. URLs and Paths -Creating a RESTful route will also make available a pile of helpers within your application, something that requires explicit mention otherwise: +Creating a resourceful route will also expose a number of helpers to the controllers in your application. In the case of +resources :photos+: -* +photos_url+ and +photos_path+ map to the path for the index and create actions -* +new_photo_url+ and +new_photo_path+ map to the path for the new action -* +edit_photo_url+ and +edit_photo_path+ map to the path for the edit action -* +photo_url+ and +photo_path+ map to the path for the show, update, and destroy actions +* +photos_path+ returns +/photos+ +* +new_photo_path+ returns +/photos/new+ +* +edit_photo_path+ returns +/photos/edit+ +* +photo_path(id)+ returns +/photos/:id+ (for instance, +photo_path(10)+ returns +/photos/10+) -NOTE: Because routing makes use of the HTTP verb as well as the path in the request to dispatch requests, the seven routes generated by a RESTful routing entry only give rise to four pairs of helpers. +Each of these helpers has a corresponding +_url+ helper (such as +photos_url+) which returns the same path prefixed with the current host, port and path prefix. -In each case, the +_url+ helper generates a string containing the entire URL that the application will understand, while the +_path+ helper generates a string containing the relative path from the root of the application. For example: - - -photos_url # => "http://www.example.com/photos" -photos_path # => "/photos" - +NOTE: Because the router uses the HTTP verb and URL to match inbound requests, four URLs map to seven different actions. h4. Defining Multiple Resources at the Same Time -If you need to create routes for more than one RESTful resource, you can save a bit of typing by defining them all with a single call to +resources+: +If you need to create routes for more than one resource, you can save a bit of typing by defining them all with a single call to +resources+: resources :photos, :books, :videos -This has exactly the same effect as +This works exactly the same as resources :photos @@ -185,205 +116,91 @@ resources :videos h4. Singular Resources -You can also apply RESTful routing to singleton resources within your application. In this case, you use +resource+ instead of +resources+ and the route generation is slightly different. For example, a routing entry of +Sometimes, you have a resource that clients always look up without referencing an ID. A common example, +/profile+ always shows the profile of the currently logged in user. In this case, you can use a singular resource to map +/profile+ (rather than +/profile/:id+) to the +show+ action. resource :geocoder -creates six different routes in your application: - -|_.HTTP verb|_.URL |_.controller|_.action |_.used for| -|GET |/geocoder/new |Geocoders |new |return an HTML form for creating the new geocoder| -|POST |/geocoder |Geocoders |create |create the new geocoder| -|GET |/geocoder |Geocoders |show |display the one and only geocoder resource| -|GET |/geocoder/edit |Geocoders |edit |return an HTML form for editing the geocoder| -|PUT |/geocoder |Geocoders |update |update the one and only geocoder resource| -|DELETE |/geocoder |Geocoders |destroy |delete the geocoder resource| - -NOTE: Even though the name of the resource is singular in +routes.rb+, the matching controller is still plural. - -A singular RESTful route generates an abbreviated set of helpers: - -* +new_geocoder_url+ and +new_geocoder_path+ map to the path for the new action -* +edit_geocoder_url+ and +edit_geocoder_path+ map to the path for the edit action -* +geocoder_url+ and +geocoder_path+ map to the path for the create, show, update, and destroy actions - -h4. Customizing Resources +creates six different routes in your application, all mapping to the +Geocoders+ controller: -Although the conventions of RESTful routing are likely to be sufficient for many applications, there are a number of ways to customize the way that RESTful routes work. These options include: +|_. Verb |_.URL |_.action |_.used for| +|GET |/geocoder/new |new |return an HTML form for creating the geocoder| +|POST |/geocoder |create |create the new geocoder| +|GET |/geocoder |show |display the one and only geocoder resource| +|GET |/geocoder/edit |edit |return an HTML form for editing the geocoder| +|PUT |/geocoder |update |update the one and only geocoder resource| +|DELETE |/geocoder |destroy |delete the geocoder resource| -* +:controller+ -* +:singular+ -* +:constraints+ -* +:as+ -* +:path_names+ -* +:only+ -* +:except+ +NOTE: Because you might want to use the same controller for a singular route (+/account+) and a plural route (+/accounts/45+), singular resources map to plural controllers. -You can also add additional routes via the +member+ and +collection+ blocks, which are discussed later in this guide. +A singular resourceful route generates these helpers: -h5. Using +:controller+ +* +new_geocoder_path+ returns +/geocoder/new+ +* +edit_geocoder_path+ returns +/geocoder/edit+ +* +geocoder_path+ returns +/geocoder+ -The +:controller+ option lets you use a controller name that is different from the public-facing resource name. For example, this routing entry: - - -resources :photos, :controller => "images" - - -will recognize incoming URLs containing +photo+ but route the requests to the Images controller: - -|_.HTTP verb|_.URL |_.controller|_.action |_.used for| -|GET |/photos |Images |index |display a list of all images| -|GET |/photos/new |Images |new |return an HTML form for creating a new image| -|POST |/photos |Images |create |create a new image| -|GET |/photos/1 |Images |show |display a specific image| -|GET |/photos/1/edit |Images |edit |return an HTML form for editing an image| -|PUT |/photos/1 |Images |update |update a specific image| -|DELETE |/photos/1 |Images |destroy |delete a specific image| - -NOTE: The helpers will be generated with the name of the resource, not the name of the controller. So in this case, you'd still get +photos_path+, +new_photo_path+, and so on. +As with plural resources, the same helpers ending in +_url+ will also include the host, port and path prefix. h4. Controller Namespaces and Routing -Rails allows you to group your controllers into namespaces by saving them in folders underneath +app/controllers+. The +:controller+ option provides a convenient way to use these routes. For example, you might have a resource whose controller is purely for admin users in the +admin+ folder: +You may wish to organize groups of controllers under a namespace. Most commonly, you might group a number of administrative controllers under an +Admin::+ namespace. You would place these controllers under the +app/controllers/admin+ directory, and you can group them together in your router: -resources :photos, :controller => "admin/photos" - - -If you use controller namespaces, you need to be aware of a subtlety in the Rails routing code: it always tries to preserve as much of the namespace from the previous request as possible. For example, if you are on a view generated from the +photo_path+ helper, and you follow a link generated with +<%= link_to "show", photo_path(1) %>+ you will end up on the view generated by +admin/photos/show+, but you will also end up in the same place if you have +<%= link_to "show", {:controller => "photos", :action => "show"} %>+ because Rails will generate the show URL relative to the current URL. - -TIP: If you want to guarantee that a link goes to a top-level controller, use a preceding slash to anchor the controller name: +<%= link_to "show", {:controller => "/photos", :action => "show"} %>+ - -You can also specify a controller namespace with the +namespace+ method instead of a path. This can be especially useful when mapping multiple namespaced routes together: - - -namespace :admin do - resources :photos, :videos +namespace "admin" do + resources :posts, :comments end -That would give you routing for +admin/photos+ and +admin/videos+ controllers. - -The difference between generating routes through +namespace+ and the +:controller+ key is that the +namespace+ will add +admin+ to the generated helpers as well, so the above route generates +admin_photos_path+. - -h5. Using +:singular+ - -If for some reason Rails isn't doing what you want in converting the plural resource name to a singular name in member routes, you can override its judgment with the +:singular+ option: - - -resources :teeth, :singular => "tooth" - - -TIP: Depending on the other code in your application, you may prefer to add additional rules to the +Inflector+ class instead. - -h5. Using +:constraints+ - -You can use the +:constraints+ option in a RESTful route to impose a format on the implied parameter in routes. For example: - - -resources :photos, :constraints => {:id => /[A-Z][A-Z][0-9]+/} - - -This declaration constrains the +:id+ parameter to match the supplied regular expression. So, in this case, +/photos/1+ would no longer be recognized by this route, but +/photos/RR27+ would. - -h5. Using +:as+ - -The +:as+ option lets you override the normal naming for the actual generated paths. For example: - - -resources :photos, :as => "images" - - -will recognize incoming URLs containing +image+ but route the requests to the Photos controller: - -|_.HTTP verb|_.URL |_.controller|_.action |_:used for| -|GET |/images |Photos |index |display a list of all photos| -|GET |/images/new |Photos |new |return an HTML form for creating a new photo| -|POST |/images |Photos |create |create a new photo| -|GET |/images/1 |Photos |show |display a specific photo| -|GET |/images/1/edit |Photos |edit |return an HTML form for editing a photo| -|PUT |/images/1 |Photos |update |update a specific photo| -|DELETE |/images/1 |Photos |destroy |delete a specific photo| +This will create a number of routes for each of the +posts+ and +comments+ controller. For +Admin::PostsController+, Rails will create: -NOTE: The helpers will be generated with the name of the resource, not the path name. So in this case, you'd still get +photos_path+, +new_photo_path+, and so on. +|_. Verb |_.URL |_.action |_. helper | +|GET |/admin/photos |index | admin_photos_path | +|GET |/admin/photos/new |new | new_admin_photos_path | +|POST |/admin/photos |create | admin_photos_path | +|GET |/admin/photos/1 |show | admin_photo_path(id) | +|GET |/admin/photos/1/edit |edit | edit_admin_photo_path(id) | +|PUT |/admin/photos/1 |update | admin_photo_path(id) | +|DELETE |/admin/photos/1 |destroy | admin_photo_path(id) | -h5. Using +:path_names+ - -The +:path_names+ option lets you override the automatically-generated "new" and "edit" segments in URLs: +If you want to route +/photos+ (without the prefix +/admin+) to +Admin::PostsController+, you could use -resources :photos, :path_names => { :new => 'make', :edit => 'change' } - - -This would cause the routing to recognize URLs such as - -
-/photos/make
-/photos/1/change
-
- -NOTE: The actual action names aren't changed by this option; the two URLs shown would still route to the new and edit actions. - -TIP: If you find yourself wanting to change this option uniformly for all of your routes, you can set a default in your environment: - - -config.action_controller.resources_path_names = { :new => 'make', :edit => 'change' } +scope :module => "admin" do + resources :posts, :comments +end -h5. Using +:name_prefix+ - -You can use the :name_prefix option to avoid collisions between routes. This is most useful when you have two resources with the same name that use +:path_prefix+ to map differently. For example: +or, for a single case -resources :photos :name_prefix => 'photographer' +resources :posts, :module => "admin" -This combination will give you route helpers such as +photographer_photos_path+ to use in your code. - -NOTE: You can also use +:name_prefix+ with non-RESTful routes. - -h5. Using +:only+ and +:except+ - -By default, Rails creates routes for all seven of the default actions (index, show, new, create, edit, update, and destroy) for every RESTful route in your application. You can use the +:only+ and +:except+ options to fine-tune this behavior. The +:only+ option specifies that only certain routes should be generated: +If you want to route +/admin/photos+ to +PostsController+ (without the +Admin::+ module prefix), you could use -resources :photos, :only => [:index, :show] - - -With this declaration, a +GET+ request to +/photos+ would succeed, but a +POST+ request to +/photos+ (which would ordinarily be routed to the create action) will fail. - -The +:except+ option specifies a route or list of routes that should _not_ be generated: - - -resources :photos, :except => :destroy +scope "/admin" do + resources :posts, :comments +end -In this case, all of the normal routes except the route for +destroy+ (a +DELETE+ request to +/photos/id+) will be generated. - -TIP: If your application has many RESTful routes, using +:only+ and +:except+ to generate only the routes that you actually need can cut down on memory use and speed up the routing process. - -h5. Changing Path Names for Resources - -Using +scope+, we can alter path names generated by resources: +or, for a single case -scope(:resources_path_names => { :new => "neu", :edit => "bearbeiten" }) do - resources :categories, :path => "kategorien" -end +resources :posts, :path => "/admin" -With +scope+ defined, it now generates routes with customized path names. +In each of these cases, the named routes remain the same as if you did not use +scope+. In the last case, the following URLs map to +PostsController+: -|_.HTTP verb|_.URL |_.controller |_.action |_:used for| -|GET |/kategorien |Categories |index |display a list of all categories| -|GET |/kategorien/neu |Categories |new |return an HTML form for creating a new category| -|POST |/kategorien |Categories |create |create a new category| -|GET |/kategorien/1 |Categories |show |display a specific category| -|GET |/kategorien/:id/bearbeiten |Categories |edit |return an HTML form for editing a category| -|PUT |/kategorien/1 |Categories |update |update a specific category| -|DELETE |/kategorien/1 |Categories |destroy |delete a specific category| +|_. Verb |_.URL |_.action |_. helper | +|GET |photos |index | photos_path | +|GET |photos/new |new | photos_path | +|POST |photos |create | photos_path | +|GET |photos/1 |show | photo_path(id) | +|GET |photos/1/edit |edit | dmin_photo_path(id) | +|PUT |photos/1 |update | photo_path(id) | +|DELETE |photos/1 |destroy | photo_path(id) | h4. Nested Resources @@ -399,7 +216,7 @@ class Ad < ActiveRecord::Base end
-Each ad is logically subservient to one magazine. Nested routes allow you to capture this relationship in your routing. In this case, you might include this route declaration: +Nested routes allow you to capture this relationship in your routing. In this case, you could include this route declaration: resources :magazines do @@ -407,31 +224,19 @@ resources :magazines do end -In addition to the routes for magazines, this declaration will also create routes for ads, each of which requires the specification of a magazine in the URL: - -|_.HTTP verb|_.URL |_.controller|_.action |_.used for| -|GET |/magazines/1/ads |Ads |index |display a list of all ads for a specific magazine| -|GET |/magazines/1/ads/new |Ads |new |return an HTML form for creating a new ad belonging to a specific magazine| -|POST |/magazines/1/ads |Ads |create |create a new ad belonging to a specific magazine| -|GET |/magazines/1/ads/1 |Ads |show |display a specific ad belonging to a specific magazine| -|GET |/magazines/1/ads/1/edit |Ads |edit |return an HTML form for editing an ad belonging to a specific magazine| -|PUT |/magazines/1/ads/1 |Ads |update |update a specific ad belonging to a specific magazine| -|DELETE |/magazines/1/ads/1 |Ads |destroy |delete a specific ad belonging to a specific magazine| - +In addition to the routes for magazines, this declaration will also route ads to an +AdsController+. The ad URLs require a magazine: -This will also create routing helpers such as +magazine_ads_url+ and +edit_magazine_ad_path+. +|_.Verb |_.URL |_.action |_.used for| +|GET |/magazines/1/ads |index |display a list of all ads for a specific magazine| +|GET |/magazines/1/ads/new |new |return an HTML form for creating a new ad belonging to a specific magazine| +|POST |/magazines/1/ads |create |create a new ad belonging to a specific magazine| +|GET |/magazines/1/ads/1 |show |display a specific ad belonging to a specific magazine| +|GET |/magazines/1/ads/1/edit |edit |return an HTML form for editing an ad belonging to a specific magazine| +|PUT |/magazines/1/ads/1 |update |update a specific ad belonging to a specific magazine| +|DELETE |/magazines/1/ads/1 |destroy |delete a specific ad belonging to a specific magazine| -h5(#nested-name-prefix). Using +:name_prefix+ - -The +:name_prefix+ option overrides the automatically-generated prefix in nested route helpers. For example, - - -resources :magazines do - resources :ads, :name_prefix => 'periodical' -end - -This will create routing helpers such as +periodical_ads_url+ and +periodical_edit_ad_path+. +This will also create routing helpers such as +magazine_ads_url+ and +edit_magazine_ad_path+. These helpers take an instance of Magazine as the first parameter (+magazine_ads_url(@magazine)+). h5. Limits to Nesting @@ -455,33 +260,9 @@ The corresponding route helper would be +publisher_magazine_photo_url+, requirin TIP: _Resources should never be nested more than 1 level deep._ -h5. Shallow Nesting +h4. Creating URLs From Objects -The +:shallow+ option provides an elegant solution to the difficulties of deeply-nested routes. If you specify this option at any level of routing, then paths for nested resources which reference a specific member (that is, those with an +:id+ parameter) will not use the parent path prefix or name prefix. To see what this means, consider this set of routes: - - -resources :publishers, :shallow => true do - resources :magazines do - resources :photos - end -end - - -This will enable recognition of (among others) these routes: - -
-/publishers/1           ==> publisher_path(1)
-/publishers/1/magazines ==> publisher_magazines_path(1)
-/magazines/2            ==> magazine_path(2)
-/magazines/2/photos     ==> magazines_photos_path(2)
-/photos/3               ==> photo_path(3)
-
- -With shallow nesting, you need only supply enough information to uniquely identify the resource that you want to work with. - -h4. Route Generation from Arrays - -In addition to using the generated routing helpers, Rails can also generate RESTful routes from an array of parameters. For example, suppose you have a set of routes generated with these entries in routes.rb: +In addition to using the routing helpers, Rails can also create URLs from an array of parameters. For example, suppose you have this set of routes: resources :magazines do @@ -489,49 +270,35 @@ resources :magazines do end -Rails will generate helpers such as magazine_ad_path that you can use in building links: +When using +magazine_ad_path+, you can pass in instances of +Magazine+ and +Ad+ instead of the numeric IDs. - + <%= link_to "Ad details", magazine_ad_path(@magazine, @ad) %> - - -Another way to refer to the same route is with an array of objects: - - -<%= link_to "Ad details", [@magazine, @ad] %> - +
-This format is especially useful when you might not know until runtime which of several types of object will be used in a particular link. +You can also use +url_for+ with a set of objects, and Rails will automatically determine which route you want: -h4. Namespaced Resources + +<%= link_to "Ad details", url_for(@magazine, @ad) %> + -It's possible to do some quite complex things by combining +scope+ and +:name_prefix+. For example, you can use the combination of these two options to move administrative resources to their own folder in your application: +In this case, Rails will see that +@magazine+ is a +Magazine+ and +@ad+ is an +Ad+ and will therefore use the +magazine_ad_path+ helper. In helpers like +link_to+, you can specify just the object in place of the full +url_for+ call: - -scope 'admin' do - resources :photos, :name_prefix => "admin", :controller => 'admin/photos' - scope 'photos' do - resources :tags, :name_prefix => 'admin_photo', :controller => 'admin/photo_tags' - resources :ratings, :name_prefix => 'admin_photo', :controller => 'admin/photo_ratings' - end -end - + +<%= link_to "Ad details", [@magazine, @ad] %> + -The good news is that if you find yourself using this level of complexity, you can stop. Rails supports _namespaced resources_ to make placing resources in their own folder a snap. Here's the namespaced version of those same three routes: +If you wanted to link to just a magazine, you could leave out the +Array+: - -namespace :admin do - resources :photos do - resources :tags, :ratings - end -end - + +<%= link_to "Magazine details", @magazine %> + -As you can see, the namespaced version is much more succinct than the one that spells everything out - but it still creates the same routes. For example, you'll get +admin_photos_url+ that expects to find an +Admin::PhotosController+ and that matches +admin/photos+, and +admin_photos_ratings_path+ that matches +/admin/photos/_photo_id_/ratings+, expecting to use +Admin::RatingsController+. Even though you're not specifying +path_prefix+ explicitly, the routing code will calculate the appropriate +path_prefix+ from the route nesting. +This allows you to treat instances of your models as URLs, and is a key advantage to using the resourceful style. h4. Adding More RESTful Actions -You are not limited to the seven routes that RESTful routing creates by default. If you like, you may add additional member routes (those which apply to a single instance of the resource), additional new routes (those that apply to creating a new resource), or additional collection routes (those which apply to the collection of resources as a whole). +You are not limited to the seven routes that RESTful routing creates by default. If you like, you may add additional routes that apply to the collection or individual members of the collection. h5. Adding Member Routes @@ -545,9 +312,9 @@ resources :photos do end -This will enable Rails to recognize URLs such as +/photos/1/preview+ using the GET HTTP verb, and route them to the preview action of the Photos controller. It will also create the +preview_photo_url+ and +preview_photo_path+ route helpers. +This will recognize +/photos/1/preview+ with GET, and route to the +preview+ action of +PhotosController+. It will also create the +preview_photo_url+ and +preview_photo_path+ helpers. -Within the block of member routes, each route name specifies the HTTP verb that it will recognize. You can use +get+, +put+, +post+, or +delete+ here. If you don't have multiple +member+ route, you can also passing +:on+ to the routing. +Within the block of member routes, each route name specifies the HTTP verb that it will recognize. You can use +get+, +put+, +post+, or +delete+ here. If you don't have multiple +member+ routes, you can also passing +:on+ to a route. resources :photos do @@ -557,7 +324,7 @@ end h5. Adding Collection Routes -To add a collection route, use the +:collection+ option: +To add a route to the collection: resources :photos do @@ -567,9 +334,9 @@ resources :photos do end -This will enable Rails to recognize URLs such as +/photos/search+ using the GET HTTP verb, and route them to the search action of the Photos controller. It will also create the +search_photos_url+ and +search_photos_path+ route helpers. +This will enable Rails to recognize URLs such as +/photos/search+ with GET, and route to the +search+ action of +PhotosController+. It will also create the +search_photos_url+ and +search_photos_path+ route helpers. -Just as with member routes, you can passing +:on+ to the routing. +Just as with member routes, you can pass +:on+ to a route. resources :photos do @@ -577,24 +344,17 @@ resources :photos do end -h5. Adding New Routes - -As of writing, Rails 3 has deprecated +:new+ option from routing. You will need to explicit define the route using +match+ method - - -resources :photos -match 'photos/new/upload' => 'photos#upload', :as => 'upload_new_photos' - - h5. A Note of Caution -If you find yourself adding many extra actions to a RESTful route, it's time to stop and ask yourself whether you're disguising the presence of another resource that would be better split off on its own. When the +member+ and +collection+ hashes become a dumping-ground, RESTful routes lose the advantage of easy readability that is one of their strongest points. +If you find yourself adding many extra actions to a resourceful route, it's time to stop and ask yourself whether you're disguising the presence of another resource. -h3. Regular Routes +h3. Non-Resourceful Routes -In addition to RESTful routing, Rails supports regular routing - a way to map URLs to controllers and actions. With regular routing, you don't get the masses of routes automatically generated by RESTful routing. Instead, you must set up each route within your application separately. +In addition to resource routing, Rails has powerful support for routing arbitrary URLs to actions. Here, you don't get groups of routes automatically generated by resourceful routing. Instead, you set up each route within your application separately. -While RESTful routing has become the Rails standard, there are still plenty of places where the simpler regular routing works fine. You can even mix the two styles within a single application. In general, you should prefer RESTful routing _when possible_, because it will make parts of your application easier to write. But there's no need to try to shoehorn every last piece of your application into a RESTful framework if that's not a good fit. +While you should usually use resourceful routing, there are still many places where the simpler routing is more appropriate. There's no need to try to shoehorn every last piece of your application into a resourceful framework if that's not a good fit. + +In particular, simple routing makes it very easy to map legacy URLs to new Rails actions. h4. Bound Parameters @@ -604,80 +364,121 @@ When you set up a regular route, you supply a series of symbols that Rails maps match ':controller(/:action(/:id))' -If an incoming request of +/photos/show/1+ is processed by this route (because it hasn't matched any previous route in the file), then the result will be to invoke the +show+ action of the +Photos+ controller, and to make the final parameter (1) available as +params[:id]+. This route will also route the incoming request of +/photos+ to PhotosController, since +:action+ and +:id+ are optional parameters, denoted by parenthesis. +If an incoming request of +/photos/show/1+ is processed by this route (because it hasn't matched any previous route in the file), then the result will be to invoke the +show+ action of the +PhotosController+, and to make the final parameter +"1"+ available as +params[:id]+. This route will also route the incoming request of +/photos+ to +PhotosController+, since +:action+ and +:id+ are optional parameters, denoted by parentheses. -h4. Wildcard Components +h4. Dynamic Segments -You can set up as many wildcard symbols within a regular route as you like. Anything other than +:controller+ or +:action+ will be available to the matching action as part of the params hash. So, if you set up this route: +You can set up as many dynamic segments within a regular route as you like. Anything other than +:controller+ or +:action+ will be available to the action as part of +params+. If you set up this route: match ':controller/:action/:id/:user_id' -An incoming URL of +/photos/show/1/2+ will be dispatched to the +show+ action of the +Photos+ controller. +params[:id]+ will be set to 1, and +params[:user_id]+ will be set to 2. +An incoming URL of +/photos/show/1/2+ will be dispatched to the +show+ action of the +PhotosController+. +params[:id]+ will be +"1"+, and +params[:user_id]+ will be +"2"+. -h4. Static Text +h4. Static Segments -You can specify static text when creating a route. In this case, the static text is used only for matching the incoming requests: +You can specify static segments when creating a route. match ':controller/:action/:id/with_user/:user_id' -This route would respond to URLs such as +/photos/show/1/with_user/2+. +This route would respond to URLs such as +/photos/show/1/with_user/2+. In this case, +params+ would be { :controller => "photos", :action => "show", :id => "1", :user_id => "2" }. -h4. Querystring Parameters +h4. The Query String -Rails routing automatically picks up querystring parameters and makes them available in the +params+ hash. For example, with this route: +The +params+ will also include any parameters from the query string. For example, with this route: match ':controller/:action/:id -An incoming URL of +/photos/show/1?user_id=2+ will be dispatched to the +show+ action of the +Photos+ controller. +params[:id]+ will be set to 1, and +params[:user_id]+ will be equal to 2. +An incoming URL of +/photos/show/1?user_id=2+ will be dispatched to the +show+ action of the +Photos+ controller. +params+ will be { :controller => "photos", :action => "show", :id => "1", :user_id => "2" }. h4. Defining Defaults -You do not need to explicitly use the +:controller+ and +:action+ symbols within a route. You can supply defaults for these two parameters by putting it after +=>+: +You do not need to explicitly use the +:controller+ and +:action+ symbols within a route. You can supply them as defaults: match 'photos/:id' => 'photos#show' -With this route, an incoming URL of +/photos/12+ would be dispatched to the +show+ action within the +Photos+ controller. +With this route, Rails will match an incoming URL of +/photos/12+ to the +show+ action of +PhotosController+. -You can also define other defaults in a route by supplying a hash for the +:defaults+ option. This even applies to parameters that are not explicitly defined elsewhere in the route. For example: +You can also define other defaults in a route by supplying a hash for the +:defaults+ option. This even applies to parameters that you do not specify as dynamic segments. For example: match 'photos/:id' => 'photos#show', :defaults => { :format => 'jpg' } -With this route, an incoming URL of +photos/12+ would be dispatched to the +show+ action within the +Photos+ controller, and +params[:format]+ will be set to +jpg+. +Rails would match +photos/12+ to the +show+ action of +PhotosController+, and set +params[:format]+ to +"jpg"+. -h4. Named Routes +h4. Naming Routes -Regular routes need not use the +connect+ method. You can use any other name here to create a _named route_. For example, +You can specify a name for any route using the +:as+ option. match 'logout' => 'sessions#destroy', :as => :logout -This will do two things. First, requests to +/logout+ will be sent to the +destroy+ action of the +Sessions+ controller. Second, Rails will maintain the +logout_path+ and +logout_url+ helpers for use within your code. +This will create +logout_path+ and +logout_url+ as named helpers in your application. Calling +logout_path+ will return +/logout+ -h4. Route Constraints +h4. Segment Constraints -You can use the +:constraints+ option to enforce a format for any parameter in a route: +You can use the +:constraints+ option to enforce a format for a dynamic segment: match 'photo/:id' => 'photos#show', :constraints => { :id => /[A-Z]\d{5}/ } -This route would respond to URLs such as +/photo/A12345+. You can more succinctly express the same route this way: +This route would match URLs such as +/photo/A12345+. You can more succinctly express the same route this way: match 'photo/:id' => 'photos#show', :id => /[A-Z]\d{5}/ +h4. Request-Based Constraints + +You can also constrain a route based on any method on the Request object that returns a +String+. + +You specify a request-based constraint the same way that you specify a segment constraint: + + +match "photo", :constraints => {:subdomain => "admin"} + + +You can also specify constrains in a block form: + + +namespace "admin" do + constraints :subdomain => "admin" do + resources :photos + end +end + + +h4. Advanced Constraints + +If you have a more advanced constraint, you can provide an object that responds to +matches?+ that Rails should use. Let's say you wanted to route all users on a blacklist to the +BlacklistController+. You could do: + + +class BlacklistConstraint + def initialize + @ips = Blacklist.retrieve_ips + end + + def matches?(request) + @ips.include?(request.remote_ip) + end +end + +TwitterClone::Application.routes.draw do + match "*path" => "blacklist#index", + :constraints => BlacklistConstraint.new +end + + h4. Route Globbing Route globbing is a way to specify that a particular parameter should be matched to all the remaining parts of a route. For example @@ -686,89 +487,244 @@ Route globbing is a way to specify that a particular parameter should be matched match 'photo/*other' => 'photos#unknown' -This route would match +photo/12+ or +/photo/long/path/to/12+ equally well, creating an array of path segments as the value of +params[:other]+. +This route would match +photo/12+ or +/photo/long/path/to/12+, setting +params[:other]+ to +"12"+ or +"long/path/to/12"+. + +h4. Redirection + +You can redirect any path to another path using the +redirect+ helper in your router: + + +match "/stories" => redirect("/posts") + + +You can also reuse dynamic segments from the match in the path to redirect to: + + +match "/stories/:name" => redirect("/posts/%{name}") + + +You can also provide a block to redirect, which receives the params and (optionally) the request object: -h3. Formats and +respond_to+ + +match "/stories/:name" => redirect {|params| "/posts/#{params[:name].pluralize}" } +match "/stories" => redirect {|p, req| "/posts/#{req.subdomain}" } + + +In all of these cases, if you don't provide the leading host (+http://www.example.com+), Rails will take those details from the current request. -There's one more way in which routing can do different things depending on differences in the incoming HTTP request: by issuing a response that corresponds to what the request specifies that it will accept. In Rails routing, you can control this with the special +:format+ parameter in the route. +h4. Routing to Rack Applications -For instance, consider the second of the default routes in the boilerplate +routes.rb+ file: +Instead of a String, like +"posts#index"+, which corresponds to the +index+ action in the +PostsController+, you can specify any Rack application as the endpoint for a matcher. -match ':controller(/:action(/:id(.:format)))' +match "/application.js" => Sprockets -This route matches requests such as +/photo/edit/1.xml+ or +/photo/show/2.rss+. Within the appropriate action code, you can issue different responses depending on the requested format: +As long as +Sprockets+ responds to +call+ and returns a [status, headers, body], the router won't know the difference between the Rack application and an action. + +NOTE: For the curious, +"posts#index"+ actually expands out to +PostsController.action(:index)+, which returns a valid Rack application. + +h4. Using +root+ + +You can specify what Rails should route +"/"+ to with the +root+ method: -respond_to do |format| - format.html # return the default template for HTML - format.xml { render :xml => @photo.to_xml } +root :to => 'pages#main' + + +You should put the +root+ route at the end of the file. + +h3. Customizing Resourceful Routes + +While the default routes and helpers generated by +resources :posts+ will usually serve you well, you may want to customize them in some way. Rails allows you to customize virtually any generic part of the resourceful helpers. + +h4. Specifying a Controller to Use + +The +:controller+ option lets you explicitly specify a controller to use for the resource. For example: + + +resources :photos, :controller => "images" + + +will recognize incoming URLs beginning with +/photo+ but route to the +Images+ controller: + +|_. Verb |_.URL |_.action | +|GET |/photos |index | +|GET |/photos/new |new | +|POST |/photos |create | +|GET |/photos/1 |show | +|GET |/photos/1/edit |edit | +|PUT |/photos/1 |update | +|DELETE |/photos/1 |destroy | + +NOTE: Use +photos_path+, +new_photos_path+, etc. to generate URLs for this resource. + +h4. Specifying Constraints + +You can use the +:constraints+ option to specify a required format on the implicit +id+. For example: + + +resources :photos, :constraints => {:id => /[A-Z][A-Z][0-9]+/} + + +This declaration constrains the +:id+ parameter to match the supplied regular expression. So, in this case, the router would no longer match +/photos/1+ to this route. Instead, +/photos/RR27+ would match. + +You can specify a single constraint to a apply to a number of routes by using the block form: + + +constraints(:id => /[A-Z][A-Z][0-9]+/) do + resources :photos + resources :accounts +end + + +NOTE: Of course, you can use the more advanced constraints available in non-resourceful routes in this context + +h4. Overriding the Named Helpers + +The +:as+ option lets you override the normal naming for the named route helpers. For example: + + +resources :photos, :as => "images" + + +will recognize incoming URLs beginning with +/photos+ and route the requests to +PhotosController+: + +|_.HTTP verb|_.URL |_.action |_.named helper | +|GET |/photos |index | images_path_ | +|GET |/photos/new |new | new_image_path | +|POST |/photos |create | images_path | +|GET |/photos/1 |show | image_path | +|GET |/photos/1/edit |edit | edit_image_path | +|PUT |/photos/1 |update | image_path | +|DELETE |/photos/1 |destroy | image_path | + +h4. Overriding the +new+ and +edit+ Segments + +The +:path_names+ option lets you override the automatically-generated "new" and "edit" segments in URLs: + + +resources :photos, :path_names => { :new => 'make', :edit => 'change' } + + +This would cause the routing to recognize URLs such as + +
+/photos/make
+/photos/1/change
+
+ +NOTE: The actual action names aren't changed by this option. The two URLs shown would still route to the new and edit actions. + +TIP: If you find yourself wanting to change this option uniformly for all of your routes, you can use a scope: + + +scope :path_names => { :new => "make" } do + # rest of your routes end -h4. Specifying the Format with an HTTP Header +h4. Overriding the Named Helper Prefix -If there is no +:format+ parameter in the route, Rails will automatically look at the HTTP Accept header to determine the desired format. +You can use the :name_prefix option to add a prefix to the named route helpers that Rails generates for a route. You can use this option to prevent collisions between routes using a path scope. -h4. Recognized MIME types + +scope "admin" do + resources :photos, :name_prefix => "admin" +end -By default, Rails recognizes +html+, +text+, +json+, +csv+, +xml+, +rss+, +atom+, and +yaml+ as acceptable response types. If you need types beyond this, you can register them in your environment: +resources :photos + + +This will provide route helpers such as +photographer_photos_path+. + +You could specify a name prefix to use for a group of routes in the scope: -Mime::Type.register "image/jpg", :jpg +scope "admin", :name_prefix => "admin" do + resources :photos, :accounts +end + +resources :photos, :accounts -h3. The Default Routes +NOTE: The +namespace+ scope will automatically add a +:name_prefix+ as well as +:module+ and +:path+ prefixes. + +h4. Restricting the Routes Created -When you create a new Rails application, +routes.rb+ is initialized with a default route: +By default, Rails creates routes for all seven of the default actions (index, show, new, create, edit, update, and destroy) for every RESTful route in your application. You can use the +:only+ and +:except+ options to fine-tune this behavior. The +:only+ option tells Rails to create only the specified routes: -match ':controller(/:action(/:id(.:format)))' +resources :photos, :only => [:index, :show] -These routes provide reasonable defaults for many URLs, if you're not using RESTful routing. +Now, a +GET+ request to +/photos+ would succeed, but a +POST+ request to +/photos+ (which would ordinarily be routed to the +create+ action) will fail. + +The +:except+ option specifies a route or list of routes that Rails should _not_ create: -NOTE: The default routes will make every action of every controller in your application accessible to GET requests. If you've designed your application to make consistent use of RESTful and named routes, you should comment out the default routes to prevent access to your controllers through the wrong verbs. If you've had the default routes enabled during development, though, you need to be sure that you haven't unwittingly depended on them somewhere in your application - otherwise you may find mysterious failures when you disable them. + +resources :photos, :except => :destroy + -h3. The Empty Route +In this case, Rails will create all of the normal routes except the route for +destroy+ (a +DELETE+ request to +/photos/:id+). -Don't confuse the default routes with the empty route. The empty route has one specific purpose: to route requests that come in to the root of the web site. For example, if your site is example.com, then requests to +http://example.com+ or +http://example.com/+ will be handled by the empty route. +TIP: If your application has many RESTful routes, using +:only+ and +:except+ to generate only the routes that you actually need can cut down on memory use and speed up the routing process. -h4. Using +root+ +h4. Translated Paths -The preferred way to set up the empty route is with the +root+ command: +Using +scope+, we can alter path names generated by resources: -root :to => 'pages#main' +scope(:path_names => { :new => "neu", :edit => "bearbeiten" }) do + resources :categories, :path => "kategorien" +end -The use of the +root+ method tells Rails that this route applies to requests for the root of the site. +Rails now creates routes to the +CategoriesControlleR+. -Because of the top-down processing of the file, the named route must be specified _before_ the call to +root+. +|_.HTTP verb|_.URL |_.action | +|GET |/kategorien |index | +|GET |/kategorien/neu |new | +|POST |/kategorien |create | +|GET |/kategorien/1 |show | +|GET |/kategorien/:id/bearbeiten |edit | +|PUT |/kategorien/1 |update | +|DELETE |/kategorien/1 |destroy | -h4. Connecting the Empty String +h4. Overriding the Singular Form -You can also specify an empty route by explicitly connecting the empty string: +If you want to customize the singular name of the route in the named helpers, you can use the +:singular+ option. -match '' => 'pages#main' +resources :teeth, :singular => "tooth" + + +TIP: If you want to define the singular form of a word for your entire application, you should add additional rules to the +Inflector+ instead. + +h4(#nested-name-prefix). Using +:name_prefix+ in Nested Resources + +The +:name_prefix+ option overrides the automatically-generated prefix for the parent resource in nested route helpers. For example, + + +resources :magazines do + resources :ads, :name_prefix => 'periodical' +end -TIP: If the empty route does not seem to be working in your application, make sure that you have deleted the file +public/index.html+ from your Rails tree. +This will create routing helpers such as +periodical_ads_url+ and +periodical_edit_ad_path+. h3. Inspecting and Testing Routes -Routing in your application should not be a "black box" that you never open. Rails offers built-in tools for both inspecting and testing routes. +Rails offers facilities for inspecting and testing your routes. h4. Seeing Existing Routes with +rake+ -If you want a complete list of all of the available routes in your application, run the +rake routes+ command. This will dump all of your routes to the console, in the same order that they appear in +routes.rb+. For each route, you'll see: +If you want a complete list of all of the available routes in your application, run +rake routes+ command. This will print all of your routes, in the same order that they appear in +routes.rb+. For each route, you'll see: * The route name (if any) * The HTTP verb used (if the route doesn't respond to all verbs) -* The URL pattern -* The routing parameters that will be generated by this URL +* The URL pattern to match +* The routing parameters for the route For example, here's a small section of the +rake routes+ output for a RESTful route: @@ -812,7 +768,7 @@ You can supply a +:method+ argument to specify the HTTP verb: assert_recognizes({ :controller => "photos", :action => "create" }, { :path => "photos", :method => :post }) -You can also use the RESTful helpers to test recognition of a RESTful route: +You can also use the resourceful helpers to test recognition of a RESTful route: assert_recognizes new_photo_url, { :path => "photos", :method => :post } -- cgit v1.2.3 From cd79a4617421f1b66e905f5da84ff28004e2bedd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Sat, 10 Apr 2010 10:53:05 +0200 Subject: Remove input, form, error_messages_for and error_message_on from the framework. If you think you will miss them, feel free to use the dynamic_form plugin available at http://github.com/rails/dynamic_form --- .../lib/action_view/helpers/active_model_helper.rb | 285 ++------------------ actionpack/lib/action_view/helpers/form_helper.rb | 8 - .../test/template/active_model_helper_i18n_test.rb | 42 --- .../test/template/active_model_helper_test.rb | 296 +-------------------- actionpack/test/template/form_helper_test.rb | 37 --- 5 files changed, 32 insertions(+), 636 deletions(-) delete mode 100644 actionpack/test/template/active_model_helper_i18n_test.rb diff --git a/actionpack/lib/action_view/helpers/active_model_helper.rb b/actionpack/lib/action_view/helpers/active_model_helper.rb index 44e193f18e..92530246a6 100644 --- a/actionpack/lib/action_view/helpers/active_model_helper.rb +++ b/actionpack/lib/action_view/helpers/active_model_helper.rb @@ -1,8 +1,6 @@ -require 'cgi' require 'action_view/helpers/form_helper' require 'active_support/core_ext/class/attribute_accessors' require 'active_support/core_ext/enumerable' -require 'active_support/core_ext/kernel/reporting' require 'active_support/core_ext/object/blank' module ActionView @@ -14,252 +12,29 @@ module ActionView end module Helpers - # The Active Record Helper makes it easier to create forms for records kept in instance variables. The most far-reaching is the +form+ - # method that creates a complete form for all the basic content types of the record (not associations or aggregations, though). This - # is a great way of making the record quickly available for editing, but likely to prove lackluster for a complicated real-world form. - # In that case, it's better to use the +input+ method and the specialized +form+ methods in link:classes/ActionView/Helpers/FormHelper.html module ActiveModelHelper - # Returns a default input tag for the type of object returned by the method. For example, if @post - # has an attribute +title+ mapped to a +VARCHAR+ column that holds "Hello World": - # - # input("post", "title") - # # => - def input(record_name, method, options = {}) - InstanceTag.new(record_name, method, self).to_tag(options) - end - - # Returns an entire form with all needed input tags for a specified Active Record object. For example, if @post - # has attributes named +title+ of type +VARCHAR+ and +body+ of type +TEXT+ then - # - # form("post") - # - # would yield a form like the following (modulus formatting): - # - #
- #

- #
- # - #

- #

- #
- # - #

- # - #
- # - # It's possible to specialize the form builder by using a different action name and by supplying another - # block renderer. For example, if @entry has an attribute +message+ of type +VARCHAR+ then - # - # form("entry", - # :action => "sign", - # :input_block => Proc.new { |record, column| - # "#{column.human_name}: #{input(record, column.name)}
" - # }) - # - # would yield a form like the following (modulus formatting): - # - #
- # Message: - #
- # - #
- # - # It's also possible to add additional content to the form by giving it a block, such as: - # - # form("entry", :action => "sign") do |form| - # form << content_tag("b", "Department") - # form << collection_select("department", "id", @departments, "id", "name") - # end - # - # The following options are available: - # - # * :action - The action used when submitting the form (default: +create+ if a new record, otherwise +update+). - # * :input_block - Specialize the output using a different block, see above. - # * :method - The method used when submitting the form (default: +post+). - # * :multipart - Whether to change the enctype of the form to "multipart/form-data", used when uploading a file (default: +false+). - # * :submit_value - The text of the submit button (default: "Create" if a new record, otherwise "Update"). - def form(record_name, options = {}) - record = instance_variable_get("@#{record_name}") - record = convert_to_model(record) - - options = options.symbolize_keys - options[:action] ||= record.persisted? ? "update" : "create" - action = url_for(:action => options[:action], :id => record) - - submit_value = options[:submit_value] || options[:action].gsub(/[^\w]/, '').capitalize - - contents = form_tag({:action => action}, :method =>(options[:method] || 'post'), :enctype => options[:multipart] ? 'multipart/form-data': nil) - contents.safe_concat hidden_field(record_name, :id) if record.persisted? - contents.safe_concat all_input_tags(record, record_name, options) - yield contents if block_given? - contents.safe_concat submit_tag(submit_value) - contents.safe_concat('') - end - - # Returns a string containing the error message attached to the +method+ on the +object+ if one exists. - # This error message is wrapped in a DIV tag by default or with :html_tag if specified, - # which can be extended to include a :prepend_text and/or :append_text (to properly explain - # the error), and a :css_class to style it accordingly. +object+ should either be the name of an - # instance variable or the actual object. The method can be passed in either as a string or a symbol. - # As an example, let's say you have a model @post that has an error message on the +title+ attribute: - # - # <%= error_message_on "post", "title" %> - # # =>
can't be empty
- # - # <%= error_message_on @post, :title %> - # # =>
can't be empty
- # - # <%= error_message_on "post", "title", - # :prepend_text => "Title simply ", - # :append_text => " (or it won't work).", - # :html_tag => "span", - # :css_class => "inputError" %> - # # => Title simply can't be empty (or it won't work). - def error_message_on(object, method, *args) - options = args.extract_options! - unless args.empty? - ActiveSupport::Deprecation.warn('error_message_on takes an option hash instead of separate ' + - 'prepend_text, append_text, html_tag, and css_class arguments', caller) - - options[:prepend_text] = args[0] || '' - options[:append_text] = args[1] || '' - options[:html_tag] = args[2] || 'div' - options[:css_class] = args[3] || 'formError' - end - options.reverse_merge!(:prepend_text => '', :append_text => '', :html_tag => 'div', :css_class => 'formError') - - object = convert_to_model(object) - - if (obj = (object.respond_to?(:errors) ? object : instance_variable_get("@#{object}"))) && - (errors = obj.errors[method]).presence - content_tag(options[:html_tag], - (options[:prepend_text].html_safe << errors.first).safe_concat(options[:append_text]), - :class => options[:css_class] - ) - else - '' - end - end - - # Returns a string with a DIV containing all of the error messages for the objects located as instance variables by the names - # given. If more than one object is specified, the errors for the objects are displayed in the order that the object names are - # provided. - # - # This DIV can be tailored by the following options: - # - # * :header_tag - Used for the header of the error div (default: "h2"). - # * :id - The id of the error div (default: "errorExplanation"). - # * :class - The class of the error div (default: "errorExplanation"). - # * :object - The object (or array of objects) for which to display errors, - # if you need to escape the instance variable convention. - # * :object_name - The object name to use in the header, or any text that you prefer. - # If :object_name is not set, the name of the first object will be used. - # * :header_message - The message in the header of the error div. Pass +nil+ - # or an empty string to avoid the header message altogether. (Default: "X errors - # prohibited this object from being saved"). - # * :message - The explanation message after the header message and before - # the error list. Pass +nil+ or an empty string to avoid the explanation message - # altogether. (Default: "There were problems with the following fields:"). - # - # To specify the display for one object, you simply provide its name as a parameter. - # For example, for the @user model: - # - # error_messages_for 'user' - # - # You can also supply an object: - # - # error_messages_for @user - # - # This will use the last part of the model name in the presentation. For instance, if - # this is a MyKlass::User object, this will use "user" as the name in the String. This - # is taken from MyKlass::User.model_name.human, which can be overridden. - # - # To specify more than one object, you simply list them; optionally, you can add an extra :object_name parameter, which - # will be the name used in the header message: - # - # error_messages_for 'user_common', 'user', :object_name => 'user' - # - # You can also use a number of objects, which will have the same naming semantics - # as a single object. - # - # error_messages_for @user, @post - # - # If the objects cannot be located as instance variables, you can add an extra :object parameter which gives the actual - # object (or array of objects to use): - # - # error_messages_for 'user', :object => @question.user - # - # NOTE: This is a pre-packaged presentation of the errors with embedded strings and a certain HTML structure. If what - # you need is significantly different from the default presentation, it makes plenty of sense to access the object.errors - # instance yourself and set it up. View the source of this method to see how easy it is. - def error_messages_for(*params) - options = params.extract_options!.symbolize_keys - - objects = Array.wrap(options.delete(:object) || params).map do |object| - object = instance_variable_get("@#{object}") unless object.respond_to?(:to_model) - object = convert_to_model(object) - - if object.class.respond_to?(:model_name) - options[:object_name] ||= object.class.model_name.human.downcase + %w(input form error_messages_for error_message_on).each do |method| + class_eval <<-RUBY, __FILE__, __LINE__ + 1 + def #{method}(*args) + ActiveSupport::Deprecation.warn "#{method} was removed from Rails and is now available as plugin. " << + "Please install it with `rails plugin install git://github.com/rails/dynamic_form.git`.", caller end + RUBY + end + end - object - end - - objects.compact! - count = objects.inject(0) {|sum, object| sum + object.errors.count } - - unless count.zero? - html = {} - [:id, :class].each do |key| - if options.include?(key) - value = options[key] - html[key] = value unless value.blank? - else - html[key] = 'errorExplanation' - end - end - options[:object_name] ||= params.first - - I18n.with_options :locale => options[:locale], :scope => [:errors, :template] do |locale| - header_message = if options.include?(:header_message) - options[:header_message] - else - locale.t :header, :count => count, :model => options[:object_name].to_s.gsub('_', ' ') - end - - message = options.include?(:message) ? options[:message] : locale.t(:body) - - error_messages = objects.sum do |object| - object.errors.full_messages.map do |msg| - content_tag(:li, msg) - end - end.join.html_safe - - contents = '' - contents << content_tag(options[:header_tag] || :h2, header_message) unless header_message.blank? - contents << content_tag(:p, message) unless message.blank? - contents << content_tag(:ul, error_messages) - - content_tag(:div, contents.html_safe, html) + module ActiveModelFormBuilder + %w(error_messages error_message_on).each do |method| + class_eval <<-RUBY, __FILE__, __LINE__ + 1 + def #{method}(*args) + ActiveSupport::Deprecation.warn "f.#{method} was removed from Rails and is now available as plugin. " << + "Please install it with `rails plugin install git://github.com/rails/dynamic_form.git`.", caller end - else - '' - end + RUBY end - - private - def all_input_tags(record, record_name, options) - input_block = options[:input_block] || default_input_block - record.class.content_columns.collect{ |column| input_block.call(record_name, column) }.join("\n") - end - - def default_input_block - Proc.new { |record, column| %(


#{input(record, column.name)}

) } - end end - module ActiveRecordInstanceTag + module ActiveModelInstanceTag def object @active_model_object ||= begin object = super @@ -267,26 +42,6 @@ module ActionView end end - def to_tag(options = {}) - case column_type - when :string - field_type = @method_name.include?("password") ? "password" : "text" - to_input_field_tag(field_type, options) - when :text - to_text_area_tag(options) - when :integer, :float, :decimal - to_input_field_tag("text", options) - when :date - to_date_select_tag(options) - when :datetime, :timestamp - to_datetime_select_tag(options) - when :time - to_time_select_tag(options) - when :boolean - to_boolean_select_tag(options) - end - end - %w(tag content_tag to_date_select_tag to_datetime_select_tag to_time_select_tag).each do |meth| module_eval "def #{meth}(*) error_wrapping(super) end" end @@ -302,14 +57,14 @@ module ActionView def error_message object.errors[@method_name] end + end - def column_type - object.send(:column_for_attribute, @method_name).type - end + class FormBuilder + include ActiveModelFormBuilder end class InstanceTag - include ActiveRecordInstanceTag + include ActiveModelInstanceTag end end end diff --git a/actionpack/lib/action_view/helpers/form_helper.rb b/actionpack/lib/action_view/helpers/form_helper.rb index c0e84ce225..a3453cc47a 100644 --- a/actionpack/lib/action_view/helpers/form_helper.rb +++ b/actionpack/lib/action_view/helpers/form_helper.rb @@ -1169,14 +1169,6 @@ module ActionView @template.hidden_field(@object_name, method, objectify_options(options)) end - def error_message_on(method, *args) - @template.error_message_on(@object, method, *args) - end - - def error_messages(options = {}) - @template.error_messages_for(@object_name, objectify_options(options)) - end - # Add the submit button for the given form. When no value is given, it checks # if the object is a new resource or not to create the proper label: # diff --git a/actionpack/test/template/active_model_helper_i18n_test.rb b/actionpack/test/template/active_model_helper_i18n_test.rb deleted file mode 100644 index 4eb2f262bd..0000000000 --- a/actionpack/test/template/active_model_helper_i18n_test.rb +++ /dev/null @@ -1,42 +0,0 @@ -require 'abstract_unit' - -class ActiveModelHelperI18nTest < Test::Unit::TestCase - include ActionView::Context - include ActionView::Helpers::ActiveModelHelper - - attr_reader :request - - def setup - @object = stub :errors => stub(:count => 1, :full_messages => ['full_messages']) - @object.stubs :to_model => @object - @object.stubs :class => stub(:model_name => stub(:human => "")) - - @object_name = 'book_seller' - @object_name_without_underscore = 'book seller' - - stubs(:content_tag).returns 'content_tag' - - I18n.stubs(:t).with(:'header', :locale => 'en', :scope => [:errors, :template], :count => 1, :model => '').returns "1 error prohibited this from being saved" - I18n.stubs(:t).with(:'body', :locale => 'en', :scope => [:errors, :template]).returns 'There were problems with the following fields:' - end - - def test_error_messages_for_given_a_header_option_it_does_not_translate_header_message - I18n.expects(:t).with(:'header', :locale => 'en', :scope => [:errors, :template], :count => 1, :model => '').never - error_messages_for(:object => @object, :header_message => 'header message', :locale => 'en') - end - - def test_error_messages_for_given_no_header_option_it_translates_header_message - I18n.expects(:t).with(:'header', :locale => 'en', :scope => [:errors, :template], :count => 1, :model => '').returns 'header message' - error_messages_for(:object => @object, :locale => 'en') - end - - def test_error_messages_for_given_a_message_option_it_does_not_translate_message - I18n.expects(:t).with(:'body', :locale => 'en', :scope => [:errors, :template]).never - error_messages_for(:object => @object, :message => 'message', :locale => 'en') - end - - def test_error_messages_for_given_no_message_option_it_translates_message - I18n.expects(:t).with(:'body', :locale => 'en', :scope => [:errors, :template]).returns 'There were problems with the following fields:' - error_messages_for(:object => @object, :locale => 'en') - end -end diff --git a/actionpack/test/template/active_model_helper_test.rb b/actionpack/test/template/active_model_helper_test.rb index 47eb620f7a..8deeb78eab 100644 --- a/actionpack/test/template/active_model_helper_test.rb +++ b/actionpack/test/template/active_model_helper_test.rb @@ -4,132 +4,25 @@ class ActiveModelHelperTest < ActionView::TestCase tests ActionView::Helpers::ActiveModelHelper silence_warnings do - class Post < Struct.new(:title, :author_name, :body, :secret, :written_on) - extend ActiveModel::Naming + class Post < Struct.new(:author_name, :body) include ActiveModel::Conversion - end - - class User < Struct.new(:email) - extend ActiveModel::Naming - include ActiveModel::Conversion - end - - class Column < Struct.new(:type, :name, :human_name) - extend ActiveModel::Naming - include ActiveModel::Conversion - end - end + include ActiveModel::Validations - class DirtyPost - class Errors - def empty? + def persisted? false end - - def count - 1 - end - - def full_messages - ["Author name can't be empty"] - end - - def [](field) - ["can't be empty"] - end - end - - def errors - Errors.new end end - def setup_post - @post = Post.new - def @post.errors - Class.new { - def [](field) - case field.to_s - when "author_name" - ["can't be empty"] - when "body" - ['foo'] - else - [] - end - end - def empty?() false end - def count() 1 end - def full_messages() [ "Author name can't be empty" ] end - }.new - end - - def @post.persisted?() false end - def @post.to_param() nil end - - def @post.column_for_attribute(attr_name) - Post.content_columns.select { |column| column.name == attr_name }.first - end - - silence_warnings do - def Post.content_columns() [ Column.new(:string, "title", "Title"), Column.new(:text, "body", "Body") ] end - end - - @post.title = "Hello World" - @post.author_name = "" - @post.body = "Back to the hill and over it again!" - @post.secret = 1 - @post.written_on = Date.new(2004, 6, 15) - end - - def setup_user - @user = User.new - def @user.errors - Class.new { - def [](field) field == "email" ? ['nonempty'] : [] end - def empty?() false end - def count() 1 end - def full_messages() [ "User email can't be empty" ] end - }.new - end - - def @user.new_record?() true end - def @user.to_param() nil end - - def @user.column_for_attribute(attr_name) - User.content_columns.select { |column| column.name == attr_name }.first - end - - silence_warnings do - def User.content_columns() [ Column.new(:string, "email", "Email") ] end - end - - @user.email = "" - end - - def protect_against_forgery? - @protect_against_forgery ? true : false - end - attr_accessor :request_forgery_protection_token, :form_authenticity_token - def setup super - setup_post - setup_user - - @response = ActionController::TestResponse.new - end - - def url_for(options) - options = options.symbolize_keys - [options[:action], options[:id].to_param].compact.join('/') - end + @post = Post.new + @post.errors[:author_name] << "can't be empty" + @post.errors[:body] << "foo" - def test_generic_input_tag - assert_dom_equal( - %(), input("post", "title") - ) + @post.author_name = "" + @post.body = "Back to the hill and over it again!" end def test_text_area_with_errors @@ -160,176 +53,11 @@ class ActiveModelHelperTest < ActionView::TestCase ActionView::Base.field_error_proc = old_proc if old_proc end - def test_form_with_string - assert_dom_equal( - %(


\n


), - form("post") - ) - - silence_warnings do - class << @post - def persisted?() true end - def to_param() id end - def id() 1 end + def test_deprecations + %w(input form error_messages_for error_message_on).each do |method| + assert_deprecated do + send(method, "post") end end - - assert_dom_equal( - %(


\n


), - form("post") - ) - end - - def test_form_with_protect_against_forgery - @protect_against_forgery = true - @request_forgery_protection_token = 'authenticity_token' - @form_authenticity_token = '123' - assert_dom_equal( - %(


\n


), - form("post") - ) - end - - def test_form_with_method_option - assert_dom_equal( - %(


\n


), - form("post", :method=>'get') - ) - end - - def test_form_with_action_option - output_buffer << form("post", :action => "sign") - assert_select "form[action=sign]" do |form| - assert_select "input[type=submit][value=Sign]" - end - end - - def test_form_with_date - silence_warnings do - def Post.content_columns() [ Column.new(:date, "written_on", "Written on") ] end - end - - assert_dom_equal( - %(


\n\n\n

), - form("post") - ) - end - - def test_form_with_datetime - silence_warnings do - def Post.content_columns() [ Column.new(:datetime, "written_on", "Written on") ] end - end - @post.written_on = Time.gm(2004, 6, 15, 16, 30) - - assert_dom_equal( - %(


\n\n\n — \n : \n

), - form("post") - ) - end - - def test_error_for_block - assert_dom_equal %(

1 error prohibited this post from being saved

There were problems with the following fields:

  • Author name can't be empty
), error_messages_for("post") - assert_equal %(

1 error prohibited this post from being saved

There were problems with the following fields:

  • Author name can't be empty
), error_messages_for("post", :class => "errorDeathByClass", :id => "errorDeathById", :header_tag => "h1") - assert_equal %(

1 error prohibited this post from being saved

There were problems with the following fields:

  • Author name can't be empty
), error_messages_for("post", :class => nil, :id => "errorDeathById", :header_tag => "h1") - assert_equal %(

1 error prohibited this post from being saved

There were problems with the following fields:

  • Author name can't be empty
), error_messages_for("post", :class => "errorDeathByClass", :id => nil, :header_tag => "h1") - end - - def test_error_messages_for_escapes_html - @dirty_post = DirtyPost.new - assert_dom_equal %(

1 error prohibited this dirty post from being saved

There were problems with the following fields:

  • Author name can't be <em>empty</em>
), error_messages_for("dirty_post") - end - - def test_error_messages_for_handles_nil - assert_equal "", error_messages_for("notthere") - end - - def test_error_message_on_escapes_html - @dirty_post = DirtyPost.new - assert_dom_equal "
can't be <em>empty</em>
", error_message_on(:dirty_post, :author_name) - end - - def test_error_message_on_handles_nil - assert_equal "", error_message_on("notthere", "notthere") - end - - def test_error_message_on - assert_dom_equal "
can't be empty
", error_message_on(:post, :author_name) - end - - def test_error_message_on_no_instance_variable - other_post = @post - assert_dom_equal "
can't be empty
", error_message_on(other_post, :author_name) - end - - def test_error_message_on_with_options_hash - assert_dom_equal "
beforecan't be emptyafter
", error_message_on(:post, :author_name, :css_class => 'differentError', :prepend_text => 'before', :append_text => 'after') - end - - def test_error_message_on_with_tag_option_in_options_hash - assert_dom_equal "beforecan't be emptyafter", error_message_on(:post, :author_name, :html_tag => "span", :css_class => 'differentError', :prepend_text => 'before', :append_text => 'after') - end - - def test_error_message_on_handles_empty_errors - assert_equal "", error_message_on(@post, :tag) - end - - def test_error_messages_for_many_objects - assert_dom_equal %(

2 errors prohibited this post from being saved

There were problems with the following fields:

  • Author name can't be empty
  • User email can't be empty
), error_messages_for("post", "user") - - # reverse the order, error order changes and so does the title - assert_dom_equal %(

2 errors prohibited this user from being saved

There were problems with the following fields:

  • User email can't be empty
  • Author name can't be empty
), error_messages_for("user", "post") - - # add the default to put post back in the title - assert_dom_equal %(

2 errors prohibited this post from being saved

There were problems with the following fields:

  • User email can't be empty
  • Author name can't be empty
), error_messages_for("user", "post", :object_name => "post") - - # symbols work as well - assert_dom_equal %(

2 errors prohibited this post from being saved

There were problems with the following fields:

  • User email can't be empty
  • Author name can't be empty
), error_messages_for(:user, :post, :object_name => :post) - - # any default works too - assert_dom_equal %(

2 errors prohibited this monkey from being saved

There were problems with the following fields:

  • User email can't be empty
  • Author name can't be empty
), error_messages_for(:user, :post, :object_name => "monkey") - - # should space object name - assert_dom_equal %(

2 errors prohibited this chunky bacon from being saved

There were problems with the following fields:

  • User email can't be empty
  • Author name can't be empty
), error_messages_for(:user, :post, :object_name => "chunky_bacon") - - # hide header and explanation messages with nil or empty string - assert_dom_equal %(
  • User email can't be empty
  • Author name can't be empty
), error_messages_for(:user, :post, :header_message => nil, :message => "") - - # override header and explanation messages - header_message = "Yikes! Some errors" - message = "Please fix the following fields and resubmit:" - assert_dom_equal %(

#{header_message}

#{message}

  • User email can't be empty
  • Author name can't be empty
), error_messages_for(:user, :post, :header_message => header_message, :message => message) - end - - def test_error_messages_for_non_instance_variable - actual_user = @user - actual_post = @post - @user = nil - @post = nil - - #explicitly set object - assert_dom_equal %(

1 error prohibited this post from being saved

There were problems with the following fields:

  • Author name can't be empty
), error_messages_for("post", :object => actual_post) - - #multiple objects - assert_dom_equal %(

2 errors prohibited this user from being saved

There were problems with the following fields:

  • User email can't be empty
  • Author name can't be empty
), error_messages_for("user", "post", :object => [actual_user, actual_post]) - - #nil object - assert_equal '', error_messages_for('user', :object => nil) - end - - def test_error_messages_for_model_objects - error = error_messages_for(@post) - assert_dom_equal %(

1 error prohibited this post from being saved

There were problems with the following fields:

  • Author name can't be empty
), - error - - error = error_messages_for(@user, @post) - assert_dom_equal %(

2 errors prohibited this user from being saved

There were problems with the following fields:

  • User email can't be empty
  • Author name can't be empty
), - error - end - - def test_form_with_string_multipart - assert_dom_equal( - %(


\n


), - form("post", :multipart => true) - ) end end diff --git a/actionpack/test/template/form_helper_test.rb b/actionpack/test/template/form_helper_test.rb index abd50a3bf9..28a13b07be 100644 --- a/actionpack/test/template/form_helper_test.rb +++ b/actionpack/test/template/form_helper_test.rb @@ -1366,43 +1366,6 @@ class FormHelperTest < ActionView::TestCase ActionView::Base.default_form_builder = old_default_form_builder end - def test_default_form_builder_with_active_record_helpers - assert_deprecated do - form_for(:post, @post) do |f| - concat f.error_message_on('author_name') - concat f.error_messages - end - end - - expected = %(
) + - %(
can't be empty
) + - %(

1 error prohibited this post from being saved

There were problems with the following fields:

  • Author name can't be empty
) + - %(
) - - assert_dom_equal expected, output_buffer - - end - - def test_default_form_builder_no_instance_variable - post = @post - @post = nil - - assert_deprecated do - form_for(:post, post) do |f| - concat f.error_message_on('author_name') - concat f.error_messages - end - end - - expected = %(
) + - %(
can't be empty
) + - %(

1 error prohibited this post from being saved

There were problems with the following fields:

  • Author name can't be empty
) + - %(
) - - assert_dom_equal expected, output_buffer - - end - def test_fields_for_with_labelled_builder output_buffer = fields_for(:post, @post, :builder => LabelledFormBuilder) do |f| concat f.text_field(:title) -- cgit v1.2.3 From 5087b831a0fa2bc102c52473743b00e5319d857c Mon Sep 17 00:00:00 2001 From: wycats Date: Sat, 10 Apr 2010 04:54:25 -0400 Subject: Updated changelog --- railties/guides/source/routing.textile | 1 + 1 file changed, 1 insertion(+) diff --git a/railties/guides/source/routing.textile b/railties/guides/source/routing.textile index 92d38c4aa7..32b1e30502 100644 --- a/railties/guides/source/routing.textile +++ b/railties/guides/source/routing.textile @@ -786,6 +786,7 @@ h3. Changelog "Lighthouse ticket":http://rails.lighthouseapp.com/projects/16213-rails-guides/tickets/3 +* April 10, 2010: Updated guide to remove outdated and superfluous information, and to provide information about new features, by "Yehuda Katz":http://www.yehudakatz.com * April 2, 2010: Updated guide to match new Routing DSL in Rails 3, by "Rizwan Reza":http://www.rizwanreza.com/ * Febuary 1, 2010: Modifies the routing documentation to match new routing DSL in Rails 3, by Prem Sichanugrist * October 4, 2008: Added additional detail on specifying verbs for resource member/collection routes, by "Mike Gunderloy":credits.html#mgunderloy -- cgit v1.2.3 From 26e05efdb6c29430c5d282870b1e236dff8465c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Sat, 10 Apr 2010 11:18:20 +0200 Subject: Remove error_messages_for from scaffold. --- .../rails/generators/erb/scaffold/templates/_form.html.erb | 11 ++++++++++- .../rails/generators/rails/stylesheets/templates/scaffold.css | 11 +++-------- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/railties/lib/rails/generators/erb/scaffold/templates/_form.html.erb b/railties/lib/rails/generators/erb/scaffold/templates/_form.html.erb index 01ec58c615..b0222b24e4 100644 --- a/railties/lib/rails/generators/erb/scaffold/templates/_form.html.erb +++ b/railties/lib/rails/generators/erb/scaffold/templates/_form.html.erb @@ -1,5 +1,14 @@ <%%= form_for(@<%= singular_name %>) do |f| %> - <%%= f.error_messages %> + <%% if @<%= singular_name %>.errors.any? %> +
+

The following errors prohibited this form from being saved:

+
    + <%% @<%= singular_name %>.errors.full_messages.each do |msg| %> +
  • <%%= msg %>
  • + <%% end %> +
+
+ <%% end %> <% for attribute in attributes -%>
diff --git a/railties/lib/rails/generators/rails/stylesheets/templates/scaffold.css b/railties/lib/rails/generators/rails/stylesheets/templates/scaffold.css index ea3dc9b8b5..f3f46d8b98 100644 --- a/railties/lib/rails/generators/rails/stylesheets/templates/scaffold.css +++ b/railties/lib/rails/generators/rails/stylesheets/templates/scaffold.css @@ -35,10 +35,10 @@ div.field, div.actions { } #errorExplanation { - width: 400px; + width: 450px; border: 2px solid red; padding: 7px; - padding-bottom: 12px; + padding-bottom: 0; margin-bottom: 20px; background-color: #f0f0f0; } @@ -49,16 +49,11 @@ div.field, div.actions { padding: 5px 5px 5px 15px; font-size: 12px; margin: -7px; + margin-bottom: 0px; background-color: #c00; color: #fff; } -#errorExplanation p { - color: #333; - margin-bottom: 0; - padding: 5px; -} - #errorExplanation ul li { font-size: 12px; list-style: square; -- cgit v1.2.3 From ece157e9504e192dcc065909c86316d520992221 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Sat, 10 Apr 2010 11:47:20 +0200 Subject: Move verification to a plugin as well: http://github.com/rails/verification.git --- actionpack/lib/action_controller.rb | 1 - actionpack/lib/action_controller/base.rb | 1 - .../lib/action_controller/deprecated/base.rb | 28 ++- .../lib/action_controller/metal/verification.rb | 130 ---------- .../lib/action_view/helpers/active_model_helper.rb | 4 +- actionpack/test/controller/verification_test.rb | 270 --------------------- 6 files changed, 21 insertions(+), 413 deletions(-) delete mode 100644 actionpack/lib/action_controller/metal/verification.rb delete mode 100644 actionpack/test/controller/verification_test.rb diff --git a/actionpack/lib/action_controller.rb b/actionpack/lib/action_controller.rb index 536154fc6b..c14393dda7 100644 --- a/actionpack/lib/action_controller.rb +++ b/actionpack/lib/action_controller.rb @@ -33,7 +33,6 @@ module ActionController autoload :Streaming autoload :Testing autoload :UrlFor - autoload :Verification end autoload :Dispatcher, 'action_controller/deprecated/dispatcher' diff --git a/actionpack/lib/action_controller/base.rb b/actionpack/lib/action_controller/base.rb index 1dfc240029..2e94a20d9d 100644 --- a/actionpack/lib/action_controller/base.rb +++ b/actionpack/lib/action_controller/base.rb @@ -30,7 +30,6 @@ module ActionController Cookies, Flash, - Verification, RequestForgeryProtection, Streaming, RecordIdentifier, diff --git a/actionpack/lib/action_controller/deprecated/base.rb b/actionpack/lib/action_controller/deprecated/base.rb index 05551ffee4..5d9cfb153a 100644 --- a/actionpack/lib/action_controller/deprecated/base.rb +++ b/actionpack/lib/action_controller/deprecated/base.rb @@ -6,15 +6,6 @@ module ActionController deprecated_config_writer(option, message) end - # This method has been moved to ActionDispatch::Request.filter_parameters - def filter_parameter_logging(*args, &block) - ActiveSupport::Deprecation.warn("Setting filter_parameter_logging in ActionController is deprecated and has no longer effect, please set 'config.filter_parameters' in config/application.rb instead", caller) - filter = Rails.application.config.filter_parameters - filter.concat(args) - filter << block if block - filter - end - def deprecated_config_reader(option, message = nil) message ||= "Reading #{option} directly from ActionController::Base is deprecated. " \ "Please read it from config.#{option}" @@ -136,6 +127,25 @@ module ActionController end end + module DeprecatedBehavior + # This method has been moved to ActionDispatch::Request.filter_parameters + def filter_parameter_logging(*args, &block) + ActiveSupport::Deprecation.warn("Setting filter_parameter_logging in ActionController is deprecated and has no longer effect, please set 'config.filter_parameters' in config/application.rb instead", caller) + filter = Rails.application.config.filter_parameters + filter.concat(args) + filter << block if block + filter + end + + # This was moved to a plugin + def verify(*args) + ActiveSupport::Deprecation.warn "verify was removed from Rails and is now available as a plugin. " << + "Please install it with `rails plugin install git://github.com/rails/verification.git`.", caller + end + end + + extend DeprecatedBehavior + deprecated_config_writer :session_store deprecated_config_writer :session_options deprecated_config_accessor :relative_url_root, "relative_url_root is ineffective. Please stop using it" diff --git a/actionpack/lib/action_controller/metal/verification.rb b/actionpack/lib/action_controller/metal/verification.rb deleted file mode 100644 index b7fc2b7421..0000000000 --- a/actionpack/lib/action_controller/metal/verification.rb +++ /dev/null @@ -1,130 +0,0 @@ -module ActionController #:nodoc: - module Verification #:nodoc: - extend ActiveSupport::Concern - - include AbstractController::Callbacks, Flash, Rendering - - # This module provides a class-level method for specifying that certain - # actions are guarded against being called without certain prerequisites - # being met. This is essentially a special kind of before_filter. - # - # An action may be guarded against being invoked without certain request - # parameters being set, or without certain session values existing. - # - # When a verification is violated, values may be inserted into the flash, and - # a specified redirection is triggered. If no specific action is configured, - # verification failures will by default result in a 400 Bad Request response. - # - # Usage: - # - # class GlobalController < ActionController::Base - # # Prevent the #update_settings action from being invoked unless - # # the 'admin_privileges' request parameter exists. The - # # settings action will be redirected to in current controller - # # if verification fails. - # verify :params => "admin_privileges", :only => :update_post, - # :redirect_to => { :action => "settings" } - # - # # Disallow a post from being updated if there was no information - # # submitted with the post, and if there is no active post in the - # # session, and if there is no "note" key in the flash. The route - # # named category_url will be redirected to if verification fails. - # - # verify :params => "post", :session => "post", "flash" => "note", - # :only => :update_post, - # :add_flash => { "alert" => "Failed to create your message" }, - # :redirect_to => :category_url - # - # Note that these prerequisites are not business rules. They do not examine - # the content of the session or the parameters. That level of validation should - # be encapsulated by your domain model or helper methods in the controller. - module ClassMethods - # Verify the given actions so that if certain prerequisites are not met, - # the user is redirected to a different action. The +options+ parameter - # is a hash consisting of the following key/value pairs: - # - # :params:: - # a single key or an array of keys that must be in the params - # hash in order for the action(s) to be safely called. - # :session:: - # a single key or an array of keys that must be in the session - # in order for the action(s) to be safely called. - # :flash:: - # a single key or an array of keys that must be in the flash in order - # for the action(s) to be safely called. - # :method:: - # a single key or an array of keys--any one of which must match the - # current request method in order for the action(s) to be safely called. - # (The key should be a symbol: :get or :post, for - # example.) - # :xhr:: - # true/false option to ensure that the request is coming from an Ajax - # call or not. - # :add_flash:: - # a hash of name/value pairs that should be merged into the session's - # flash if the prerequisites cannot be satisfied. - # :add_headers:: - # a hash of name/value pairs that should be merged into the response's - # headers hash if the prerequisites cannot be satisfied. - # :redirect_to:: - # the redirection parameters to be used when redirecting if the - # prerequisites cannot be satisfied. You can redirect either to named - # route or to the action in some controller. - # :render:: - # the render parameters to be used when the prerequisites cannot be satisfied. - # :only:: - # only apply this verification to the actions specified in the associated - # array (may also be a single value). - # :except:: - # do not apply this verification to the actions specified in the associated - # array (may also be a single value). - def verify(options={}) - before_filter :only => options[:only], :except => options[:except] do - verify_action options - end - end - end - - private - - def verify_action(options) #:nodoc: - if prereqs_invalid?(options) - flash.update(options[:add_flash]) if options[:add_flash] - response.headers.merge!(options[:add_headers]) if options[:add_headers] - apply_remaining_actions(options) unless performed? - end - end - - def prereqs_invalid?(options) # :nodoc: - verify_presence_of_keys_in_hash_flash_or_params(options) || - verify_method(options) || - verify_request_xhr_status(options) - end - - def verify_presence_of_keys_in_hash_flash_or_params(options) # :nodoc: - [*options[:params] ].find { |v| v && params[v.to_sym].nil? } || - [*options[:session]].find { |v| session[v].nil? } || - [*options[:flash] ].find { |v| flash[v].nil? } - end - - def verify_method(options) # :nodoc: - [*options[:method]].all? { |v| request.method_symbol != v.to_sym } if options[:method] - end - - def verify_request_xhr_status(options) # :nodoc: - request.xhr? != options[:xhr] unless options[:xhr].nil? - end - - def apply_redirect_to(redirect_to_option) # :nodoc: - (redirect_to_option.is_a?(Symbol) && redirect_to_option != :back) ? self.__send__(redirect_to_option) : redirect_to_option - end - - def apply_remaining_actions(options) # :nodoc: - case - when options[:render] ; render(options[:render]) - when options[:redirect_to] ; redirect_to(apply_redirect_to(options[:redirect_to])) - else head(:bad_request) - end - end - end -end diff --git a/actionpack/lib/action_view/helpers/active_model_helper.rb b/actionpack/lib/action_view/helpers/active_model_helper.rb index 92530246a6..a7650c0050 100644 --- a/actionpack/lib/action_view/helpers/active_model_helper.rb +++ b/actionpack/lib/action_view/helpers/active_model_helper.rb @@ -16,7 +16,7 @@ module ActionView %w(input form error_messages_for error_message_on).each do |method| class_eval <<-RUBY, __FILE__, __LINE__ + 1 def #{method}(*args) - ActiveSupport::Deprecation.warn "#{method} was removed from Rails and is now available as plugin. " << + ActiveSupport::Deprecation.warn "#{method} was removed from Rails and is now available as a plugin. " << "Please install it with `rails plugin install git://github.com/rails/dynamic_form.git`.", caller end RUBY @@ -27,7 +27,7 @@ module ActionView %w(error_messages error_message_on).each do |method| class_eval <<-RUBY, __FILE__, __LINE__ + 1 def #{method}(*args) - ActiveSupport::Deprecation.warn "f.#{method} was removed from Rails and is now available as plugin. " << + ActiveSupport::Deprecation.warn "f.#{method} was removed from Rails and is now available as a plugin. " << "Please install it with `rails plugin install git://github.com/rails/dynamic_form.git`.", caller end RUBY diff --git a/actionpack/test/controller/verification_test.rb b/actionpack/test/controller/verification_test.rb deleted file mode 100644 index 0600ec2ec1..0000000000 --- a/actionpack/test/controller/verification_test.rb +++ /dev/null @@ -1,270 +0,0 @@ -require 'abstract_unit' - -class VerificationTest < ActionController::TestCase - class TestController < ActionController::Base - verify :only => :guarded_one, :params => "one", - :add_flash => { :error => 'unguarded' }, - :redirect_to => { :action => "unguarded" } - - verify :only => :guarded_two, :params => %w( one two ), - :redirect_to => { :action => "unguarded" } - - verify :only => :guarded_with_flash, :params => "one", - :add_flash => { :notice => "prereqs failed" }, - :redirect_to => { :action => "unguarded" } - - verify :only => :guarded_in_session, :session => "one", - :redirect_to => { :action => "unguarded" } - - verify :only => [:multi_one, :multi_two], :session => %w( one two ), - :redirect_to => { :action => "unguarded" } - - verify :only => :guarded_by_method, :method => :post, - :redirect_to => { :action => "unguarded" } - - verify :only => :guarded_by_xhr, :xhr => true, - :redirect_to => { :action => "unguarded" } - - verify :only => :guarded_by_not_xhr, :xhr => false, - :redirect_to => { :action => "unguarded" } - - before_filter :unconditional_redirect, :only => :two_redirects - verify :only => :two_redirects, :method => :post, - :redirect_to => { :action => "unguarded" } - - verify :only => :must_be_post, :method => :post, :render => { :status => 405, :text => "Must be post" }, :add_headers => { "Allow" => "POST" } - - verify :only => :guarded_one_for_named_route_test, :params => "one", - :redirect_to => :foo_url - - verify :only => :no_default_action, :params => "santa" - - verify :only => :guarded_with_back, :method => :post, - :redirect_to => :back - - def guarded_one - render :text => "#{params[:one]}" - end - - def guarded_one_for_named_route_test - render :text => "#{params[:one]}" - end - - def guarded_with_flash - render :text => "#{params[:one]}" - end - - def guarded_two - render :text => "#{params[:one]}:#{params[:two]}" - end - - def guarded_in_session - render :text => "#{session["one"]}" - end - - def multi_one - render :text => "#{session["one"]}:#{session["two"]}" - end - - def multi_two - render :text => "#{session["two"]}:#{session["one"]}" - end - - def guarded_by_method - render :text => "#{request.method.downcase}" - end - - def guarded_by_xhr - render :text => "#{request.xhr?}" - end - - def guarded_by_not_xhr - render :text => "#{request.xhr?}" - end - - def unguarded - render :text => "#{params[:one]}" - end - - def two_redirects - render :nothing => true - end - - def must_be_post - render :text => "Was a post!" - end - - def guarded_with_back - render :text => "#{params[:one]}" - end - - def no_default_action - # Will never run - end - - protected - - def unconditional_redirect - redirect_to :action => "unguarded" - end - end - - tests TestController - - def test_using_symbol_back_with_no_referrer - assert_raise(ActionController::RedirectBackError) { get :guarded_with_back } - end - - def test_using_symbol_back_redirects_to_referrer - @request.env["HTTP_REFERER"] = "/foo" - get :guarded_with_back - assert_redirected_to '/foo' - end - - def test_no_deprecation_warning_for_named_route - assert_not_deprecated do - with_routing do |set| - set.draw do |map| - match 'foo', :to => 'test#foo', :as => :foo - match 'verification_test/:action', :to => ::VerificationTest::TestController - end - get :guarded_one_for_named_route_test, :two => "not one" - assert_redirected_to '/foo' - end - end - end - - def test_guarded_one_with_prereqs - get :guarded_one, :one => "here" - assert_equal "here", @response.body - end - - def test_guarded_one_without_prereqs - get :guarded_one - assert_redirected_to :action => "unguarded" - assert_equal 'unguarded', flash[:error] - end - - def test_guarded_with_flash_with_prereqs - get :guarded_with_flash, :one => "here" - assert_equal "here", @response.body - assert flash.empty? - end - - def test_guarded_with_flash_without_prereqs - get :guarded_with_flash - assert_redirected_to :action => "unguarded" - assert_equal "prereqs failed", flash[:notice] - end - - def test_guarded_two_with_prereqs - get :guarded_two, :one => "here", :two => "there" - assert_equal "here:there", @response.body - end - - def test_guarded_two_without_prereqs_one - get :guarded_two, :two => "there" - assert_redirected_to :action => "unguarded" - end - - def test_guarded_two_without_prereqs_two - get :guarded_two, :one => "here" - assert_redirected_to :action => "unguarded" - end - - def test_guarded_two_without_prereqs_both - get :guarded_two - assert_redirected_to :action => "unguarded" - end - - def test_unguarded_with_params - get :unguarded, :one => "here" - assert_equal "here", @response.body - end - - def test_unguarded_without_params - get :unguarded - assert @response.body.blank? - end - - def test_guarded_in_session_with_prereqs - get :guarded_in_session, {}, "one" => "here" - assert_equal "here", @response.body - end - - def test_guarded_in_session_without_prereqs - get :guarded_in_session - assert_redirected_to :action => "unguarded" - end - - def test_multi_one_with_prereqs - get :multi_one, {}, "one" => "here", "two" => "there" - assert_equal "here:there", @response.body - end - - def test_multi_one_without_prereqs - get :multi_one - assert_redirected_to :action => "unguarded" - end - - def test_multi_two_with_prereqs - get :multi_two, {}, "one" => "here", "two" => "there" - assert_equal "there:here", @response.body - end - - def test_multi_two_without_prereqs - get :multi_two - assert_redirected_to :action => "unguarded" - end - - def test_guarded_by_method_with_prereqs - post :guarded_by_method - assert_equal "post", @response.body - end - - def test_guarded_by_method_without_prereqs - get :guarded_by_method - assert_redirected_to :action => "unguarded" - end - - def test_guarded_by_xhr_with_prereqs - xhr :post, :guarded_by_xhr - assert_equal "true", @response.body - end - - def test_guarded_by_xhr_without_prereqs - get :guarded_by_xhr - assert_redirected_to :action => "unguarded" - end - - def test_guarded_by_not_xhr_with_prereqs - get :guarded_by_not_xhr - assert_equal "false", @response.body - end - - def test_guarded_by_not_xhr_without_prereqs - xhr :post, :guarded_by_not_xhr - assert_redirected_to :action => "unguarded" - end - - def test_guarded_post_and_calls_render_succeeds - post :must_be_post - assert_equal "Was a post!", @response.body - end - - def test_default_failure_should_be_a_bad_request - post :no_default_action - assert_response :bad_request - end - - def test_guarded_post_and_calls_render_fails_and_sets_allow_header - get :must_be_post - assert_response 405 - assert_equal "Must be post", @response.body - assert_equal "POST", @response.headers["Allow"] - end - - def test_second_redirect - assert_nothing_raised { get :two_redirects } - end -end -- cgit v1.2.3 From 55d159b25d2647e1f602cc60b62f39caf7a91844 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Sat, 10 Apr 2010 11:50:09 +0200 Subject: Remove error_messages_for data from locale. --- actionpack/lib/action_view/locale/en.yml | 8 -------- 1 file changed, 8 deletions(-) diff --git a/actionpack/lib/action_view/locale/en.yml b/actionpack/lib/action_view/locale/en.yml index a3e2230f6f..187e010e30 100644 --- a/actionpack/lib/action_view/locale/en.yml +++ b/actionpack/lib/action_view/locale/en.yml @@ -141,14 +141,6 @@ minute: "Minute" second: "Seconds" - errors: - template: - header: - one: "1 error prohibited this {{model}} from being saved" - other: "{{count}} errors prohibited this {{model}} from being saved" - # The variable :count is also available - body: "There were problems with the following fields:" - helpers: select: # Default value for :prompt => true in FormOptionsHelper -- cgit v1.2.3 From ee309d506c18dfac0608309d889810926f154cbb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Sat, 10 Apr 2010 12:17:34 +0200 Subject: Update versions (otherwise you install a gem from source as beta3 but internally it's beta2) and update CHANGELOG. --- actionmailer/lib/action_mailer/version.rb | 2 +- actionpack/CHANGELOG | 6 ++++++ actionpack/lib/action_pack/version.rb | 2 +- activemodel/lib/active_model/version.rb | 2 +- activerecord/lib/active_record/version.rb | 2 +- activeresource/lib/active_resource/version.rb | 2 +- activesupport/lib/active_support/version.rb | 2 +- railties/lib/rails/version.rb | 2 +- version.rb | 2 +- 9 files changed, 14 insertions(+), 8 deletions(-) diff --git a/actionmailer/lib/action_mailer/version.rb b/actionmailer/lib/action_mailer/version.rb index 5954cfcede..e66172c8d3 100644 --- a/actionmailer/lib/action_mailer/version.rb +++ b/actionmailer/lib/action_mailer/version.rb @@ -3,7 +3,7 @@ module ActionMailer MAJOR = 3 MINOR = 0 TINY = 0 - BUILD = "beta2" + BUILD = "beta3" STRING = [MAJOR, MINOR, TINY, BUILD].join('.') end diff --git a/actionpack/CHANGELOG b/actionpack/CHANGELOG index 21c6eb8c87..708683747b 100644 --- a/actionpack/CHANGELOG +++ b/actionpack/CHANGELOG @@ -1,5 +1,11 @@ *Rails 3.0.0 [beta 3] (pending)* +* Removed verify method in controllers. [JV] + It's now available as a plugin at http://github.com/rails/verification + +* Removed input, form, error_messages_for and error_message_on from views. [JV] + It's now available as a plugin at http://github.com/rails/dynamic_form + * Routes can be scoped by controller module. [Jeremy Kemper] # /session => Auth::SessionsController diff --git a/actionpack/lib/action_pack/version.rb b/actionpack/lib/action_pack/version.rb index 0b40465a79..8f0c5d939f 100644 --- a/actionpack/lib/action_pack/version.rb +++ b/actionpack/lib/action_pack/version.rb @@ -3,7 +3,7 @@ module ActionPack MAJOR = 3 MINOR = 0 TINY = 0 - BUILD = "beta2" + BUILD = "beta3" STRING = [MAJOR, MINOR, TINY, BUILD].join('.') end diff --git a/activemodel/lib/active_model/version.rb b/activemodel/lib/active_model/version.rb index a33657626f..aac47d5f81 100644 --- a/activemodel/lib/active_model/version.rb +++ b/activemodel/lib/active_model/version.rb @@ -3,7 +3,7 @@ module ActiveModel MAJOR = 3 MINOR = 0 TINY = 0 - BUILD = "beta2" + BUILD = "beta3" STRING = [MAJOR, MINOR, TINY, BUILD].join('.') end diff --git a/activerecord/lib/active_record/version.rb b/activerecord/lib/active_record/version.rb index cf78ec6e12..bf6b995a37 100644 --- a/activerecord/lib/active_record/version.rb +++ b/activerecord/lib/active_record/version.rb @@ -3,7 +3,7 @@ module ActiveRecord MAJOR = 3 MINOR = 0 TINY = 0 - BUILD = "beta2" + BUILD = "beta3" STRING = [MAJOR, MINOR, TINY, BUILD].join('.') end diff --git a/activeresource/lib/active_resource/version.rb b/activeresource/lib/active_resource/version.rb index d01ebd017f..6b9b8d3a9d 100644 --- a/activeresource/lib/active_resource/version.rb +++ b/activeresource/lib/active_resource/version.rb @@ -3,7 +3,7 @@ module ActiveResource MAJOR = 3 MINOR = 0 TINY = 0 - BUILD = "beta2" + BUILD = "beta3" STRING = [MAJOR, MINOR, TINY, BUILD].join('.') end diff --git a/activesupport/lib/active_support/version.rb b/activesupport/lib/active_support/version.rb index 3ce11e59d2..538a8b87c6 100644 --- a/activesupport/lib/active_support/version.rb +++ b/activesupport/lib/active_support/version.rb @@ -3,7 +3,7 @@ module ActiveSupport MAJOR = 3 MINOR = 0 TINY = 0 - BUILD = "beta2" + BUILD = "beta3" STRING = [MAJOR, MINOR, TINY, BUILD].join('.') end diff --git a/railties/lib/rails/version.rb b/railties/lib/rails/version.rb index 7c47cbeabd..c10876134a 100644 --- a/railties/lib/rails/version.rb +++ b/railties/lib/rails/version.rb @@ -3,7 +3,7 @@ module Rails MAJOR = 3 MINOR = 0 TINY = 0 - BUILD = "beta2" + BUILD = "beta3" STRING = [MAJOR, MINOR, TINY, BUILD].join('.') end diff --git a/version.rb b/version.rb index 7c47cbeabd..c10876134a 100644 --- a/version.rb +++ b/version.rb @@ -3,7 +3,7 @@ module Rails MAJOR = 3 MINOR = 0 TINY = 0 - BUILD = "beta2" + BUILD = "beta3" STRING = [MAJOR, MINOR, TINY, BUILD].join('.') end -- cgit v1.2.3 From 944637648c9399391c6e790740a01eeeac620a5f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Sat, 10 Apr 2010 12:45:17 +0200 Subject: Use pluralize to properly inflect the number of errors. --- railties/lib/rails/generators/erb/scaffold/templates/_form.html.erb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/railties/lib/rails/generators/erb/scaffold/templates/_form.html.erb b/railties/lib/rails/generators/erb/scaffold/templates/_form.html.erb index b0222b24e4..0615a34a85 100644 --- a/railties/lib/rails/generators/erb/scaffold/templates/_form.html.erb +++ b/railties/lib/rails/generators/erb/scaffold/templates/_form.html.erb @@ -1,7 +1,7 @@ <%%= form_for(@<%= singular_name %>) do |f| %> <%% if @<%= singular_name %>.errors.any? %>
-

The following errors prohibited this form from being saved:

+

<%%= pluralize(@<%= singular_name %>.errors.count, "error") %> prohibited this <%= singular_name %> from being saved:

    <%% @<%= singular_name %>.errors.full_messages.each do |msg| %>
  • <%%= msg %>
  • -- cgit v1.2.3 From d748cc3cd07c6931e5ebc5242f268f1f7ec3d906 Mon Sep 17 00:00:00 2001 From: Ryan Bigg Date: Sat, 10 Apr 2010 00:48:24 +1000 Subject: Re-define empty? for errors to check if the values inside the OrderedHash are empty rather than the OrderedHash itself. [#4356 state:resolved] MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: José Valim --- activemodel/lib/active_model/errors.rb | 5 +++++ activemodel/test/cases/validations_test.rb | 6 ++++++ 2 files changed, 11 insertions(+) diff --git a/activemodel/lib/active_model/errors.rb b/activemodel/lib/active_model/errors.rb index 64b28f6def..e6c86c7843 100644 --- a/activemodel/lib/active_model/errors.rb +++ b/activemodel/lib/active_model/errors.rb @@ -142,6 +142,11 @@ module ActiveModel to_a.size end + # Returns true if there are any errors, false if not. + def empty? + all? { |k, v| v && v.empty? } + end + # Returns an xml formatted representation of the Errors hash. # # p.errors.add(:name, "can't be blank") diff --git a/activemodel/test/cases/validations_test.rb b/activemodel/test/cases/validations_test.rb index 9fedd84c73..925a68da91 100644 --- a/activemodel/test/cases/validations_test.rb +++ b/activemodel/test/cases/validations_test.rb @@ -97,6 +97,12 @@ class ValidationsTest < ActiveModel::TestCase assert_equal 2, r.errors.count end + def test_errors_empty_after_errors_on_check + t = Topic.new + assert t.errors[:id].empty? + assert t.errors.empty? + end + def test_validates_each hits = 0 Topic.validates_each(:title, :content, [:title, :content]) do |record, attr| -- cgit v1.2.3 From b22d0914acf04f4440db7ed281fb821150524614 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Sat, 10 Apr 2010 13:29:57 +0200 Subject: Fix a typo in load_once_paths [#4357 state:resolved] (ht: Kim Altintop) --- railties/lib/rails/engine/configuration.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/railties/lib/rails/engine/configuration.rb b/railties/lib/rails/engine/configuration.rb index 28e7ef947d..c5411a0331 100644 --- a/railties/lib/rails/engine/configuration.rb +++ b/railties/lib/rails/engine/configuration.rb @@ -43,7 +43,7 @@ module Rails end def load_once_paths - @eager_load_paths ||= paths.load_once + @load_once_paths ||= paths.load_once end def load_paths -- cgit v1.2.3 From 922e4c57a4a8efe5b045cf800692c487cbacb93c Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Mon, 5 Apr 2010 23:48:16 -0700 Subject: kill warnings on 1.8.7 [#4331 state:resolved] MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: José Valim --- .../test/cases/associations/belongs_to_associations_test.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/activerecord/test/cases/associations/belongs_to_associations_test.rb b/activerecord/test/cases/associations/belongs_to_associations_test.rb index 62121b93cb..be77ee4bf3 100644 --- a/activerecord/test/cases/associations/belongs_to_associations_test.rb +++ b/activerecord/test/cases/associations/belongs_to_associations_test.rb @@ -35,11 +35,11 @@ class BelongsToAssociationsTest < ActiveRecord::TestCase def test_belongs_to_with_primary_key_joins_on_correct_column sql = Client.joins(:firm_with_primary_key).to_sql if current_adapter?(:MysqlAdapter) - assert_no_match /`firm_with_primary_keys_companies`\.`id`/, sql - assert_match /`firm_with_primary_keys_companies`\.`name`/, sql + assert_no_match(/`firm_with_primary_keys_companies`\.`id`/, sql) + assert_match(/`firm_with_primary_keys_companies`\.`name`/, sql) else - assert_no_match /"firm_with_primary_keys_companies"\."id"/, sql - assert_match /"firm_with_primary_keys_companies"\."name"/, sql + assert_no_match(/"firm_with_primary_keys_companies"\."id"/, sql) + assert_match(/"firm_with_primary_keys_companies"\."name"/, sql) end end -- cgit v1.2.3 From f46dc9b6b706d8fbbb37d9d6374e671a633bff9f Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 6 Apr 2010 00:18:22 -0700 Subject: clear the rest of the warnings, run with warnings turned on [#4332 state:resolved] MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: José Valim --- activerecord/Rakefile | 1 + activerecord/test/cases/migration_test.rb | 64 +++++++++++++++++++------------ 2 files changed, 40 insertions(+), 25 deletions(-) diff --git a/activerecord/Rakefile b/activerecord/Rakefile index e638da0f3e..bf05389eae 100644 --- a/activerecord/Rakefile +++ b/activerecord/Rakefile @@ -50,6 +50,7 @@ end t.libs << "test" << connection_path t.test_files=Dir.glob( "test/cases/**/*_test{,_#{adapter_short}}.rb" ).sort t.verbose = true + t.warning = true } task "isolated_test_#{adapter}" do diff --git a/activerecord/test/cases/migration_test.rb b/activerecord/test/cases/migration_test.rb index e213986ede..7a26ee072d 100644 --- a/activerecord/test/cases/migration_test.rb +++ b/activerecord/test/cases/migration_test.rb @@ -1136,21 +1136,6 @@ if ActiveRecord::Base.connection.supports_migrations? load(MIGRATIONS_ROOT + "/valid/1_people_have_last_names.rb") end - def test_migrator_interleaved_migrations - ActiveRecord::Migrator.up(MIGRATIONS_ROOT + "/interleaved/pass_1") - - assert_nothing_raised do - ActiveRecord::Migrator.up(MIGRATIONS_ROOT + "/interleaved/pass_2") - end - - Person.reset_column_information - assert Person.column_methods_hash.include?(:last_name) - - assert_nothing_raised do - ActiveRecord::Migrator.down(MIGRATIONS_ROOT + "/interleaved/pass_3") - end - end - def test_migrator_db_has_no_schema_migrations_table # Oracle adapter raises error if semicolon is present as last character if current_adapter?(:OracleAdapter) @@ -1362,16 +1347,6 @@ if ActiveRecord::Base.connection.supports_migrations? end end - def test_migration_should_be_run_without_logger - previous_logger = ActiveRecord::Base.logger - ActiveRecord::Base.logger = nil - assert_nothing_raised do - ActiveRecord::Migrator.migrate(MIGRATIONS_ROOT + "/valid") - end - ensure - ActiveRecord::Base.logger = previous_logger - end - protected def with_env_tz(new_tz = 'US/Eastern') old_tz, ENV['TZ'] = ENV['TZ'], new_tz @@ -1457,6 +1432,45 @@ if ActiveRecord::Base.connection.supports_migrations? end # SexyMigrationsTest + class MigrationLoggerTest < ActiveRecord::TestCase + def setup + Object.send(:remove_const, :InnocentJointable) + end + + def test_migration_should_be_run_without_logger + previous_logger = ActiveRecord::Base.logger + ActiveRecord::Base.logger = nil + assert_nothing_raised do + ActiveRecord::Migrator.migrate(MIGRATIONS_ROOT + "/valid") + end + ensure + ActiveRecord::Base.logger = previous_logger + end + end + + class InterleavedMigrationsTest < ActiveRecord::TestCase + def setup + Object.send(:remove_const, :PeopleHaveLastNames) + end + + def test_migrator_interleaved_migrations + ActiveRecord::Migrator.up(MIGRATIONS_ROOT + "/interleaved/pass_1") + + assert_nothing_raised do + ActiveRecord::Migrator.up(MIGRATIONS_ROOT + "/interleaved/pass_2") + end + + Person.reset_column_information + assert Person.column_methods_hash.include?(:last_name) + + Object.send(:remove_const, :PeopleHaveLastNames) + Object.send(:remove_const, :InnocentJointable) + assert_nothing_raised do + ActiveRecord::Migrator.down(MIGRATIONS_ROOT + "/interleaved/pass_3") + end + end + end + class ChangeTableMigrationsTest < ActiveRecord::TestCase def setup @connection = Person.connection -- cgit v1.2.3 From dc974306301809f4e184f518261f5baae2c909eb Mon Sep 17 00:00:00 2001 From: Doug Alcorn Date: Sat, 27 Mar 2010 12:47:39 -0400 Subject: ActiveSupport::BacktraceCleaner#remove_filters! allows for completely untouched backtrace [#4079 state:resolved] MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: José Valim --- activesupport/lib/active_support/backtrace_cleaner.rb | 8 +++++++- activesupport/test/clean_backtrace_test.rb | 7 ++++++- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/activesupport/lib/active_support/backtrace_cleaner.rb b/activesupport/lib/active_support/backtrace_cleaner.rb index 6fab565646..8465bc1e10 100644 --- a/activesupport/lib/active_support/backtrace_cleaner.rb +++ b/activesupport/lib/active_support/backtrace_cleaner.rb @@ -4,7 +4,9 @@ module ActiveSupport # context, so only the relevant lines are included. # # If you need to reconfigure an existing BacktraceCleaner, like the one in Rails, to show as much as possible, you can always - # call BacktraceCleaner#remove_silencers! + # call BacktraceCleaner#remove_silencers! Also, if you need to reconfigure an existing BacktraceCleaner so that it does not + # filter or modify the paths of any lines of the backtrace, you can call BacktraceCleaner#remove_filters! These two methods + # will give you a completely untouched backtrace. # # Example: # @@ -60,6 +62,10 @@ module ActiveSupport @silencers = [] end + def remove_filters! + @filters = [] + end + private def filter(backtrace) @filters.each do |f| diff --git a/activesupport/test/clean_backtrace_test.rb b/activesupport/test/clean_backtrace_test.rb index ddbc258df1..86838a7f9a 100644 --- a/activesupport/test/clean_backtrace_test.rb +++ b/activesupport/test/clean_backtrace_test.rb @@ -9,6 +9,11 @@ class BacktraceCleanerFilterTest < ActiveSupport::TestCase test "backtrace should not contain prefix when it has been filtered out" do assert_equal "/my/class.rb", @bc.clean([ "/my/prefix/my/class.rb" ]).first end + + test "backtrace cleaner should allow removing filters" do + @bc.remove_filters! + assert_equal "/my/prefix/my/class.rb", @bc.clean(["/my/prefix/my/class.rb"]).first + end test "backtrace should contain unaltered lines if they dont match a filter" do assert_equal "/my/other_prefix/my/class.rb", @bc.clean([ "/my/other_prefix/my/class.rb" ]).first @@ -44,4 +49,4 @@ class BacktraceCleanerFilterAndSilencerTest < ActiveSupport::TestCase test "backtrace should not silence lines that has first had their silence hook filtered out" do assert_equal [ "/class.rb" ], @bc.clean([ "/mongrel/class.rb" ]) end -end \ No newline at end of file +end -- cgit v1.2.3 From 5850edf104ab1da0f72a43e6717a1270134db293 Mon Sep 17 00:00:00 2001 From: mfoster Date: Sun, 31 Jan 2010 01:03:52 -0800 Subject: Made arrays of ActiveRecords, and any classes, with namespaces convert to valid xml. [#3824 state:resolved] MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: José Valim --- activerecord/test/cases/xml_serialization_test.rb | 12 +++++++++++- .../lib/active_support/core_ext/array/conversions.rb | 2 +- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/activerecord/test/cases/xml_serialization_test.rb b/activerecord/test/cases/xml_serialization_test.rb index e1ad5c1685..2849ff11b7 100644 --- a/activerecord/test/cases/xml_serialization_test.rb +++ b/activerecord/test/cases/xml_serialization_test.rb @@ -130,10 +130,20 @@ class NilXmlSerializationTest < ActiveRecord::TestCase end class DatabaseConnectedXmlSerializationTest < ActiveRecord::TestCase - fixtures :authors, :posts + fixtures :authors, :posts, :projects + # to_xml used to mess with the hash the user provided which # caused the builder to be reused. This meant the document kept # getting appended to. + + def test_modules + projects = MyApplication::Business::Project.all + xml = projects.to_xml + root = projects.first.class.to_s.underscore.pluralize.tr('/','_').dasherize + assert_match "<#{root} type=\"array\">", xml + assert_match "", xml + end + def test_passing_hash_shouldnt_reuse_builder options = {:include=>:posts} david = authors(:david) diff --git a/activesupport/lib/active_support/core_ext/array/conversions.rb b/activesupport/lib/active_support/core_ext/array/conversions.rb index 2119322bfe..5d8e78e6e5 100644 --- a/activesupport/lib/active_support/core_ext/array/conversions.rb +++ b/activesupport/lib/active_support/core_ext/array/conversions.rb @@ -131,7 +131,7 @@ class Array require 'builder' unless defined?(Builder) options = options.dup - options[:root] ||= all? { |e| e.is_a?(first.class) && first.class.to_s != "Hash" } ? ActiveSupport::Inflector.pluralize(ActiveSupport::Inflector.underscore(first.class.name)) : "records" + options[:root] ||= all? { |e| e.is_a?(first.class) && first.class.to_s != "Hash" } ? ActiveSupport::Inflector.pluralize(ActiveSupport::Inflector.underscore(first.class.name)).tr('/', '_') : "records" options[:children] ||= options[:root].singularize options[:indent] ||= 2 options[:builder] ||= Builder::XmlMarkup.new(:indent => options[:indent]) -- cgit v1.2.3 From 381f877bbbbf81d679f5be3b7ac7e961d41502bd Mon Sep 17 00:00:00 2001 From: wycats Date: Sat, 10 Apr 2010 15:13:21 -0400 Subject: Revert "Revert "Use path_names, not resource_path_names, consistently"" This reverts commit d3ec4b1ba6528a081f5124fd71cc026b1f8abe9c. --- actionpack/lib/action_dispatch/routing/mapper.rb | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/actionpack/lib/action_dispatch/routing/mapper.rb b/actionpack/lib/action_dispatch/routing/mapper.rb index 61256e8df1..7035e360ec 100644 --- a/actionpack/lib/action_dispatch/routing/mapper.rb +++ b/actionpack/lib/action_dispatch/routing/mapper.rb @@ -372,7 +372,7 @@ module ActionDispatch @scope[:module] ? "#{@scope[:module]}/#{child}" : child end - def merge_resources_path_names_scope(parent, child) + def merge_path_names_scope(parent, child) merge_options_scope(parent, child) end @@ -521,7 +521,7 @@ module ActionDispatch def initialize(*args) #:nodoc: super - @scope[:resources_path_names] = @set.resources_path_names + @scope[:path_names] = @set.resources_path_names end def resource(*resources, &block) @@ -637,7 +637,7 @@ module ActionDispatch return self end - resources_path_names = options.delete(:path_names) + path_names = options.delete(:path_names) if args.first.is_a?(Symbol) action = args.first @@ -654,7 +654,7 @@ module ActionDispatch end else with_exclusive_name_prefix(action) do - return match("#{action_path(action, resources_path_names)}(.:format)", options.reverse_merge(:to => action)) + return match("#{action_path(action, path_names)}(.:format)", options.reverse_merge(:to => action)) end end end @@ -682,7 +682,7 @@ module ActionDispatch private def action_path(name, path_names = nil) - path_names ||= @scope[:resources_path_names] + path_names ||= @scope[:path_names] path_names[name.to_sym] || name.to_s end @@ -693,7 +693,7 @@ module ActionDispatch end if path_names = options.delete(:path_names) - scope(:resources_path_names => path_names) do + scope(:path_names => path_names) do send(method, resources.pop, options, &block) end return true -- cgit v1.2.3