Upgraded to Rails 2.3.4 (#3597)

* Ran the Rails upgrade
* Upgraded to Rails Engines 2.3.2
* Added a plugin to let Engines override application views.
* Converted tests to use the new classes:
** ActionController::TestCase for functional
** ActiveSupport::TestCase for units
* Converted ActiveRecord::Error message to a string.
* ActiveRecord grouping returns an ordered hash which doesn't have #sort!
* Updated the I18n storage_units format.
* Added some default initializers from a fresh rails app
* Changed the order of check_box_tags and hidden_field_tags.  The hidden tag
  needs to appear first in Rails 2.3, otherwise it will override any value in
  the check_box_tag.
* Removed the custom handler for when the cookie store is tampered with.
  Rails 2.3 removed the TamperedWithCookie exception and instead Rails will not
  load the data from it when it's been tampered with (e.g. no user login).
* Fixed mail layouts, 2.3 has problems with implicit multipart emails that
  use layouts.  Also removed some custom Redmine mailer code.
* Fixed a bug that occurred in tests where the "required" span tag would be
  added to the :field_status translation.  This resulted in an email string of:

    <li>Status<span class="required"> *</span><span class="required"> *</span>

  Instead of:

    <li>Status: New</li>

git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@2887 e93f8b46-1217-0410-a6f0-8f06a7374b81
This commit is contained in:
Eric Davis
2009-09-13 17:14:35 +00:00
parent fb349dc4ab
commit 7b0cb6aba8
263 changed files with 1636 additions and 440 deletions
+5 -5
View File
@@ -43,7 +43,7 @@ module Engines
# List of extensions to load, can be changed in init.rb before calling Engines.init
mattr_accessor :rails_extensions
self.rails_extensions = %w(action_mailer asset_helpers form_tag_helpers routing migrations dependencies)
self.rails_extensions = %w(asset_helpers form_tag_helpers migrations dependencies)
# The name of the public directory to mirror public engine assets into.
# Defaults to <tt>RAILS_ROOT/public/plugin_assets</tt>.
@@ -68,7 +68,7 @@ module Engines
mattr_accessor :disable_application_code_loading
self.disable_application_code_loading = false
# Set this ti true if code should not be mixed (i.e. it will be loaded
# Set this to true if code should not be mixed (i.e. it will be loaded
# from the first valid path on $LOAD_PATH)
mattr_accessor :disable_code_mixing
self.disable_code_mixing = false
@@ -81,7 +81,7 @@ module Engines
self.code_mixing_file_types = %w(controller helper)
class << self
def init
def init(initializer)
load_extensions
Engines::Assets.initialize_base_public_directory
end
@@ -124,9 +124,9 @@ module Engines
# and that they are placed within plugin/app/things (the pluralized form of 'thing').
#
# It's important to note that you'll also want to ensure that the "things" are
# on your load path in your plugin's init.rb:
# on your load path by including them in Rails load path mechanism, e.g. in init.rb:
#
# Rails.plugins[:my_plugin].code_paths << "app/things"
# ActiveSupport::Dependencies.load_paths << File.join(File.dirname(__FILE__), 'app', 'things'))
#
def mix_code_from(*types)
self.code_mixing_file_types += types.map { |x| x.to_s.singularize }
+1 -48
View File
@@ -4,23 +4,9 @@
#
# Engines.plugins[:plugin_name]
#
# If this plugin contains paths in directories other than <tt>app/controllers</tt>,
# <tt>app/helpers</tt>, <tt>app/models</tt> and <tt>components</tt>, authors can
# declare this by adding extra paths to #code_paths:
#
# Rails.plugin[:my_plugin].code_paths << "app/sweepers" << "vendor/my_lib"
#
# Other properties of the Plugin instance can also be set.
module Engines
class Plugin < Rails::Plugin
# Plugins can add code paths to this attribute in init.rb if they
# need plugin directories to be added to the load path, i.e.
#
# plugin.code_paths << 'app/other_classes'
#
# Defaults to ["app/controllers", "app/helpers", "app/models", "components"]
attr_accessor :code_paths
# Plugins can add paths to this attribute in init.rb if they need
# controllers loaded from additional locations.
attr_accessor :controller_paths
@@ -32,16 +18,6 @@ module Engines
attr_accessor :public_directory
protected
# The default set of code paths which will be added to $LOAD_PATH
# and Dependencies.load_paths
def default_code_paths
# lib will actually be removed from the load paths when we call
# uniq! in #inject_into_load_paths, but it's important to keep it
# around (for the documentation tasks, for instance).
%w(app/controllers app/helpers app/models components lib)
end
# The default set of code paths which will be added to the routing system
def default_controller_paths
%w(app/controllers components)
@@ -58,41 +34,23 @@ module Engines
def initialize(directory)
super directory
@code_paths = default_code_paths
@controller_paths = default_controller_paths
@public_directory = default_public_directory
end
# Returns a list of paths this plugin wishes to make available in $LOAD_PATH
#
# Overwrites the correspondend method in the superclass
def load_paths
report_nonexistant_or_empty_plugin! unless valid?
select_existing_paths :code_paths
end
# Extends the superclass' load method to additionally mirror public assets
def load(initializer)
return if loaded?
super initializer
add_plugin_view_paths
add_plugin_locale_paths
Assets.mirror_files_for(self)
end
# for code_paths and controller_paths select those paths that actually
# exist in the plugin's directory
# select those paths that actually exist in the plugin's directory
def select_existing_paths(name)
Engines.select_existing_paths(self.send(name).map { |p| File.join(directory, p) })
end
def add_plugin_view_paths
view_path = File.join(directory, 'app', 'views')
if File.exist?(view_path)
ActionController::Base.prepend_view_path(view_path) # push it just underneath the app
end
end
def add_plugin_locale_paths
locale_path = File.join(directory, 'locales')
return unless File.exists?(locale_path)
@@ -112,11 +70,6 @@ module Engines
"#{File.basename(Engines.public_directory)}/#{name}"
end
# The path to this plugin's routes file
def routes_path
File.join(directory, "routes.rb")
end
# The directory containing this plugin's migrations (<tt>plugin/db/migrate</tt>)
def migration_directory
File.join(self.directory, 'db', 'migrate')
-7
View File
@@ -5,14 +5,7 @@ module Engines
def register_plugin_as_loaded(plugin)
super plugin
Engines.plugins << plugin
register_to_routing(plugin)
end
# Registers the plugin's controller_paths for the routing system.
def register_to_routing(plugin)
initializer.configuration.controller_paths += plugin.select_existing_paths(:controller_paths)
initializer.configuration.controller_paths.uniq!
end
end
end
end
@@ -1,82 +0,0 @@
# The way ActionMailer is coded in terms of finding templates is very restrictive, to the point
# where all templates for rendering must exist under the single base path. This is difficult to
# work around without re-coding significant parts of the action mailer code.
#
# ---
#
# The MailTemplates module overrides two (private) methods from ActionMailer to enable mail
# templates within plugins:
#
# [+template_path+] which now produces the contents of #template_paths
# [+initialize_template_class+] which now find the first matching template and creates
# an ActionVew::Base instance with the correct view_paths
#
# Ideally ActionMailer would use the same template-location logic as ActionView, and the same
# view paths as ActionController::Base.view_paths, but it currently does not.
module Engines::RailsExtensions::ActionMailer
def self.included(base) #:nodoc:
base.class_eval do
alias_method_chain :template_path, :engine_additions
alias_method_chain :initialize_template_class, :engine_additions
end
end
private
#--
# ActionMailer::Base#create uses two mechanisms to determine the proper template file(s)
# to load. Firstly, it searches within the template_root for files that much the explicit
# (or implicit) part encodings (like signup.text.plain.erb for the signup action).
# This is how implicit multipart emails are built, by the way.
#
# Secondly, it then creates an ActionMailer::Base instance with it's view_paths parameter
# set to the template_root, so that ActionMailer will then take over rendering the
# templates.
#
# Ideally, ActionMailer would pass the same set of view paths as it gets in a normal
# request (i.e. ActionController::Base.view_paths), so that all possible view paths
# were searched. However, this seems to introduce some problems with helper modules.
#
# So instead, and because we have to fool these two independent parts of ActionMailer,
# we fudge with the mechanisms it uses to find the templates (via template_paths, and
# template_path_with_engine_additions), and then intercept the creation of the ActionView
# instance so we can set the view_paths (in initialize_template_class_with_engine_additions).
#++
# Returns all possible template paths for the current mailer, including those
# within the loaded plugins.
def template_paths
paths = Engines.plugins.by_precedence.map { |p| "#{p.directory}/app/views/#{mailer_name}" }
paths.unshift(template_path_without_engine_additions) unless Engines.disable_application_view_loading
paths
end
# Return something that Dir[] can glob against. This method is called in
# ActionMailer::Base#create! and used as part of an argument to Dir. We can
# take advantage of this by using some of the features of Dir.glob to search
# multiple paths for matching files.
def template_path_with_engine_additions
"{#{template_paths.join(",")}}"
end
# Return an instance of ActionView::Base with the view paths set to all paths
# in ActionController::Base.view_paths (i.e. including all plugin view paths)
def initialize_template_class_with_engine_additions(assigns)
# I'd like to just return this, but I get problems finding methods in helper
# modules if the method implemention from the regular class is not called
#
# ActionView::Base.new(ActionController::Base.view_paths.dup, assigns, self)
renderer = initialize_template_class_without_engine_additions(assigns)
renderer.view_paths.unshift(*ActionController::Base.view_paths.dup)
renderer
end
end
# We don't need to do this if ActionMailer hasn't been loaded.
if Object.const_defined?(:ActionMailer)
module ::ActionMailer #:nodoc:
class Base #:nodoc:
include Engines::RailsExtensions::ActionMailer
end
end
end
@@ -1,83 +0,0 @@
# Effective use of Rails' routes can help create a tidy and elegant set of URLs,
# and is a significant part of creating an external API for your web application.
#
# When developing plugins which contain controllers, it seems obvious that including
# the corresponding routes would be extremely useful. This is particularly true
# when exposing RESTful resources using the new REST-ian features of Rails.
#
# == Including routes in your plugin
#
# The engines plugin makes it possible to include a set of routes within your plugin
# very simply, as it turns out. Include a <tt>routes.rb</tt> file like the one below
# at the root of your plugin (along-side <tt>init.rb</tt> and <tt>lib/</tt>):
#
# connect "/login", :controller => "account", :action => "login"
#
# # add a named route
# logout "/logout", :controller => "account", :action => "logout"
#
# # some restful stuff
# resources :things do |t|
# t.resources :other_things
# end
#
# Everywhere in a normal <tt>RAILS_ROOT/config/routes.rb</tt> file
# where you might have <tt>map.connect</tt>, you just use <tt>connect</tt> in your
# plugin's <tt>routes.rb</tt>.
#
# === Hooking it up in your application
#
# While it would be possible to have each plugin's routes automagically included into
# the application's route set, to do so would actually be a stunningly bad idea. Route
# priority is the key issue here. You, the application developer, needs to be in complete
# control when it comes to specifying the priority of routes in your application, since
# the ordering of your routes directly affects how Rails will interpret incoming requests.
#
# To add plugin routes into your application's <tt>routes.rb</tt> file, you need to explicitly
# map them in using the Engines::RailsExtensions::Routing#from_plugin method:
#
# ApplicationController::Routing::Routes.draw do |map|
#
# map.connect "/app_stuff", :controller => "application_thing" # etc...
#
# # This line includes the routes from the given plugin at this point, giving you
# # control over the priority of your application routes
# map.from_plugin :your_plugin
#
# map.connect ":controller/:action/:id"
# end
#
# By including routes in plugins which have controllers, you can now share in a simple way
# a compact and elegant URL scheme which corresponds to those controllers.
#
# ---
#
# The Engines::RailsExtensions::Routing module defines extensions to Rails'
# routing (ActionController::Routing) mechanism such that routes can be loaded
# from a given plugin.
#
# The key method is Engines::RailsExtensions::Routing#from_plugin, which can be called
# within your application's <tt>config/routes.rb</tt> file to load plugin routes at that point.
#
module Engines::RailsExtensions::Routing
# Loads the set of routes from within a plugin and evaluates them at this
# point within an application's main <tt>routes.rb</tt> file.
#
# Plugin routes are loaded from <tt><plugin_root>/routes.rb</tt>.
def from_plugin(name)
map = self # to make 'map' available within the plugin route file
routes_path = Engines.plugins[name].routes_path
eval(IO.read(routes_path), binding, routes_path) if File.file?(routes_path)
end
end
module ::ActionController #:nodoc:
module Routing #:nodoc:
class RouteSet #:nodoc:
class Mapper #:nodoc:
include Engines::RailsExtensions::Routing
end
end
end
end
+15 -1
View File
@@ -67,10 +67,14 @@ module Engines::Testing
# This method is called by the engines-supplied plugin testing rake tasks
def self.setup_plugin_fixtures(plugins = Engines.plugins.by_precedence)
# First, clear the directory
Dir.glob("#{self.temporary_fixtures_directory}/*.yml").each{|fixture| File.delete(fixture)}
# Copy all plugin fixtures, and then the application fixtures, into this directory
plugins.each do |plugin|
plugin_fixtures_directory = File.join(plugin.directory, "test", "fixtures")
if File.directory?(plugin_fixtures_directory)
plugin_app_directory = File.join(plugin.directory, "app")
if File.directory?(plugin_app_directory) && File.directory?(plugin_fixtures_directory)
Engines.mirror_files_from(plugin_fixtures_directory, self.temporary_fixtures_directory)
end
end
@@ -84,4 +88,14 @@ module Engines::Testing
ActiveSupport::TestCase.fixture_path = self.temporary_fixtures_directory
$LOAD_PATH.unshift self.temporary_fixtures_directory
end
# overridden test should be in test/{unit,functional,integration}/{plugin_name}/{test_name}
def self.override_tests_from_app
filename = caller.first.split(":").first
plugin_name = filename.split("/")[-4]
test_kind = filename.split("/")[-2]
override_file = File.expand_path(File.join(File.dirname(filename), "..", "..", "..", "..", "..", "test",
test_kind, plugin_name, File.basename(filename)))
load(override_file) if File.exist?(override_file)
end
end