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:
+5
-5
@@ -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
@@ -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')
|
||||
|
||||
@@ -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
@@ -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
|
||||
Reference in New Issue
Block a user