mirror of
https://github.com/github/rails.git
synced 2026-04-26 03:00:59 -04:00
Merge branch 'master' of git@github.com:rails/rails
This commit is contained in:
@@ -420,12 +420,6 @@ module ActionMailer #:nodoc:
|
||||
new.deliver!(mail)
|
||||
end
|
||||
|
||||
def register_template_extension(extension)
|
||||
ActiveSupport::Deprecation.warn(
|
||||
"ActionMailer::Base.register_template_extension has been deprecated." +
|
||||
"Use ActionView::Base.register_template_extension instead", caller)
|
||||
end
|
||||
|
||||
def template_root
|
||||
self.view_paths && self.view_paths.first
|
||||
end
|
||||
|
||||
54
actionmailer/test/asset_host_test.rb
Normal file
54
actionmailer/test/asset_host_test.rb
Normal file
@@ -0,0 +1,54 @@
|
||||
require 'abstract_unit'
|
||||
|
||||
class AssetHostMailer < ActionMailer::Base
|
||||
def email_with_asset(recipient)
|
||||
recipients recipient
|
||||
subject "testing email containing asset path while asset_host is set"
|
||||
from "tester@example.com"
|
||||
end
|
||||
end
|
||||
|
||||
class AssetHostTest < Test::Unit::TestCase
|
||||
def setup
|
||||
set_delivery_method :test
|
||||
ActionMailer::Base.perform_deliveries = true
|
||||
ActionMailer::Base.deliveries = []
|
||||
|
||||
@recipient = 'test@localhost'
|
||||
end
|
||||
|
||||
def teardown
|
||||
restore_delivery_method
|
||||
end
|
||||
|
||||
def test_asset_host_as_string
|
||||
ActionController::Base.asset_host = "http://www.example.com"
|
||||
mail = AssetHostMailer.deliver_email_with_asset(@recipient)
|
||||
assert_equal "<img alt=\"Somelogo\" src=\"http://www.example.com/images/somelogo.png\" />", mail.body.strip
|
||||
end
|
||||
|
||||
def test_asset_host_as_one_arguement_proc
|
||||
ActionController::Base.asset_host = Proc.new { |source|
|
||||
if source.starts_with?('/images')
|
||||
"http://images.example.com"
|
||||
else
|
||||
"http://assets.example.com"
|
||||
end
|
||||
}
|
||||
mail = AssetHostMailer.deliver_email_with_asset(@recipient)
|
||||
assert_equal "<img alt=\"Somelogo\" src=\"http://images.example.com/images/somelogo.png\" />", mail.body.strip
|
||||
end
|
||||
|
||||
def test_asset_host_as_two_arguement_proc
|
||||
ActionController::Base.asset_host = Proc.new {|source,request|
|
||||
if request && request.ssl?
|
||||
"https://www.example.com"
|
||||
else
|
||||
"http://www.example.com"
|
||||
end
|
||||
}
|
||||
mail = nil
|
||||
assert_nothing_raised { mail = AssetHostMailer.deliver_email_with_asset(@recipient) }
|
||||
assert_equal "<img alt=\"Somelogo\" src=\"http://www.example.com/images/somelogo.png\" />", mail.body.strip
|
||||
end
|
||||
end
|
||||
1
actionmailer/test/fixtures/asset_host_mailer/email_with_asset.html.erb
vendored
Normal file
1
actionmailer/test/fixtures/asset_host_mailer/email_with_asset.html.erb
vendored
Normal file
@@ -0,0 +1 @@
|
||||
<%= image_tag "somelogo.png" %>
|
||||
@@ -1,5 +1,7 @@
|
||||
*2.3.0 [Edge]*
|
||||
|
||||
* Allow users to opt out of the spoofing checks in Request#remote_ip. Useful for sites whose traffic regularly triggers false positives. [Darren Boyd]
|
||||
|
||||
* Deprecated formatted_polymorphic_url. [Jeremy Kemper]
|
||||
|
||||
* Added the option to declare an asset_host as an object that responds to call (see http://github.com/dhh/asset-hosting-with-minimum-ssl for an example) [DHH]
|
||||
|
||||
@@ -57,6 +57,7 @@ module ActionController
|
||||
autoload :Integration, 'action_controller/integration'
|
||||
autoload :IntegrationTest, 'action_controller/integration'
|
||||
autoload :Layout, 'action_controller/layout'
|
||||
autoload :MiddlewareStack, 'action_controller/middleware_stack'
|
||||
autoload :MimeResponds, 'action_controller/mime_responds'
|
||||
autoload :PolymorphicRoutes, 'action_controller/polymorphic_routes'
|
||||
autoload :RackRequest, 'action_controller/rack_process'
|
||||
|
||||
@@ -327,6 +327,10 @@ module ActionController #:nodoc:
|
||||
# sets it to <tt>:authenticity_token</tt> by default.
|
||||
cattr_accessor :request_forgery_protection_token
|
||||
|
||||
# Controls the IP Spoofing check when determining the remote IP.
|
||||
@@ip_spoofing_check = true
|
||||
cattr_accessor :ip_spoofing_check
|
||||
|
||||
# Indicates whether or not optimise the generated named
|
||||
# route helper methods
|
||||
cattr_accessor :optimise_named_routes
|
||||
|
||||
@@ -85,6 +85,9 @@ module ActionController
|
||||
end
|
||||
end
|
||||
|
||||
cattr_accessor :middleware
|
||||
self.middleware = MiddlewareStack.new
|
||||
|
||||
cattr_accessor :error_file_path
|
||||
self.error_file_path = Rails.public_path if defined?(Rails.public_path)
|
||||
|
||||
@@ -93,6 +96,7 @@ module ActionController
|
||||
|
||||
def initialize(output = $stdout, request = nil, response = nil)
|
||||
@output, @request, @response = output, request, response
|
||||
@app = @@middleware.build(lambda { |env| self._call(env) })
|
||||
end
|
||||
|
||||
def dispatch_unlocked
|
||||
@@ -127,6 +131,10 @@ module ActionController
|
||||
end
|
||||
|
||||
def call(env)
|
||||
@app.call(env)
|
||||
end
|
||||
|
||||
def _call(env)
|
||||
@request = RackRequest.new(env)
|
||||
@response = RackResponse.new(@request)
|
||||
dispatch
|
||||
|
||||
42
actionpack/lib/action_controller/middleware_stack.rb
Normal file
42
actionpack/lib/action_controller/middleware_stack.rb
Normal file
@@ -0,0 +1,42 @@
|
||||
module ActionController
|
||||
class MiddlewareStack < Array
|
||||
class Middleware
|
||||
attr_reader :klass, :args, :block
|
||||
|
||||
def initialize(klass, *args, &block)
|
||||
@klass = klass.is_a?(Class) ? klass : klass.to_s.constantize
|
||||
@args = args
|
||||
@block = block
|
||||
end
|
||||
|
||||
def ==(middleware)
|
||||
case middleware
|
||||
when Middleware
|
||||
klass == middleware.klass
|
||||
when Class
|
||||
klass == middleware
|
||||
else
|
||||
klass == middleware.to_s.constantize
|
||||
end
|
||||
end
|
||||
|
||||
def inspect
|
||||
str = @klass.to_s
|
||||
@args.each { |arg| str += ", #{arg.inspect}" }
|
||||
str
|
||||
end
|
||||
|
||||
def build(app)
|
||||
klass.new(app, *args, &block)
|
||||
end
|
||||
end
|
||||
|
||||
def use(*args, &block)
|
||||
push(Middleware.new(*args, &block))
|
||||
end
|
||||
|
||||
def build(app)
|
||||
reverse.inject(app) { |a, e| e.build(a) }
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -218,7 +218,7 @@ module ActionController
|
||||
remote_ips = @env['HTTP_X_FORWARDED_FOR'] && @env['HTTP_X_FORWARDED_FOR'].split(',')
|
||||
|
||||
if @env.include? 'HTTP_CLIENT_IP'
|
||||
if remote_ips && !remote_ips.include?(@env['HTTP_CLIENT_IP'])
|
||||
if ActionController::Base.ip_spoofing_check && remote_ips && !remote_ips.include?(@env['HTTP_CLIENT_IP'])
|
||||
# We don't know which came from the proxy, and which from the user
|
||||
raise ActionControllerError.new(<<EOM)
|
||||
IP spoofing attack?!
|
||||
|
||||
@@ -574,7 +574,7 @@ module ActionView
|
||||
|
||||
private
|
||||
def request
|
||||
@controller.request
|
||||
request? && @controller.request
|
||||
end
|
||||
|
||||
def request?
|
||||
|
||||
@@ -370,8 +370,8 @@ module ActionView
|
||||
options.reverse_merge!(:link => :all, :html => {})
|
||||
|
||||
case options[:link].to_sym
|
||||
when :all then auto_link_email_addresses(auto_link_urls(text, options[:html], &block), &block)
|
||||
when :email_addresses then auto_link_email_addresses(text, &block)
|
||||
when :all then auto_link_email_addresses(auto_link_urls(text, options[:html], &block), options[:html], &block)
|
||||
when :email_addresses then auto_link_email_addresses(text, options[:html], &block)
|
||||
when :urls then auto_link_urls(text, options[:html], &block)
|
||||
end
|
||||
end
|
||||
@@ -559,7 +559,7 @@ module ActionView
|
||||
|
||||
# Turns all email addresses into clickable links. If a block is given,
|
||||
# each email is yielded and the result is used as the link text.
|
||||
def auto_link_email_addresses(text)
|
||||
def auto_link_email_addresses(text, html_options = {})
|
||||
body = text.dup
|
||||
text.gsub(/([\w\.!#\$%\-+.]+@[A-Za-z0-9\-]+(\.[A-Za-z0-9\-]+)+)/) do
|
||||
text = $1
|
||||
@@ -568,7 +568,7 @@ module ActionView
|
||||
text
|
||||
else
|
||||
display_text = (block_given?) ? yield(text) : text
|
||||
%{<a href="mailto:#{text}">#{display_text}</a>}
|
||||
mail_to text, display_text, html_options
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -66,6 +66,15 @@ class RequestTest < ActiveSupport::TestCase
|
||||
assert_match /HTTP_X_FORWARDED_FOR="9.9.9.9, 3.4.5.6, 10.0.0.1, 172.31.4.4"/, e.message
|
||||
assert_match /HTTP_CLIENT_IP="8.8.8.8"/, e.message
|
||||
|
||||
# turn IP Spoofing detection off.
|
||||
# This is useful for sites that are aimed at non-IP clients. The typical
|
||||
# example is WAP. Since the cellular network is not IP based, it's a
|
||||
# leap of faith to assume that their proxies are ever going to set the
|
||||
# HTTP_CLIENT_IP/HTTP_X_FORWARDED_FOR headers properly.
|
||||
ActionController::Base.ip_spoofing_check = false
|
||||
assert_equal('8.8.8.8', @request.remote_ip(true))
|
||||
ActionController::Base.ip_spoofing_check = true
|
||||
|
||||
@request.env['HTTP_X_FORWARDED_FOR'] = '8.8.8.8, 9.9.9.9'
|
||||
assert_equal '8.8.8.8', @request.remote_ip(true)
|
||||
|
||||
|
||||
@@ -262,6 +262,11 @@ class TextHelperTest < ActionView::TestCase
|
||||
email2_result = %{<a href="mailto:#{email2_raw}">#{email2_raw}</a>}
|
||||
assert_equal email2_result, auto_link(email2_raw)
|
||||
|
||||
email3_raw = '+david@loudthinking.com'
|
||||
email3_result = %{<a href="mailto:+%64%61%76%69%64@%6c%6f%75%64%74%68%69%6e%6b%69%6e%67.%63%6f%6d">#{email3_raw}</a>}
|
||||
assert_equal email3_result, auto_link(email3_raw, :all, :encode => :hex)
|
||||
assert_equal email3_result, auto_link(email3_raw, :email_addresses, :encode => :hex)
|
||||
|
||||
link2_raw = 'www.rubyonrails.com'
|
||||
link2_result = generate_result(link2_raw, "http://#{link2_raw}")
|
||||
assert_equal %(Go to #{link2_result}), auto_link("Go to #{link2_raw}", :urls)
|
||||
@@ -362,7 +367,7 @@ class TextHelperTest < ActionView::TestCase
|
||||
end
|
||||
|
||||
def test_auto_link_with_options_hash
|
||||
assert_dom_equal 'Welcome to my new blog at <a href="http://www.myblog.com/" class="menu" target="_blank">http://www.myblog.com/</a>. Please e-mail me at <a href="mailto:me@email.com">me@email.com</a>.',
|
||||
assert_dom_equal 'Welcome to my new blog at <a href="http://www.myblog.com/" class="menu" target="_blank">http://www.myblog.com/</a>. Please e-mail me at <a href="mailto:me@email.com" class="menu" target="_blank">me@email.com</a>.',
|
||||
auto_link("Welcome to my new blog at http://www.myblog.com/. Please e-mail me at me@email.com.",
|
||||
:link => :all, :html => { :class => "menu", :target => "_blank" })
|
||||
end
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
*2.3.0/3.0*
|
||||
|
||||
* Add :having as a key to find and the relevant associations. [miloops]
|
||||
|
||||
* Added default_scope to Base #1381 [Paweł Kondzior]. Example:
|
||||
|
||||
class Person < ActiveRecord::Base
|
||||
|
||||
@@ -185,7 +185,7 @@ module ActiveRecord
|
||||
|
||||
associated_records = reflection.klass.find(:all, :conditions => [conditions, ids],
|
||||
:include => options[:include],
|
||||
:joins => "INNER JOIN #{connection.quote_table_name options[:join_table]} as t0 ON #{reflection.klass.quoted_table_name}.#{reflection.klass.primary_key} = t0.#{reflection.association_foreign_key}",
|
||||
:joins => "INNER JOIN #{connection.quote_table_name options[:join_table]} t0 ON #{reflection.klass.quoted_table_name}.#{reflection.klass.primary_key} = t0.#{reflection.association_foreign_key}",
|
||||
:select => "#{options[:select] || table_name+'.*'}, t0.#{reflection.primary_key_name} as the_parent_record_id",
|
||||
:order => options[:order])
|
||||
|
||||
|
||||
@@ -724,6 +724,8 @@ module ActiveRecord
|
||||
# Specify second-order associations that should be eager loaded when the collection is loaded.
|
||||
# [:group]
|
||||
# An attribute name by which the result should be grouped. Uses the <tt>GROUP BY</tt> SQL-clause.
|
||||
# [:having]
|
||||
# Combined with +:group+ this can be used to filter the records that a <tt>GROUP BY</tt> returns. Uses the <tt>HAVING</tt> SQL-clause.
|
||||
# [:limit]
|
||||
# An integer determining the limit on the number of rows that should be returned.
|
||||
# [:offset]
|
||||
@@ -1181,6 +1183,8 @@ module ActiveRecord
|
||||
# Specify second-order associations that should be eager loaded when the collection is loaded.
|
||||
# [:group]
|
||||
# An attribute name by which the result should be grouped. Uses the <tt>GROUP BY</tt> SQL-clause.
|
||||
# [:having]
|
||||
# Combined with +:group+ this can be used to filter the records that a <tt>GROUP BY</tt> returns. Uses the <tt>HAVING</tt> SQL-clause.
|
||||
# [:limit]
|
||||
# An integer determining the limit on the number of rows that should be returned.
|
||||
# [:offset]
|
||||
@@ -1553,7 +1557,7 @@ module ActiveRecord
|
||||
@@valid_keys_for_has_many_association = [
|
||||
:class_name, :table_name, :foreign_key, :primary_key,
|
||||
:dependent,
|
||||
:select, :conditions, :include, :order, :group, :limit, :offset,
|
||||
:select, :conditions, :include, :order, :group, :having, :limit, :offset,
|
||||
:as, :through, :source, :source_type,
|
||||
:uniq,
|
||||
:finder_sql, :counter_sql,
|
||||
@@ -1609,7 +1613,7 @@ module ActiveRecord
|
||||
mattr_accessor :valid_keys_for_has_and_belongs_to_many_association
|
||||
@@valid_keys_for_has_and_belongs_to_many_association = [
|
||||
:class_name, :table_name, :join_table, :foreign_key, :association_foreign_key,
|
||||
:select, :conditions, :include, :order, :group, :limit, :offset,
|
||||
:select, :conditions, :include, :order, :group, :having, :limit, :offset,
|
||||
:uniq,
|
||||
:finder_sql, :counter_sql, :delete_sql, :insert_sql,
|
||||
:before_add, :after_add, :before_remove, :after_remove,
|
||||
@@ -1658,7 +1662,7 @@ module ActiveRecord
|
||||
add_conditions!(sql, options[:conditions], scope)
|
||||
add_limited_ids_condition!(sql, options, join_dependency) if !using_limitable_reflections?(join_dependency.reflections) && ((scope && scope[:limit]) || options[:limit])
|
||||
|
||||
add_group!(sql, options[:group], scope)
|
||||
add_group!(sql, options[:group], options[:having], scope)
|
||||
add_order!(sql, options[:order], scope)
|
||||
add_limit!(sql, options, scope) if using_limitable_reflections?(join_dependency.reflections)
|
||||
add_lock!(sql, options, scope)
|
||||
@@ -1714,7 +1718,7 @@ module ActiveRecord
|
||||
end
|
||||
|
||||
add_conditions!(sql, options[:conditions], scope)
|
||||
add_group!(sql, options[:group], scope)
|
||||
add_group!(sql, options[:group], options[:having], scope)
|
||||
|
||||
if order && is_distinct
|
||||
connection.add_order_by_for_association_limiting!(sql, :order => order)
|
||||
|
||||
@@ -188,6 +188,7 @@ module ActiveRecord
|
||||
def merge_options_from_reflection!(options)
|
||||
options.reverse_merge!(
|
||||
:group => @reflection.options[:group],
|
||||
:having => @reflection.options[:having],
|
||||
:limit => @reflection.options[:limit],
|
||||
:offset => @reflection.options[:offset],
|
||||
:joins => @reflection.options[:joins],
|
||||
|
||||
@@ -521,6 +521,7 @@ module ActiveRecord #:nodoc:
|
||||
# * <tt>:conditions</tt> - An SQL fragment like "administrator = 1", <tt>[ "user_name = ?", username ]</tt>, or <tt>["user_name = :user_name", { :user_name => user_name }]</tt>. See conditions in the intro.
|
||||
# * <tt>:order</tt> - An SQL fragment like "created_at DESC, name".
|
||||
# * <tt>:group</tt> - An attribute name by which the result should be grouped. Uses the <tt>GROUP BY</tt> SQL-clause.
|
||||
# * <tt>:having</tt> - Combined with +:group+ this can be used to filter the records that a <tt>GROUP BY</tt> returns. Uses the <tt>HAVING</tt> SQL-clause.
|
||||
# * <tt>:limit</tt> - An integer determining the limit on the number of rows that should be returned.
|
||||
# * <tt>:offset</tt> - An integer determining the offset from where the rows should be fetched. So at 5, it would skip rows 0 through 4.
|
||||
# * <tt>:joins</tt> - Either an SQL fragment for additional joins like "LEFT JOIN comments ON comments.post_id = id" (rarely needed)
|
||||
@@ -1632,7 +1633,7 @@ module ActiveRecord #:nodoc:
|
||||
add_joins!(sql, options[:joins], scope)
|
||||
add_conditions!(sql, options[:conditions], scope)
|
||||
|
||||
add_group!(sql, options[:group], scope)
|
||||
add_group!(sql, options[:group], options[:having], scope)
|
||||
add_order!(sql, options[:order], scope)
|
||||
add_limit!(sql, options, scope)
|
||||
add_lock!(sql, options, scope)
|
||||
@@ -1688,13 +1689,15 @@ module ActiveRecord #:nodoc:
|
||||
end
|
||||
end
|
||||
|
||||
def add_group!(sql, group, scope = :auto)
|
||||
def add_group!(sql, group, having, scope = :auto)
|
||||
if group
|
||||
sql << " GROUP BY #{group}"
|
||||
sql << " HAVING #{having}" if having
|
||||
else
|
||||
scope = scope(:find) if :auto == scope
|
||||
if scope && (scoped_group = scope[:group])
|
||||
sql << " GROUP BY #{scoped_group}"
|
||||
sql << " HAVING #{scoped_having}" if (scoped_having = scope[:having])
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -2259,7 +2262,7 @@ module ActiveRecord #:nodoc:
|
||||
end
|
||||
|
||||
VALID_FIND_OPTIONS = [ :conditions, :include, :joins, :limit, :offset,
|
||||
:order, :select, :readonly, :group, :from, :lock ]
|
||||
:order, :select, :readonly, :group, :having, :from, :lock ]
|
||||
|
||||
def validate_find_options(options) #:nodoc:
|
||||
options.assert_valid_keys(VALID_FIND_OPTIONS)
|
||||
|
||||
@@ -658,6 +658,11 @@ class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase
|
||||
assert_equal 1, categories(:technology).posts_gruoped_by_title.size
|
||||
end
|
||||
|
||||
def test_find_scoped_grouped_having
|
||||
assert_equal 2, projects(:active_record).well_payed_salary_groups.size
|
||||
assert projects(:active_record).well_payed_salary_groups.all? { |g| g.salary > 10000 }
|
||||
end
|
||||
|
||||
def test_get_ids
|
||||
assert_equal projects(:active_record, :action_controller).map(&:id).sort, developers(:david).project_ids.sort
|
||||
assert_equal [projects(:active_record).id], developers(:jamis).project_ids
|
||||
|
||||
@@ -255,6 +255,11 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
|
||||
assert_equal 2, companies(:first_firm).clients_grouped_by_name.length
|
||||
end
|
||||
|
||||
def test_find_scoped_grouped_having
|
||||
assert_equal 1, authors(:david).popular_grouped_posts.length
|
||||
assert_equal 0, authors(:mary).popular_grouped_posts.length
|
||||
end
|
||||
|
||||
def test_adding
|
||||
force_signal37_to_load_all_clients_of_firm
|
||||
natural = Client.new("name" => "Natural Company")
|
||||
|
||||
@@ -175,6 +175,13 @@ class FinderTest < ActiveRecord::TestCase
|
||||
assert_equal 4, developers.map(&:salary).uniq.size
|
||||
end
|
||||
|
||||
def test_find_with_group_and_having
|
||||
developers = Developer.find(:all, :group => "salary", :having => "sum(salary) > 10000", :select => "salary")
|
||||
assert_equal 3, developers.size
|
||||
assert_equal 3, developers.map(&:salary).uniq.size
|
||||
assert developers.all? { |developer| developer.salary > 10000 }
|
||||
end
|
||||
|
||||
def test_find_with_entire_select_statement
|
||||
topics = Topic.find_by_sql "SELECT * FROM topics WHERE author_name = 'Mary'"
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
class Author < ActiveRecord::Base
|
||||
has_many :posts
|
||||
has_many :posts_with_comments, :include => :comments, :class_name => "Post"
|
||||
has_many :popular_grouped_posts, :include => :comments, :class_name => "Post", :group => "type", :having => "SUM(comments_count) > 1", :select => "type"
|
||||
has_many :posts_with_comments_sorted_by_comment_id, :include => :comments, :class_name => "Post", :order => 'comments.id'
|
||||
has_many :posts_sorted_by_id_limited, :class_name => "Post", :order => 'posts.id', :limit => 1
|
||||
has_many :posts_with_categories, :include => :categories, :class_name => "Post"
|
||||
|
||||
@@ -14,6 +14,7 @@ class Category < ActiveRecord::Base
|
||||
:class_name => 'Post',
|
||||
:conditions => { :title => 'Yet Another Testing Title' }
|
||||
|
||||
has_and_belongs_to_many :popular_grouped_posts, :class_name => "Post", :group => "posts.type", :having => "sum(comments.post_id) > 2", :include => :comments
|
||||
has_and_belongs_to_many :posts_gruoped_by_title, :class_name => "Post", :group => "title", :select => "title"
|
||||
|
||||
def self.what_are_you
|
||||
|
||||
@@ -13,6 +13,7 @@ class Project < ActiveRecord::Base
|
||||
:after_add => Proc.new {|o, r| o.developers_log << "after_adding#{r.id || '<new>'}"},
|
||||
:before_remove => Proc.new {|o, r| o.developers_log << "before_removing#{r.id}"},
|
||||
:after_remove => Proc.new {|o, r| o.developers_log << "after_removing#{r.id}"}
|
||||
has_and_belongs_to_many :well_payed_salary_groups, :class_name => "Developer", :group => "salary", :having => "SUM(salary) > 10000", :select => "SUM(salary) as salary"
|
||||
|
||||
attr_accessor :developers_log
|
||||
|
||||
|
||||
@@ -704,6 +704,7 @@ module ActiveResource
|
||||
def new?
|
||||
id.nil?
|
||||
end
|
||||
alias :new_record? :new?
|
||||
|
||||
# Gets the <tt>\id</tt> attribute of the resource.
|
||||
def id
|
||||
|
||||
@@ -1,6 +1,51 @@
|
||||
*2.3.0 [Edge]*
|
||||
|
||||
* Enhanced Rails.root to take parameters that'll be join with the root, like Rails.root('app', 'controllers') => File.join(Rails.root, 'app', 'controllers') #1482 [Damian Janowski]
|
||||
* Add "-m/--template" option to Rails generator to apply a template to the generated application. [Jeremy McAnally]
|
||||
|
||||
This has been extracted from rg - http://github.com/jeremymcanally/rg
|
||||
|
||||
Example:
|
||||
|
||||
# template.rb
|
||||
|
||||
# Install plugins from git or svn
|
||||
plugin "will-paginate", :git => "git://github.com/mislav/will_paginate.git"
|
||||
plugin "old-restful-auth", :svn => "http://svn.techno-weenie.net/projects/plugins/restful_authentication/"
|
||||
|
||||
# Add gems to environment.rb
|
||||
gem "jeremymcanally-context"
|
||||
gem "bluecloth"
|
||||
|
||||
# Vendor file. Data in a string or...
|
||||
vendor("borrowed.rb", <<CODE
|
||||
def helpful_method
|
||||
do_something_helpful_here
|
||||
end
|
||||
CODE
|
||||
|
||||
# ...file data from block return value.
|
||||
# #initializer creates a new initializer file
|
||||
initializer("crypto.rb") do
|
||||
salt = "--#{Time.now}--#{rand}--#{srand(Time.now.to_i)}"
|
||||
|
||||
"SPECIAL_SALT = '#{salt}'"
|
||||
end
|
||||
|
||||
Usage:
|
||||
|
||||
To use a template, provide a file path or URL:
|
||||
|
||||
1. Using a local file :
|
||||
|
||||
rails <application name> -m /path/to/my/template.rb
|
||||
|
||||
2. Or directly from a URL :
|
||||
|
||||
rails <application name> --template=http://gist.github.com/31208.txt
|
||||
|
||||
* Extracted the process scripts (inspector, reaper, spawner) into the plugin irs_process_scripts [DHH]
|
||||
|
||||
* Changed Rails.root to return a Pathname object (allows for Rails.root.join('app', 'controllers') => "#{RAILS_ROOT}/app/controllers") #1482 [Damian Janowski/?]
|
||||
|
||||
* Added view path support for engines [DHH]
|
||||
|
||||
|
||||
@@ -53,7 +53,6 @@ BASE_DIRS = %w(
|
||||
public
|
||||
script
|
||||
script/performance
|
||||
script/process
|
||||
test
|
||||
vendor
|
||||
vendor/plugins
|
||||
@@ -71,7 +70,7 @@ LOG_FILES = %w( server.log development.log test.log production.log )
|
||||
HTML_FILES = %w( 422.html 404.html 500.html index.html robots.txt favicon.ico images/rails.png
|
||||
javascripts/prototype.js javascripts/application.js
|
||||
javascripts/effects.js javascripts/dragdrop.js javascripts/controls.js )
|
||||
BIN_FILES = %w( about console destroy generate performance/benchmarker performance/profiler process/reaper process/spawner process/inspector runner server plugin )
|
||||
BIN_FILES = %w( about console destroy generate performance/benchmarker performance/profiler runner server plugin )
|
||||
|
||||
VENDOR_LIBS = %w( actionpack activerecord actionmailer activesupport activeresource railties )
|
||||
|
||||
@@ -174,9 +173,6 @@ task :copy_dispatches do
|
||||
|
||||
copy_with_rewritten_ruby_path("dispatches/dispatch.fcgi", "#{PKG_DESTINATION}/public/dispatch.fcgi")
|
||||
chmod 0755, "#{PKG_DESTINATION}/public/dispatch.fcgi"
|
||||
|
||||
# copy_with_rewritten_ruby_path("dispatches/gateway.cgi", "#{PKG_DESTINATION}/public/gateway.cgi")
|
||||
# chmod 0755, "#{PKG_DESTINATION}/public/gateway.cgi"
|
||||
end
|
||||
|
||||
task :copy_html_files do
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
#!/usr/bin/env ruby
|
||||
require File.dirname(__FILE__) + '/../../config/boot'
|
||||
require 'commands/process/inspector'
|
||||
@@ -1,3 +0,0 @@
|
||||
#!/usr/bin/env ruby
|
||||
require File.dirname(__FILE__) + '/../../config/boot'
|
||||
require 'commands/process/reaper'
|
||||
@@ -1,3 +0,0 @@
|
||||
#!/usr/bin/env ruby
|
||||
require File.dirname(__FILE__) + '/../../config/boot'
|
||||
require 'commands/process/spawner'
|
||||
@@ -8,6 +8,7 @@ if %w(--version -v).include? ARGV.first
|
||||
end
|
||||
|
||||
freeze = ARGV.any? { |option| %w(--freeze -f).include?(option) }
|
||||
|
||||
app_path = ARGV.first
|
||||
|
||||
require File.dirname(__FILE__) + '/../lib/rails_generator'
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
# Rackup Configuration
|
||||
#
|
||||
# Start Rails mongrel server with rackup
|
||||
# $ rackup -p 3000 config.ru
|
||||
#
|
||||
# Start server with webrick (or any compatible Rack server) instead
|
||||
# $ rackup -p 3000 -s webrick config.ru
|
||||
|
||||
# Require your environment file to bootstrap Rails
|
||||
require File.dirname(__FILE__) + '/config/environment'
|
||||
|
||||
# Static server middleware
|
||||
# You can remove this extra check if you use an asset server
|
||||
use Rails::Rack::Static
|
||||
|
||||
# Dispatch the request
|
||||
run ActionController::Dispatcher.new
|
||||
@@ -1,3 +1,5 @@
|
||||
# Be sure to restart your server when you modify this file.
|
||||
|
||||
# These settings change the behavior of Rails 2 apps and will be defaults
|
||||
# for Rails 3. You can remove this initializer when Rails 3 is released.
|
||||
|
||||
|
||||
15
railties/configs/initializers/session_store.rb
Normal file
15
railties/configs/initializers/session_store.rb
Normal file
@@ -0,0 +1,15 @@
|
||||
# Be sure to restart your server when you modify this file.
|
||||
|
||||
# Your secret key for verifying cookie session data integrity.
|
||||
# If you change this key, all old sessions will become invalid!
|
||||
# Make sure the secret is at least 30 characters and all random,
|
||||
# no regular words or you'll be exposed to dictionary attacks.
|
||||
ActionController::Base.session = {
|
||||
:session_key => '_<%= app_name %>_session',
|
||||
:secret => '<%= app_secret %>'
|
||||
}
|
||||
|
||||
# Use the database for sessions instead of the cookie-based default,
|
||||
# which shouldn't be used to store highly confidential information
|
||||
# (create the session table with "rake db:sessions:create")
|
||||
# ActionController::Base.session_store = :active_record_store
|
||||
7
railties/dispatches/config.ru
Normal file
7
railties/dispatches/config.ru
Normal file
@@ -0,0 +1,7 @@
|
||||
# Rack Dispatcher
|
||||
|
||||
# Require your environment file to bootstrap Rails
|
||||
require File.dirname(__FILE__) + '/config/environment'
|
||||
|
||||
# Dispatch the request
|
||||
run ActionController::Dispatcher.new
|
||||
@@ -1,9 +1,5 @@
|
||||
# Be sure to restart your server when you modify this file
|
||||
|
||||
# Uncomment below to force Rails into production mode when
|
||||
# you don't control web/app server and can't set it the proper way
|
||||
# ENV['RAILS_ENV'] ||= 'production'
|
||||
|
||||
# Specifies gem version of Rails to use when vendor/rails is not present
|
||||
<%= '# ' if freeze %>RAILS_GEM_VERSION = '<%= Rails::VERSION::STRING %>' unless defined? RAILS_GEM_VERSION
|
||||
|
||||
@@ -14,62 +10,32 @@ Rails::Initializer.run do |config|
|
||||
# Settings in config/environments/* take precedence over those specified here.
|
||||
# Application configuration should go into files in config/initializers
|
||||
# -- all .rb files in that directory are automatically loaded.
|
||||
# See Rails::Configuration for more options.
|
||||
|
||||
# Skip frameworks you're not going to use. To use Rails without a database
|
||||
# you must remove the Active Record framework.
|
||||
# config.frameworks -= [ :active_record, :active_resource, :action_mailer ]
|
||||
# Add additional load paths for your own custom dirs
|
||||
# config.load_paths += %W( #{RAILS_ROOT}/extras )
|
||||
|
||||
# Specify gems that this application depends on.
|
||||
# They can then be installed with "rake gems:install" on new installations.
|
||||
# You have to specify the :lib option for libraries, where the Gem name (sqlite3-ruby) differs from the file itself (sqlite3)
|
||||
# Specify gems that this application depends on and have them installed with rake gems:install
|
||||
# config.gem "bj"
|
||||
# config.gem "hpricot", :version => '0.6', :source => "http://code.whytheluckystiff.net"
|
||||
# config.gem "sqlite3-ruby", :lib => "sqlite3"
|
||||
# config.gem "aws-s3", :lib => "aws/s3"
|
||||
|
||||
# Only load the plugins named here, in the order given. By default, all plugins
|
||||
# in vendor/plugins are loaded in alphabetical order.
|
||||
# Only load the plugins named here, in the order given (default is alphabetical).
|
||||
# :all can be used as a placeholder for all plugins not explicitly named
|
||||
# config.plugins = [ :exception_notification, :ssl_requirement, :all ]
|
||||
|
||||
# Add additional load paths for your own custom dirs
|
||||
# config.load_paths += %W( #{RAILS_ROOT}/extras )
|
||||
|
||||
# Force all environments to use the same logger level
|
||||
# (by default production uses :info, the others :debug)
|
||||
# config.log_level = :debug
|
||||
|
||||
# Make Time.zone default to the specified zone, and make Active Record store time values
|
||||
# in the database in UTC, and return them converted to the specified local zone.
|
||||
# Run "rake -D time" for a list of tasks for finding time zone names. Comment line to use default local time.
|
||||
config.time_zone = 'UTC'
|
||||
|
||||
# The internationalization framework can be changed to have another default locale (standard is :en) or more load paths.
|
||||
# All files from config/locales/*.rb,yml are added automatically.
|
||||
# config.i18n.load_path << Dir[File.join(RAILS_ROOT, 'my', 'locales', '*.{rb,yml}')]
|
||||
# config.i18n.default_locale = :de
|
||||
|
||||
# Your secret key for verifying cookie session data integrity.
|
||||
# If you change this key, all old sessions will become invalid!
|
||||
# Make sure the secret is at least 30 characters and all random,
|
||||
# no regular words or you'll be exposed to dictionary attacks.
|
||||
config.action_controller.session = {
|
||||
:session_key => '_<%= app_name %>_session',
|
||||
:secret => '<%= app_secret %>'
|
||||
}
|
||||
|
||||
# Use the database for sessions instead of the cookie-based default,
|
||||
# which shouldn't be used to store highly confidential information
|
||||
# (create the session table with "rake db:sessions:create")
|
||||
# config.action_controller.session_store = :active_record_store
|
||||
|
||||
# Use SQL instead of Active Record's schema dumper when creating the test database.
|
||||
# This is necessary if your schema can't be completely dumped by the schema dumper,
|
||||
# like if you have constraints or database-specific column types
|
||||
# config.active_record.schema_format = :sql
|
||||
# Skip frameworks you're not going to use. To use Rails without a database,
|
||||
# you must remove the Active Record framework.
|
||||
# config.frameworks -= [ :active_record, :active_resource, :action_mailer ]
|
||||
|
||||
# Activate observers that should always be running
|
||||
# Please note that observers generated using script/generate observer need to have an _observer suffix
|
||||
# config.active_record.observers = :cacher, :garbage_collector, :forum_observer
|
||||
end
|
||||
|
||||
# Set Time.zone default to the specified zone and make Active Record auto-convert to this zone.
|
||||
# Run "rake -D time" for a list of tasks for finding time zone names.
|
||||
config.time_zone = 'UTC'
|
||||
|
||||
# The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded.
|
||||
# config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}')]
|
||||
# config.i18n.default_locale = :de
|
||||
end
|
||||
@@ -4,21 +4,24 @@
|
||||
# Code is not reloaded between requests
|
||||
config.cache_classes = true
|
||||
|
||||
# Enable threaded mode
|
||||
# config.threadsafe!
|
||||
|
||||
# Use a different logger for distributed setups
|
||||
# config.logger = SyslogLogger.new
|
||||
|
||||
# Full error reports are disabled and caching is turned on
|
||||
config.action_controller.consider_all_requests_local = false
|
||||
config.action_controller.perform_caching = true
|
||||
|
||||
# See everything in the log (default is :info)
|
||||
# config.log_level = :debug
|
||||
|
||||
# Use a different logger for distributed setups
|
||||
# config.logger = SyslogLogger.new
|
||||
|
||||
# Use a different cache store in production
|
||||
# config.cache_store = :mem_cache_store
|
||||
|
||||
# Enable serving of images, stylesheets, and javascripts from an asset server
|
||||
# config.action_controller.asset_host = "http://assets.example.com"
|
||||
# config.action_controller.asset_host = "http://assets.example.com"
|
||||
|
||||
# Disable delivery errors, bad email addresses will be ignored
|
||||
# config.action_mailer.raise_delivery_errors = false
|
||||
|
||||
# Enable threaded mode
|
||||
# config.threadsafe!
|
||||
@@ -20,3 +20,8 @@ config.action_controller.allow_forgery_protection = false
|
||||
# The :test delivery method accumulates sent emails in the
|
||||
# ActionMailer::Base.deliveries array.
|
||||
config.action_mailer.delivery_method = :test
|
||||
|
||||
# Use SQL instead of Active Record's schema dumper when creating the test database.
|
||||
# This is necessary if your schema can't be completely dumped by the schema dumper,
|
||||
# like if you have constraints or database-specific column types
|
||||
# config.active_record.schema_format = :sql
|
||||
@@ -3,12 +3,8 @@
|
||||
|
||||
class ApplicationController < ActionController::Base
|
||||
helper :all # include all helpers, all the time
|
||||
protect_from_forgery # See ActionController::RequestForgeryProtection for details
|
||||
|
||||
# See ActionController::RequestForgeryProtection for details
|
||||
protect_from_forgery
|
||||
|
||||
# See ActionController::Base for details
|
||||
# Uncomment this to filter the contents of submitted sensitive data parameters
|
||||
# from your application log (in this case, all fields with names like "password").
|
||||
# Scrub sensitive parameters from your log
|
||||
# filter_parameter_logging :password
|
||||
end
|
||||
|
||||
@@ -1,68 +0,0 @@
|
||||
require 'optparse'
|
||||
|
||||
if RUBY_PLATFORM =~ /(:?mswin|mingw)/ then abort("Inspector is only for Unix") end
|
||||
|
||||
OPTIONS = {
|
||||
:pid_path => File.expand_path(RAILS_ROOT + '/tmp/pids'),
|
||||
:pattern => "dispatch.*.pid",
|
||||
:ps => "ps -o pid,state,user,start,time,pcpu,vsz,majflt,command -p %s"
|
||||
}
|
||||
|
||||
class Inspector
|
||||
def self.inspect(pid_path, pattern)
|
||||
new(pid_path, pattern).inspect
|
||||
end
|
||||
|
||||
def initialize(pid_path, pattern)
|
||||
@pid_path, @pattern = pid_path, pattern
|
||||
end
|
||||
|
||||
def inspect
|
||||
header = `#{OPTIONS[:ps] % 1}`.split("\n")[0] + "\n"
|
||||
lines = pids.collect { |pid| `#{OPTIONS[:ps] % pid}`.split("\n")[1] }
|
||||
|
||||
puts(header + lines.join("\n"))
|
||||
end
|
||||
|
||||
private
|
||||
def pids
|
||||
pid_files.collect do |pid_file|
|
||||
File.read(pid_file).to_i
|
||||
end
|
||||
end
|
||||
|
||||
def pid_files
|
||||
Dir.glob(@pid_path + "/" + @pattern)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
ARGV.options do |opts|
|
||||
opts.banner = "Usage: inspector [options]"
|
||||
|
||||
opts.separator ""
|
||||
|
||||
opts.on <<-EOF
|
||||
Description:
|
||||
Displays system information about Rails dispatchers (or other processes that use pid files) through
|
||||
the ps command.
|
||||
|
||||
Examples:
|
||||
inspector # default ps on all tmp/pids/dispatch.*.pid files
|
||||
inspector -s 'ps -o user,start,majflt,pcpu,vsz -p %s' # custom ps, %s is where the pid is interleaved
|
||||
EOF
|
||||
|
||||
opts.on(" Options:")
|
||||
|
||||
opts.on("-s", "--ps=command", "default: #{OPTIONS[:ps]}", String) { |v| OPTIONS[:ps] = v }
|
||||
opts.on("-p", "--pidpath=path", "default: #{OPTIONS[:pid_path]}", String) { |v| OPTIONS[:pid_path] = v }
|
||||
opts.on("-r", "--pattern=pattern", "default: #{OPTIONS[:pattern]}", String) { |v| OPTIONS[:pattern] = v }
|
||||
|
||||
opts.separator ""
|
||||
|
||||
opts.on("-h", "--help", "Show this help message.") { puts opts; exit }
|
||||
|
||||
opts.parse!
|
||||
end
|
||||
|
||||
Inspector.inspect(OPTIONS[:pid_path], OPTIONS[:pattern])
|
||||
@@ -1,149 +0,0 @@
|
||||
require 'optparse'
|
||||
require 'net/http'
|
||||
require 'uri'
|
||||
|
||||
if RUBY_PLATFORM =~ /(:?mswin|mingw)/ then abort("Reaper is only for Unix") end
|
||||
|
||||
class Killer
|
||||
class << self
|
||||
# Searches for all processes matching the given keywords, and then invokes
|
||||
# a specific action on each of them. This is useful for (e.g.) reloading a
|
||||
# set of processes:
|
||||
#
|
||||
# Killer.process(:reload, "/tmp/pids", "dispatcher.*.pid")
|
||||
def process(action, pid_path, pattern, keyword)
|
||||
new(pid_path, pattern, keyword).process(action)
|
||||
end
|
||||
|
||||
# Forces the (rails) application to reload by sending a +HUP+ signal to the
|
||||
# process.
|
||||
def reload(pid)
|
||||
`kill -s HUP #{pid}`
|
||||
end
|
||||
|
||||
# Force the (rails) application to restart by sending a +USR2+ signal to the
|
||||
# process.
|
||||
def restart(pid)
|
||||
`kill -s USR2 #{pid}`
|
||||
end
|
||||
|
||||
# Forces the (rails) application to gracefully terminate by sending a
|
||||
# +TERM+ signal to the process.
|
||||
def graceful(pid)
|
||||
`kill -s TERM #{pid}`
|
||||
end
|
||||
|
||||
# Forces the (rails) application to terminate immediately by sending a -9
|
||||
# signal to the process.
|
||||
def kill(pid)
|
||||
`kill -9 #{pid}`
|
||||
end
|
||||
|
||||
# Send a +USR1+ signal to the process.
|
||||
def usr1(pid)
|
||||
`kill -s USR1 #{pid}`
|
||||
end
|
||||
end
|
||||
|
||||
def initialize(pid_path, pattern, keyword=nil)
|
||||
@pid_path, @pattern, @keyword = pid_path, pattern, keyword
|
||||
end
|
||||
|
||||
def process(action)
|
||||
pids = find_processes
|
||||
|
||||
if pids.empty?
|
||||
warn "Couldn't find any pid file in '#{@pid_path}' matching '#{@pattern}'"
|
||||
warn "(also looked for processes matching #{@keyword.inspect})" if @keyword
|
||||
else
|
||||
pids.each do |pid|
|
||||
puts "#{action.capitalize}ing #{pid}"
|
||||
self.class.send(action, pid)
|
||||
end
|
||||
|
||||
delete_pid_files if terminating?(action)
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
def terminating?(action)
|
||||
[ "kill", "graceful" ].include?(action)
|
||||
end
|
||||
|
||||
def find_processes
|
||||
files = pid_files
|
||||
if files.empty?
|
||||
find_processes_via_grep
|
||||
else
|
||||
files.collect { |pid_file| File.read(pid_file).to_i }
|
||||
end
|
||||
end
|
||||
|
||||
def find_processes_via_grep
|
||||
lines = `ps axww -o 'pid command' | grep #{@keyword}`.split(/\n/).
|
||||
reject { |line| line =~ /inq|ps axww|grep|spawn-fcgi|spawner|reaper/ }
|
||||
lines.map { |line| line[/^\s*(\d+)/, 1].to_i }
|
||||
end
|
||||
|
||||
def delete_pid_files
|
||||
pid_files.each { |pid_file| File.delete(pid_file) }
|
||||
end
|
||||
|
||||
def pid_files
|
||||
Dir.glob(@pid_path + "/" + @pattern)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
OPTIONS = {
|
||||
:action => "restart",
|
||||
:pid_path => File.expand_path(RAILS_ROOT + '/tmp/pids'),
|
||||
:pattern => "dispatch.[0-9]*.pid",
|
||||
:dispatcher => File.expand_path("#{RAILS_ROOT}/public/dispatch.fcgi")
|
||||
}
|
||||
|
||||
ARGV.options do |opts|
|
||||
opts.banner = "Usage: reaper [options]"
|
||||
|
||||
opts.separator ""
|
||||
|
||||
opts.on <<-EOF
|
||||
Description:
|
||||
The reaper is used to restart, reload, gracefully exit, and forcefully exit processes
|
||||
running a Rails Dispatcher (or any other process responding to the same signals). This
|
||||
is commonly done when a new version of the application is available, so the existing
|
||||
processes can be updated to use the latest code.
|
||||
|
||||
It uses pid files to work on the processes and by default assume them to be located
|
||||
in RAILS_ROOT/tmp/pids.
|
||||
|
||||
The reaper actions are:
|
||||
|
||||
* restart : Restarts the application by reloading both application and framework code
|
||||
* reload : Only reloads the application, but not the framework (like the development environment)
|
||||
* graceful: Marks all of the processes for exit after the next request
|
||||
* kill : Forcefully exists all processes regardless of whether they're currently serving a request
|
||||
|
||||
Restart is the most common and default action.
|
||||
|
||||
Examples:
|
||||
reaper # restarts the default dispatchers
|
||||
reaper -a reload # reload the default dispatchers
|
||||
reaper -a kill -r *.pid # kill all processes that keep pids in tmp/pids
|
||||
EOF
|
||||
|
||||
opts.on(" Options:")
|
||||
|
||||
opts.on("-a", "--action=name", "reload|graceful|kill (default: #{OPTIONS[:action]})", String) { |v| OPTIONS[:action] = v }
|
||||
opts.on("-p", "--pidpath=path", "default: #{OPTIONS[:pid_path]}", String) { |v| OPTIONS[:pid_path] = v }
|
||||
opts.on("-r", "--pattern=pattern", "default: #{OPTIONS[:pattern]}", String) { |v| OPTIONS[:pattern] = v }
|
||||
opts.on("-d", "--dispatcher=path", "DEPRECATED. default: #{OPTIONS[:dispatcher]}", String) { |v| OPTIONS[:dispatcher] = v }
|
||||
|
||||
opts.separator ""
|
||||
|
||||
opts.on("-h", "--help", "Show this help message.") { puts opts; exit }
|
||||
|
||||
opts.parse!
|
||||
end
|
||||
|
||||
Killer.process(OPTIONS[:action], OPTIONS[:pid_path], OPTIONS[:pattern], OPTIONS[:dispatcher])
|
||||
@@ -1,219 +0,0 @@
|
||||
require 'active_support'
|
||||
require 'optparse'
|
||||
require 'socket'
|
||||
require 'fileutils'
|
||||
|
||||
def daemonize #:nodoc:
|
||||
exit if fork # Parent exits, child continues.
|
||||
Process.setsid # Become session leader.
|
||||
exit if fork # Zap session leader. See [1].
|
||||
Dir.chdir "/" # Release old working directory.
|
||||
File.umask 0000 # Ensure sensible umask. Adjust as needed.
|
||||
STDIN.reopen "/dev/null" # Free file descriptors and
|
||||
STDOUT.reopen "/dev/null", "a" # point them somewhere sensible.
|
||||
STDERR.reopen STDOUT # STDOUT/ERR should better go to a logfile.
|
||||
end
|
||||
|
||||
class Spawner
|
||||
def self.record_pid(name = "#{OPTIONS[:process]}.spawner", id = Process.pid)
|
||||
FileUtils.mkdir_p(OPTIONS[:pids])
|
||||
File.open(File.expand_path(OPTIONS[:pids] + "/#{name}.pid"), "w+") { |f| f.write(id) }
|
||||
end
|
||||
|
||||
def self.spawn_all
|
||||
OPTIONS[:instances].times do |i|
|
||||
port = OPTIONS[:port] + i
|
||||
print "Checking if something is already running on #{OPTIONS[:address]}:#{port}..."
|
||||
|
||||
begin
|
||||
srv = TCPServer.new(OPTIONS[:address], port)
|
||||
srv.close
|
||||
srv = nil
|
||||
|
||||
puts "NO"
|
||||
puts "Starting dispatcher on port: #{OPTIONS[:address]}:#{port}"
|
||||
|
||||
FileUtils.mkdir_p(OPTIONS[:pids])
|
||||
spawn(port)
|
||||
rescue
|
||||
puts "YES"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
class FcgiSpawner < Spawner
|
||||
def self.spawn(port)
|
||||
cmd = "#{OPTIONS[:spawner]} -f #{OPTIONS[:dispatcher]} -p #{port} -P #{OPTIONS[:pids]}/#{OPTIONS[:process]}.#{port}.pid"
|
||||
cmd << " -a #{OPTIONS[:address]}" if can_bind_to_custom_address?
|
||||
system(cmd)
|
||||
end
|
||||
|
||||
def self.can_bind_to_custom_address?
|
||||
@@can_bind_to_custom_address ||= /^\s-a\s/.match `#{OPTIONS[:spawner]} -h`
|
||||
end
|
||||
end
|
||||
|
||||
class MongrelSpawner < Spawner
|
||||
def self.spawn(port)
|
||||
cmd =
|
||||
"mongrel_rails start -d " +
|
||||
"-a #{OPTIONS[:address]} " +
|
||||
"-p #{port} " +
|
||||
"-P #{OPTIONS[:pids]}/#{OPTIONS[:process]}.#{port}.pid " +
|
||||
"-e #{OPTIONS[:environment]} " +
|
||||
"-c #{OPTIONS[:rails_root]} " +
|
||||
"-l #{OPTIONS[:rails_root]}/log/mongrel.log"
|
||||
|
||||
# Add prefix functionality to spawner's call to mongrel_rails
|
||||
# Digging through mongrel's project subversion server, the earliest
|
||||
# Tag that has prefix implemented in the bin/mongrel_rails file
|
||||
# is 0.3.15 which also happens to be the earliest tag listed.
|
||||
# References: http://mongrel.rubyforge.org/svn/tags
|
||||
if Mongrel::Const::MONGREL_VERSION.to_f >=0.3 && !OPTIONS[:prefix].nil?
|
||||
cmd = cmd + " --prefix #{OPTIONS[:prefix]}"
|
||||
end
|
||||
system(cmd)
|
||||
end
|
||||
|
||||
def self.can_bind_to_custom_address?
|
||||
true
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
begin
|
||||
require_library_or_gem 'fcgi'
|
||||
rescue Exception
|
||||
# FCGI not available
|
||||
end
|
||||
|
||||
begin
|
||||
require_library_or_gem 'mongrel'
|
||||
rescue Exception
|
||||
# Mongrel not available
|
||||
end
|
||||
|
||||
server = case ARGV.first
|
||||
when "fcgi", "mongrel"
|
||||
ARGV.shift
|
||||
else
|
||||
if defined?(Mongrel)
|
||||
"mongrel"
|
||||
elsif RUBY_PLATFORM !~ /(:?mswin|mingw)/ && !silence_stderr { `spawn-fcgi -version` }.blank? && defined?(FCGI)
|
||||
"fcgi"
|
||||
end
|
||||
end
|
||||
|
||||
case server
|
||||
when "fcgi"
|
||||
puts "=> Starting FCGI dispatchers"
|
||||
spawner_class = FcgiSpawner
|
||||
when "mongrel"
|
||||
puts "=> Starting mongrel dispatchers"
|
||||
spawner_class = MongrelSpawner
|
||||
else
|
||||
puts "Neither FCGI (spawn-fcgi) nor Mongrel was installed and available!"
|
||||
exit(0)
|
||||
end
|
||||
|
||||
|
||||
|
||||
OPTIONS = {
|
||||
:environment => "production",
|
||||
:spawner => '/usr/bin/env spawn-fcgi',
|
||||
:dispatcher => File.expand_path(RELATIVE_RAILS_ROOT + '/public/dispatch.fcgi'),
|
||||
:pids => File.expand_path(RELATIVE_RAILS_ROOT + "/tmp/pids"),
|
||||
:rails_root => File.expand_path(RELATIVE_RAILS_ROOT),
|
||||
:process => "dispatch",
|
||||
:port => 8000,
|
||||
:address => '0.0.0.0',
|
||||
:instances => 3,
|
||||
:repeat => nil,
|
||||
:prefix => nil
|
||||
}
|
||||
|
||||
ARGV.options do |opts|
|
||||
opts.banner = "Usage: spawner [platform] [options]"
|
||||
|
||||
opts.separator ""
|
||||
|
||||
opts.on <<-EOF
|
||||
Description:
|
||||
The spawner is a wrapper for spawn-fcgi and mongrel that makes it
|
||||
easier to start multiple processes running the Rails dispatcher. The
|
||||
spawn-fcgi command is included with the lighttpd web server, but can
|
||||
be used with both Apache and lighttpd (and any other web server
|
||||
supporting externally managed FCGI processes). Mongrel automatically
|
||||
ships with with mongrel_rails for starting dispatchers.
|
||||
|
||||
The first choice you need to make is whether to spawn the Rails
|
||||
dispatchers as FCGI or Mongrel. By default, this spawner will prefer
|
||||
Mongrel, so if that's installed, and no platform choice is made,
|
||||
Mongrel is used.
|
||||
|
||||
Then decide a starting port (default is 8000) and the number of FCGI
|
||||
process instances you'd like to run. So if you pick 9100 and 3
|
||||
instances, you'll start processes on 9100, 9101, and 9102.
|
||||
|
||||
By setting the repeat option, you get a protection loop, which will
|
||||
attempt to restart any FCGI processes that might have been exited or
|
||||
outright crashed.
|
||||
|
||||
You can select bind address for started processes. By default these
|
||||
listen on every interface. For single machine installations you would
|
||||
probably want to use 127.0.0.1, hiding them form the outside world.
|
||||
|
||||
Examples:
|
||||
spawner # starts instances on 8000, 8001, and 8002
|
||||
# using Mongrel if available.
|
||||
spawner fcgi # starts instances on 8000, 8001, and 8002
|
||||
# using FCGI.
|
||||
spawner mongrel -i 5 # starts instances on 8000, 8001, 8002,
|
||||
# 8003, and 8004 using Mongrel.
|
||||
spawner -p 9100 -i 10 # starts 10 instances counting from 9100 to
|
||||
# 9109 using Mongrel if available.
|
||||
spawner -p 9100 -r 5 # starts 3 instances counting from 9100 to
|
||||
# 9102 and attempts start them every 5
|
||||
# seconds.
|
||||
spawner -a 127.0.0.1 # starts 3 instances binding to localhost
|
||||
EOF
|
||||
|
||||
opts.on(" Options:")
|
||||
|
||||
opts.on("-p", "--port=number", Integer, "Starting port number (default: #{OPTIONS[:port]})") { |v| OPTIONS[:port] = v }
|
||||
|
||||
if spawner_class.can_bind_to_custom_address?
|
||||
opts.on("-a", "--address=ip", String, "Bind to IP address (default: #{OPTIONS[:address]})") { |v| OPTIONS[:address] = v }
|
||||
end
|
||||
|
||||
opts.on("-p", "--port=number", Integer, "Starting port number (default: #{OPTIONS[:port]})") { |v| OPTIONS[:port] = v }
|
||||
opts.on("-i", "--instances=number", Integer, "Number of instances (default: #{OPTIONS[:instances]})") { |v| OPTIONS[:instances] = v }
|
||||
opts.on("-r", "--repeat=seconds", Integer, "Repeat spawn attempts every n seconds (default: off)") { |v| OPTIONS[:repeat] = v }
|
||||
opts.on("-e", "--environment=name", String, "test|development|production (default: #{OPTIONS[:environment]})") { |v| OPTIONS[:environment] = v }
|
||||
opts.on("-P", "--prefix=path", String, "URL prefix for Rails app. [Used only with Mongrel > v0.3.15]: (default: #{OPTIONS[:prefix]})") { |v| OPTIONS[:prefix] = v }
|
||||
opts.on("-n", "--process=name", String, "default: #{OPTIONS[:process]}") { |v| OPTIONS[:process] = v }
|
||||
opts.on("-s", "--spawner=path", String, "default: #{OPTIONS[:spawner]}") { |v| OPTIONS[:spawner] = v }
|
||||
opts.on("-d", "--dispatcher=path", String, "default: #{OPTIONS[:dispatcher]}") { |dispatcher| OPTIONS[:dispatcher] = File.expand_path(dispatcher) }
|
||||
|
||||
opts.separator ""
|
||||
|
||||
opts.on("-h", "--help", "Show this help message.") { puts opts; exit }
|
||||
|
||||
opts.parse!
|
||||
end
|
||||
|
||||
ENV["RAILS_ENV"] = OPTIONS[:environment]
|
||||
|
||||
if OPTIONS[:repeat]
|
||||
daemonize
|
||||
trap("TERM") { exit }
|
||||
spawner_class.record_pid
|
||||
|
||||
loop do
|
||||
spawner_class.spawn_all
|
||||
sleep(OPTIONS[:repeat])
|
||||
end
|
||||
else
|
||||
spawner_class.spawn_all
|
||||
end
|
||||
@@ -1,57 +0,0 @@
|
||||
require 'optparse'
|
||||
|
||||
def daemonize #:nodoc:
|
||||
exit if fork # Parent exits, child continues.
|
||||
Process.setsid # Become session leader.
|
||||
exit if fork # Zap session leader. See [1].
|
||||
Dir.chdir "/" # Release old working directory.
|
||||
File.umask 0000 # Ensure sensible umask. Adjust as needed.
|
||||
STDIN.reopen "/dev/null" # Free file descriptors and
|
||||
STDOUT.reopen "/dev/null", "a" # point them somewhere sensible.
|
||||
STDERR.reopen STDOUT # STDOUT/ERR should better go to a logfile.
|
||||
end
|
||||
|
||||
OPTIONS = {
|
||||
:interval => 5.0,
|
||||
:command => File.expand_path(RAILS_ROOT + '/script/process/spawner'),
|
||||
:daemon => false
|
||||
}
|
||||
|
||||
ARGV.options do |opts|
|
||||
opts.banner = "Usage: spinner [options]"
|
||||
|
||||
opts.separator ""
|
||||
|
||||
opts.on <<-EOF
|
||||
Description:
|
||||
The spinner is a protection loop for the spawner, which will attempt to restart any FCGI processes
|
||||
that might have been exited or outright crashed. It's a brute-force attempt that'll just try
|
||||
to run the spawner every X number of seconds, so it does pose a light load on the server.
|
||||
|
||||
Examples:
|
||||
spinner # attempts to run the spawner with default settings every second with output on the terminal
|
||||
spinner -i 3 -d # only run the spawner every 3 seconds and detach from the terminal to become a daemon
|
||||
spinner -c '/path/to/app/script/process/spawner -p 9000 -i 10' -d # using custom spawner
|
||||
EOF
|
||||
|
||||
opts.on(" Options:")
|
||||
|
||||
opts.on("-c", "--command=path", String) { |v| OPTIONS[:command] = v }
|
||||
opts.on("-i", "--interval=seconds", Float) { |v| OPTIONS[:interval] = v }
|
||||
opts.on("-d", "--daemon") { |v| OPTIONS[:daemon] = v }
|
||||
|
||||
opts.separator ""
|
||||
|
||||
opts.on("-h", "--help", "Show this help message.") { puts opts; exit }
|
||||
|
||||
opts.parse!
|
||||
end
|
||||
|
||||
daemonize if OPTIONS[:daemon]
|
||||
|
||||
trap(OPTIONS[:daemon] ? "TERM" : "INT") { exit }
|
||||
|
||||
loop do
|
||||
system(OPTIONS[:command])
|
||||
sleep(OPTIONS[:interval])
|
||||
end
|
||||
@@ -65,7 +65,6 @@ end
|
||||
|
||||
ENV["RAILS_ENV"] = options[:environment]
|
||||
RAILS_ENV.replace(options[:environment]) if defined?(RAILS_ENV)
|
||||
require RAILS_ROOT + "/config/environment"
|
||||
|
||||
if File.exist?(options[:config])
|
||||
config = options[:config]
|
||||
@@ -74,20 +73,23 @@ if File.exist?(options[:config])
|
||||
if cfgfile[/^#\\(.*)/]
|
||||
opts.parse!($1.split(/\s+/))
|
||||
end
|
||||
app = eval("Rack::Builder.new {( " + cfgfile + "\n )}.to_app", nil, config)
|
||||
inner_app = eval("Rack::Builder.new {( " + cfgfile + "\n )}.to_app", nil, config)
|
||||
else
|
||||
require config
|
||||
app = Object.const_get(File.basename(config, '.rb').capitalize)
|
||||
inner_app = Object.const_get(File.basename(config, '.rb').capitalize)
|
||||
end
|
||||
else
|
||||
app = Rack::Builder.new {
|
||||
use Rails::Rack::Logger
|
||||
use Rails::Rack::Static
|
||||
use Rails::Rack::Debugger if options[:debugger]
|
||||
run ActionController::Dispatcher.new
|
||||
}.to_app
|
||||
require RAILS_ROOT + "/config/environment"
|
||||
inner_app = ActionController::Dispatcher.new
|
||||
end
|
||||
|
||||
app = Rack::Builder.new {
|
||||
use Rails::Rack::Logger
|
||||
use Rails::Rack::Static
|
||||
use Rails::Rack::Debugger if options[:debugger]
|
||||
run inner_app
|
||||
}.to_app
|
||||
|
||||
puts "=> Call with -d to detach"
|
||||
|
||||
trap(:INT) { exit }
|
||||
|
||||
@@ -98,7 +98,7 @@ class RailsFCGIHandler
|
||||
|
||||
with_signal_handler 'USR1' do
|
||||
begin
|
||||
Dispatcher.dispatch(cgi)
|
||||
::Rack::Handler::FastCGI.serve(cgi, Dispatcher.new)
|
||||
rescue SignalException, SystemExit
|
||||
raise
|
||||
rescue Exception => error
|
||||
|
||||
@@ -48,8 +48,8 @@ module Rails
|
||||
end
|
||||
end
|
||||
|
||||
def root(*args)
|
||||
File.join(RAILS_ROOT, *args.compact) if defined?(RAILS_ROOT)
|
||||
def root
|
||||
Pathname.new(RAILS_ROOT) if defined?(RAILS_ROOT)
|
||||
end
|
||||
|
||||
def env
|
||||
@@ -513,10 +513,15 @@ Run `rake gems:install` to install the missing gems.
|
||||
def initialize_time_zone
|
||||
if configuration.time_zone
|
||||
zone_default = Time.__send__(:get_zone, configuration.time_zone)
|
||||
|
||||
unless zone_default
|
||||
raise %{Value assigned to config.time_zone not recognized. Run "rake -D time" for a list of tasks for finding appropriate time zone names.}
|
||||
raise \
|
||||
'Value assigned to config.time_zone not recognized.' +
|
||||
'Run "rake -D time" for a list of tasks for finding appropriate time zone names.'
|
||||
end
|
||||
|
||||
Time.zone_default = zone_default
|
||||
|
||||
if configuration.frameworks.include?(:active_record)
|
||||
ActiveRecord::Base.time_zone_aware_attributes = true
|
||||
ActiveRecord::Base.default_timezone = :utc
|
||||
@@ -876,6 +881,11 @@ Run `rake gems:install` to install the missing gems.
|
||||
end
|
||||
end
|
||||
|
||||
def middleware
|
||||
require 'action_controller'
|
||||
ActionController::Dispatcher.middleware
|
||||
end
|
||||
|
||||
def builtin_directories
|
||||
# Include builtins only in the development environment.
|
||||
(environment == 'development') ? Dir["#{RAILTIES_PATH}/builtin/*/"] : []
|
||||
|
||||
@@ -74,6 +74,7 @@ module Rails
|
||||
|
||||
def dependencies
|
||||
return [] if framework_gem?
|
||||
return [] if specification.nil?
|
||||
all_dependencies = specification.dependencies.map do |dependency|
|
||||
GemDependency.new(dependency.name, :requirement => dependency.version_requirements)
|
||||
end
|
||||
|
||||
@@ -154,6 +154,9 @@ module Rails
|
||||
File.join(destination_root, relative_destination)
|
||||
end
|
||||
|
||||
def after_generate
|
||||
end
|
||||
|
||||
protected
|
||||
# Convenience method for generator subclasses to record a manifest.
|
||||
def record
|
||||
|
||||
@@ -40,6 +40,7 @@ module Rails
|
||||
# Replay action manifest. RewindBase subclass rewinds manifest.
|
||||
def invoke!
|
||||
manifest.replay(self)
|
||||
after_generate
|
||||
end
|
||||
|
||||
def dependency(generator_name, args, runtime_options = {})
|
||||
|
||||
@@ -1,117 +1,46 @@
|
||||
require 'rbconfig'
|
||||
require File.dirname(__FILE__) + '/template_runner'
|
||||
require 'digest/md5'
|
||||
require 'active_support/secure_random'
|
||||
|
||||
class AppGenerator < Rails::Generator::Base
|
||||
DEFAULT_SHEBANG = File.join(Config::CONFIG['bindir'],
|
||||
Config::CONFIG['ruby_install_name'])
|
||||
DEFAULT_SHEBANG = File.join(Config::CONFIG['bindir'], Config::CONFIG['ruby_install_name'])
|
||||
|
||||
DATABASES = %w(mysql oracle postgresql sqlite2 sqlite3 frontbase ibm_db)
|
||||
DATABASES = %w( mysql oracle postgresql sqlite2 sqlite3 frontbase ibm_db )
|
||||
DEFAULT_DATABASE = 'sqlite3'
|
||||
|
||||
mandatory_options :source => "#{File.dirname(__FILE__)}/../../../../.."
|
||||
default_options :db => (ENV["RAILS_DEFAULT_DATABASE"] || DEFAULT_DATABASE),
|
||||
:shebang => DEFAULT_SHEBANG, :with_dispatchers => false, :freeze => false
|
||||
mandatory_options :source => "#{File.dirname(__FILE__)}/../../../../.."
|
||||
|
||||
|
||||
def initialize(runtime_args, runtime_options = {})
|
||||
super
|
||||
|
||||
usage if args.empty?
|
||||
usage("Databases supported for preconfiguration are: #{DATABASES.join(", ")}") if (options[:db] && !DATABASES.include?(options[:db]))
|
||||
|
||||
@destination_root = args.shift
|
||||
@app_name = File.basename(File.expand_path(@destination_root))
|
||||
end
|
||||
|
||||
def manifest
|
||||
# Use /usr/bin/env if no special shebang was specified
|
||||
script_options = { :chmod => 0755, :shebang => options[:shebang] == DEFAULT_SHEBANG ? nil : options[:shebang] }
|
||||
dispatcher_options = { :chmod => 0755, :shebang => options[:shebang] }
|
||||
|
||||
# duplicate CGI::Session#generate_unique_id
|
||||
md5 = Digest::MD5.new
|
||||
now = Time.now
|
||||
md5 << now.to_s
|
||||
md5 << String(now.usec)
|
||||
md5 << String(rand(0))
|
||||
md5 << String($$)
|
||||
md5 << @app_name
|
||||
|
||||
# Do our best to generate a secure secret key for CookieStore
|
||||
secret = ActiveSupport::SecureRandom.hex(64)
|
||||
|
||||
record do |m|
|
||||
# Root directory and all subdirectories.
|
||||
m.directory ''
|
||||
BASEDIRS.each { |path| m.directory path }
|
||||
create_directories(m)
|
||||
create_root_files(m)
|
||||
create_app_files(m)
|
||||
create_config_files(m)
|
||||
create_script_files(m)
|
||||
create_test_files(m)
|
||||
create_public_files(m)
|
||||
create_documentation_file(m)
|
||||
create_log_files(m)
|
||||
end
|
||||
end
|
||||
|
||||
# Root
|
||||
m.file "fresh_rakefile", "Rakefile"
|
||||
m.file "README", "README"
|
||||
|
||||
# Application
|
||||
m.template "helpers/application_controller.rb", "app/controllers/application_controller.rb", :assigns => {
|
||||
:app_name => @app_name, :app_secret => md5.hexdigest }
|
||||
m.template "helpers/application_helper.rb", "app/helpers/application_helper.rb"
|
||||
m.template "helpers/test_helper.rb", "test/test_helper.rb"
|
||||
m.template "helpers/performance_test.rb", "test/performance/browsing_test.rb"
|
||||
|
||||
# database.yml and routes.rb
|
||||
m.template "configs/databases/#{options[:db]}.yml", "config/database.yml", :assigns => {
|
||||
:app_name => @app_name,
|
||||
:socket => options[:db] == "mysql" ? mysql_socket_location : nil
|
||||
}
|
||||
m.template "configs/routes.rb", "config/routes.rb"
|
||||
|
||||
# Initializers
|
||||
m.template "configs/initializers/backtrace_silencers.rb", "config/initializers/backtrace_silencers.rb"
|
||||
m.template "configs/initializers/inflections.rb", "config/initializers/inflections.rb"
|
||||
m.template "configs/initializers/mime_types.rb", "config/initializers/mime_types.rb"
|
||||
m.template "configs/initializers/new_rails_defaults.rb", "config/initializers/new_rails_defaults.rb"
|
||||
|
||||
# Locale
|
||||
m.template "configs/locales/en.yml", "config/locales/en.yml"
|
||||
|
||||
# Environments
|
||||
m.file "environments/boot.rb", "config/boot.rb"
|
||||
m.template "environments/environment.rb", "config/environment.rb", :assigns => { :freeze => options[:freeze], :app_name => @app_name, :app_secret => secret }
|
||||
m.file "environments/production.rb", "config/environments/production.rb"
|
||||
m.file "environments/development.rb", "config/environments/development.rb"
|
||||
m.file "environments/test.rb", "config/environments/test.rb"
|
||||
|
||||
# Scripts
|
||||
%w( about console dbconsole destroy generate performance/benchmarker performance/profiler performance/request process/reaper process/spawner process/inspector runner server plugin ).each do |file|
|
||||
m.file "bin/#{file}", "script/#{file}", script_options
|
||||
end
|
||||
|
||||
# Dispatches
|
||||
if options[:with_dispatchers]
|
||||
m.file "dispatches/dispatch.rb", "public/dispatch.rb", dispatcher_options
|
||||
m.file "dispatches/dispatch.rb", "public/dispatch.cgi", dispatcher_options
|
||||
m.file "dispatches/dispatch.fcgi", "public/dispatch.fcgi", dispatcher_options
|
||||
end
|
||||
|
||||
# HTML files
|
||||
%w(404 422 500 index).each do |file|
|
||||
m.template "html/#{file}.html", "public/#{file}.html"
|
||||
end
|
||||
|
||||
m.template "html/favicon.ico", "public/favicon.ico"
|
||||
m.template "html/robots.txt", "public/robots.txt"
|
||||
m.file "html/images/rails.png", "public/images/rails.png"
|
||||
|
||||
# Javascripts
|
||||
m.file "html/javascripts/prototype.js", "public/javascripts/prototype.js"
|
||||
m.file "html/javascripts/effects.js", "public/javascripts/effects.js"
|
||||
m.file "html/javascripts/dragdrop.js", "public/javascripts/dragdrop.js"
|
||||
m.file "html/javascripts/controls.js", "public/javascripts/controls.js"
|
||||
m.file "html/javascripts/application.js", "public/javascripts/application.js"
|
||||
|
||||
# Docs
|
||||
m.file "doc/README_FOR_APP", "doc/README_FOR_APP"
|
||||
|
||||
# Logs
|
||||
%w(server production development test).each { |file|
|
||||
m.file "configs/empty.log", "log/#{file}.log", :chmod => 0666
|
||||
}
|
||||
def after_generate
|
||||
if options[:template]
|
||||
Rails::TemplateRunner.new(@destination_root, options[:template])
|
||||
end
|
||||
end
|
||||
|
||||
@@ -138,55 +67,192 @@ class AppGenerator < Rails::Generator::Base
|
||||
opt.on("-f", "--freeze",
|
||||
"Freeze Rails in vendor/rails from the gems generating the skeleton",
|
||||
"Default: false") { |v| options[:freeze] = v }
|
||||
|
||||
opt.on("-m", "--template=path", String,
|
||||
"Use an application template that lives at path (can be a filesystem path or URL).",
|
||||
"Default: (none)") { |v| options[:template] = v }
|
||||
|
||||
end
|
||||
|
||||
|
||||
private
|
||||
def create_directories(m)
|
||||
m.directory ''
|
||||
|
||||
# Intermediate directories are automatically created so don't sweat their absence here.
|
||||
%w(
|
||||
app/controllers
|
||||
app/helpers
|
||||
app/models
|
||||
app/views/layouts
|
||||
config/environments
|
||||
config/initializers
|
||||
config/locales
|
||||
db
|
||||
doc
|
||||
lib
|
||||
lib/tasks
|
||||
log
|
||||
public/images
|
||||
public/javascripts
|
||||
public/stylesheets
|
||||
script/performance
|
||||
test/fixtures
|
||||
test/functional
|
||||
test/integration
|
||||
test/performance
|
||||
test/unit
|
||||
vendor
|
||||
vendor/plugins
|
||||
tmp/sessions
|
||||
tmp/sockets
|
||||
tmp/cache
|
||||
tmp/pids
|
||||
).each { |path| m.directory(path) }
|
||||
end
|
||||
|
||||
def create_root_files(m)
|
||||
m.file "fresh_rakefile", "Rakefile"
|
||||
m.file "README", "README"
|
||||
end
|
||||
|
||||
def create_app_files(m)
|
||||
m.file "helpers/application_controller.rb", "app/controllers/application_controller.rb"
|
||||
m.file "helpers/application_helper.rb", "app/helpers/application_helper.rb"
|
||||
end
|
||||
|
||||
def create_config_files(m)
|
||||
create_database_configuration_file(m)
|
||||
create_routes_file(m)
|
||||
create_locale_file(m)
|
||||
create_initializer_files(m)
|
||||
create_environment_files(m)
|
||||
end
|
||||
|
||||
def create_documentation_file(m)
|
||||
m.file "doc/README_FOR_APP", "doc/README_FOR_APP"
|
||||
end
|
||||
|
||||
def create_log_files(m)
|
||||
%w( server production development test ).each do |file|
|
||||
m.file "configs/empty.log", "log/#{file}.log", :chmod => 0666
|
||||
end
|
||||
end
|
||||
|
||||
def create_public_files(m)
|
||||
create_dispatch_files(m)
|
||||
create_error_files(m)
|
||||
create_welcome_file(m)
|
||||
create_browser_convention_files(m)
|
||||
create_rails_image(m)
|
||||
create_javascript_files(m)
|
||||
end
|
||||
|
||||
def create_script_files(m)
|
||||
%w(
|
||||
about console dbconsole destroy generate runner server plugin
|
||||
performance/benchmarker performance/profiler performance/request
|
||||
).each do |file|
|
||||
m.file "bin/#{file}", "script/#{file}", {
|
||||
:chmod => 0755,
|
||||
:shebang => options[:shebang] == DEFAULT_SHEBANG ? nil : options[:shebang]
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
def create_test_files(m)
|
||||
m.file "helpers/test_helper.rb", "test/test_helper.rb"
|
||||
m.file "helpers/performance_test.rb", "test/performance/browsing_test.rb"
|
||||
end
|
||||
|
||||
|
||||
def create_database_configuration_file(m)
|
||||
m.template "configs/databases/#{options[:db]}.yml", "config/database.yml", :assigns => {
|
||||
:app_name => @app_name,
|
||||
:socket => options[:db] == "mysql" ? mysql_socket_location : nil }
|
||||
end
|
||||
|
||||
def create_routes_file(m)
|
||||
m.file "configs/routes.rb", "config/routes.rb"
|
||||
end
|
||||
|
||||
def create_initializer_files(m)
|
||||
%w(
|
||||
backtrace_silencers
|
||||
inflections
|
||||
mime_types
|
||||
new_rails_defaults
|
||||
).each do |initializer|
|
||||
m.file "configs/initializers/#{initializer}.rb", "config/initializers/#{initializer}.rb"
|
||||
end
|
||||
|
||||
m.template "configs/initializers/session_store.rb", "config/initializers/session_store.rb",
|
||||
:assigns => { :app_name => @app_name, :app_secret => ActiveSupport::SecureRandom.hex(64) }
|
||||
end
|
||||
|
||||
def create_locale_file(m)
|
||||
m.file "configs/locales/en.yml", "config/locales/en.yml"
|
||||
end
|
||||
|
||||
def create_environment_files(m)
|
||||
m.template "environments/environment.rb", "config/environment.rb",
|
||||
:assigns => { :freeze => options[:freeze] }
|
||||
|
||||
m.file "environments/boot.rb", "config/boot.rb"
|
||||
m.file "environments/production.rb", "config/environments/production.rb"
|
||||
m.file "environments/development.rb", "config/environments/development.rb"
|
||||
m.file "environments/test.rb", "config/environments/test.rb"
|
||||
end
|
||||
|
||||
|
||||
def create_dispatch_files(m)
|
||||
if options[:with_dispatchers]
|
||||
dispatcher_options = { :chmod => 0755, :shebang => options[:shebang] }
|
||||
|
||||
m.file "dispatches/config.ru", "config.ru"
|
||||
m.file "dispatches/dispatch.rb", "public/dispatch.rb", dispatcher_options
|
||||
m.file "dispatches/dispatch.rb", "public/dispatch.cgi", dispatcher_options
|
||||
m.file "dispatches/dispatch.fcgi", "public/dispatch.fcgi", dispatcher_options
|
||||
end
|
||||
end
|
||||
|
||||
def create_error_files(m)
|
||||
%w( 404 422 500 ).each do |file|
|
||||
m.file "html/#{file}.html", "public/#{file}.html"
|
||||
end
|
||||
end
|
||||
|
||||
def create_welcome_file(m)
|
||||
m.file 'html/index.html', 'public/index.html'
|
||||
end
|
||||
|
||||
def create_browser_convention_files(m)
|
||||
m.file "html/favicon.ico", "public/favicon.ico"
|
||||
m.file "html/robots.txt", "public/robots.txt"
|
||||
end
|
||||
|
||||
def create_rails_image(m)
|
||||
m.file "html/images/rails.png", "public/images/rails.png"
|
||||
end
|
||||
|
||||
def create_javascript_files(m)
|
||||
%w( prototype effects dragdrop controls application ).each do |javascript|
|
||||
m.file "html/javascripts/#{javascript}.js", "public/javascripts/#{javascript}.js"
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
def mysql_socket_location
|
||||
MYSQL_SOCKET_LOCATIONS.find { |f| File.exist?(f) } unless RUBY_PLATFORM =~ /(:?mswin|mingw)/
|
||||
[
|
||||
"/tmp/mysql.sock", # default
|
||||
"/var/run/mysqld/mysqld.sock", # debian/gentoo
|
||||
"/var/tmp/mysql.sock", # freebsd
|
||||
"/var/lib/mysql/mysql.sock", # fedora
|
||||
"/opt/local/lib/mysql/mysql.sock", # fedora
|
||||
"/opt/local/var/run/mysqld/mysqld.sock", # mac + darwinports + mysql
|
||||
"/opt/local/var/run/mysql4/mysqld.sock", # mac + darwinports + mysql4
|
||||
"/opt/local/var/run/mysql5/mysqld.sock", # mac + darwinports + mysql5
|
||||
"/opt/lampp/var/mysql/mysql.sock" # xampp for linux
|
||||
].find { |f| File.exist?(f) } unless RUBY_PLATFORM =~ /(:?mswin|mingw)/
|
||||
end
|
||||
|
||||
|
||||
# Installation skeleton. Intermediate directories are automatically
|
||||
# created so don't sweat their absence here.
|
||||
BASEDIRS = %w(
|
||||
app/controllers
|
||||
app/helpers
|
||||
app/models
|
||||
app/views/layouts
|
||||
config/environments
|
||||
config/initializers
|
||||
config/locales
|
||||
db
|
||||
doc
|
||||
lib
|
||||
lib/tasks
|
||||
log
|
||||
public/images
|
||||
public/javascripts
|
||||
public/stylesheets
|
||||
script/performance
|
||||
script/process
|
||||
test/fixtures
|
||||
test/functional
|
||||
test/integration
|
||||
test/performance
|
||||
test/unit
|
||||
vendor
|
||||
vendor/plugins
|
||||
tmp/sessions
|
||||
tmp/sockets
|
||||
tmp/cache
|
||||
tmp/pids
|
||||
)
|
||||
|
||||
MYSQL_SOCKET_LOCATIONS = [
|
||||
"/tmp/mysql.sock", # default
|
||||
"/var/run/mysqld/mysqld.sock", # debian/gentoo
|
||||
"/var/tmp/mysql.sock", # freebsd
|
||||
"/var/lib/mysql/mysql.sock", # fedora
|
||||
"/opt/local/lib/mysql/mysql.sock", # fedora
|
||||
"/opt/local/var/run/mysqld/mysqld.sock", # mac + darwinports + mysql
|
||||
"/opt/local/var/run/mysql4/mysqld.sock", # mac + darwinports + mysql4
|
||||
"/opt/local/var/run/mysql5/mysqld.sock", # mac + darwinports + mysql5
|
||||
"/opt/lampp/var/mysql/mysql.sock" # xampp for linux
|
||||
]
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,16 @@
|
||||
module Rails
|
||||
class Git < Scm
|
||||
def self.clone(repos, branch=nil)
|
||||
`git clone #{repos}`
|
||||
|
||||
if branch
|
||||
`cd #{repos.split('/').last}/`
|
||||
`git checkout #{branch}`
|
||||
end
|
||||
end
|
||||
|
||||
def self.run(command)
|
||||
`git #{command}`
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,8 @@
|
||||
module Rails
|
||||
class Scm
|
||||
private
|
||||
def self.hash_to_parameters(hash)
|
||||
hash.collect { |key, value| "--#{key} #{(value.kind_of?(String) ? value : "")}"}.join(" ")
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,7 @@
|
||||
module Rails
|
||||
class Svn < Scm
|
||||
def self.checkout(repos, branch = nil)
|
||||
`svn checkout #{repos}/#{branch || "trunk"}`
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,363 @@
|
||||
require File.dirname(__FILE__) + '/scm/scm'
|
||||
require File.dirname(__FILE__) + '/scm/git'
|
||||
require File.dirname(__FILE__) + '/scm/svn'
|
||||
|
||||
require 'open-uri'
|
||||
require 'fileutils'
|
||||
|
||||
module Rails
|
||||
class TemplateRunner
|
||||
attr_reader :behavior, :description, :root
|
||||
|
||||
def initialize(root, template) # :nodoc:
|
||||
@root = Dir.pwd + "/" + root
|
||||
|
||||
puts "applying template: #{template}"
|
||||
|
||||
load_template(template)
|
||||
|
||||
puts "#{template} applied."
|
||||
end
|
||||
|
||||
def load_template(template)
|
||||
begin
|
||||
code = open(template).read
|
||||
in_root { self.instance_eval(code) }
|
||||
rescue LoadError
|
||||
raise "The template [#{template}] could not be loaded."
|
||||
end
|
||||
end
|
||||
|
||||
# Create a new file in the Rails project folder. Specify the
|
||||
# relative path from RAILS_ROOT. Data is the return value of a block
|
||||
# or a data string.
|
||||
#
|
||||
# ==== Examples
|
||||
#
|
||||
# file("lib/fun_party.rb") do
|
||||
# hostname = ask("What is the virtual hostname I should use?")
|
||||
# "vhost.name = #{hostname}"
|
||||
# end
|
||||
#
|
||||
# file("config/apach.conf", "your apache config")
|
||||
#
|
||||
def file(filename, data = nil, &block)
|
||||
puts "creating file #{filename}"
|
||||
dir, file = [File.dirname(filename), File.basename(filename)]
|
||||
|
||||
inside(dir) do
|
||||
File.open(file, "w") do |f|
|
||||
if block_given?
|
||||
f.write(block.call)
|
||||
else
|
||||
f.write(data)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Install a plugin. You must provide either a Subversion url or Git url.
|
||||
#
|
||||
# ==== Examples
|
||||
#
|
||||
# plugin 'restful-authentication', :git => 'git://github.com/technoweenie/restful-authentication.git'
|
||||
# plugin 'restful-authentication', :svn => 'svn://svnhub.com/technoweenie/restful-authentication/trunk'
|
||||
#
|
||||
def plugin(name, options)
|
||||
puts "installing plugin #{name}"
|
||||
|
||||
if options[:git] || options[:svn]
|
||||
in_root do
|
||||
`script/plugin install #{options[:svn] || options[:git]}`
|
||||
end
|
||||
else
|
||||
puts "! no git or svn provided for #{name}. skipping..."
|
||||
end
|
||||
end
|
||||
|
||||
# Adds an entry into config/environment.rb for the supplied gem :
|
||||
def gem(name, options = {})
|
||||
puts "adding gem #{name}"
|
||||
|
||||
sentinel = 'Rails::Initializer.run do |config|'
|
||||
gems_code = "config.gem '#{name}'"
|
||||
|
||||
if options.any?
|
||||
opts = options.inject([]) {|result, h| result << [":#{h[0]} => '#{h[1]}'"] }.join(", ")
|
||||
gems_code << ", #{opts}"
|
||||
end
|
||||
|
||||
in_root do
|
||||
gsub_file 'config/environment.rb', /(#{Regexp.escape(sentinel)})/mi do |match|
|
||||
"#{match}\n #{gems_code}"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Run a command in git.
|
||||
#
|
||||
# ==== Examples
|
||||
#
|
||||
# git :init
|
||||
# git :add => "this.file that.rb"
|
||||
# git :add => "onefile.rb", :rm => "badfile.cxx"
|
||||
#
|
||||
def git(command = {})
|
||||
puts "running git #{command}"
|
||||
|
||||
in_root do
|
||||
if command.is_a?(Symbol)
|
||||
Git.run(command.to_s)
|
||||
else
|
||||
command.each do |command, options|
|
||||
Git.run("#{command} #{options}")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Create a new file in the vendor/ directory. Code can be specified
|
||||
# in a block or a data string can be given.
|
||||
#
|
||||
# ==== Examples
|
||||
#
|
||||
# vendor("sekrit.rb") do
|
||||
# sekrit_salt = "#{Time.now}--#{3.years.ago}--#{rand}--"
|
||||
# "salt = '#{sekrit_salt}'"
|
||||
# end
|
||||
#
|
||||
# vendor("foreign.rb", "# Foreign code is fun")
|
||||
#
|
||||
def vendor(filename, data = nil, &block)
|
||||
puts "vendoring file #{filename}"
|
||||
inside("vendor") do |folder|
|
||||
File.open("#{folder}/#{filename}", "w") do |f|
|
||||
if block_given?
|
||||
f.write(block.call)
|
||||
else
|
||||
f.write(data)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Create a new file in the lib/ directory. Code can be specified
|
||||
# in a block or a data string can be given.
|
||||
#
|
||||
# ==== Examples
|
||||
#
|
||||
# lib("crypto.rb") do
|
||||
# "crypted_special_value = '#{rand}--#{Time.now}--#{rand(1337)}--'"
|
||||
# end
|
||||
#
|
||||
# lib("foreign.rb", "# Foreign code is fun")
|
||||
#
|
||||
def lib(filename, data = nil)
|
||||
puts "add lib file #{filename}"
|
||||
inside("lib") do |folder|
|
||||
File.open("#{folder}/#{filename}", "w") do |f|
|
||||
if block_given?
|
||||
f.write(block.call)
|
||||
else
|
||||
f.write(data)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Create a new Rakefile with the provided code (either in a block or a string).
|
||||
#
|
||||
# ==== Examples
|
||||
#
|
||||
# rakefile("bootstrap.rake") do
|
||||
# project = ask("What is the UNIX name of your project?")
|
||||
#
|
||||
# <<-TASK
|
||||
# namespace :#{project} do
|
||||
# task :bootstrap do
|
||||
# puts "i like boots!"
|
||||
# end
|
||||
# end
|
||||
# TASK
|
||||
# end
|
||||
#
|
||||
# rakefile("seed.rake", "puts 'im plantin ur seedz'")
|
||||
#
|
||||
def rakefile(filename, data = nil, &block)
|
||||
puts "adding rakefile #{filename}"
|
||||
inside("lib/tasks") do |folder|
|
||||
File.open("#{folder}/#{filename}", "w") do |f|
|
||||
if block_given?
|
||||
f.write(block.call)
|
||||
else
|
||||
f.write(data)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Create a new initializer with the provided code (either in a block or a string).
|
||||
#
|
||||
# ==== Examples
|
||||
#
|
||||
# initializer("globals.rb") do
|
||||
# data = ""
|
||||
#
|
||||
# ['MY_WORK', 'ADMINS', 'BEST_COMPANY_EVAR'].each do
|
||||
# data << "#{const} = :entp"
|
||||
# end
|
||||
#
|
||||
# data
|
||||
# end
|
||||
#
|
||||
# initializer("api.rb", "API_KEY = '123456'")
|
||||
#
|
||||
def initializer(filename, data = nil, &block)
|
||||
puts "adding initializer #{filename}"
|
||||
inside("config/initializers") do |folder|
|
||||
File.open("#{folder}/#{filename}", "w") do |f|
|
||||
if block_given?
|
||||
f.write(block.call)
|
||||
else
|
||||
f.write(data)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Generate something using a generator from Rails or a plugin.
|
||||
# The second parameter is the argument string that is passed to
|
||||
# the generator or an Array that is joined.
|
||||
#
|
||||
# ==== Example
|
||||
#
|
||||
# generate(:authenticated, "user session")
|
||||
#
|
||||
def generate(what, args = nil)
|
||||
puts "generating #{what}"
|
||||
args = args.join(" ") if args.class == Array
|
||||
|
||||
in_root { `#{root}/script/generate #{what} #{args}` }
|
||||
end
|
||||
|
||||
# Executes a command
|
||||
#
|
||||
# ==== Example
|
||||
#
|
||||
# inside('vendor') do
|
||||
# run('ln -s ~/edge rails)
|
||||
# end
|
||||
#
|
||||
def run(command)
|
||||
puts "executing #{command} from #{Dir.pwd}"
|
||||
`#{command}`
|
||||
end
|
||||
|
||||
# Runs the supplied rake task
|
||||
#
|
||||
# ==== Example
|
||||
#
|
||||
# rake("db:migrate")
|
||||
# rake("db:migrate", "production")
|
||||
#
|
||||
def rake(command, env = 'development')
|
||||
puts "running rake task #{command}"
|
||||
in_root { `rake #{command} RAILS_ENV=#{env}` }
|
||||
end
|
||||
|
||||
# Just run the capify command in root
|
||||
#
|
||||
# ==== Example
|
||||
#
|
||||
# capify!
|
||||
#
|
||||
def capify!
|
||||
in_root { `capify .` }
|
||||
end
|
||||
|
||||
# Add Rails to /vendor/rails
|
||||
#
|
||||
# ==== Example
|
||||
#
|
||||
# freeze!
|
||||
#
|
||||
def freeze!(args = {})
|
||||
puts "vendoring rails edge"
|
||||
in_root { `rake rails:freeze:edge` }
|
||||
end
|
||||
|
||||
# Make an entry in Rails routing file conifg/routes.rb
|
||||
#
|
||||
# === Example
|
||||
#
|
||||
# route "map.root :controller => :welcome"
|
||||
#
|
||||
def route(routing_code)
|
||||
sentinel = 'ActionController::Routing::Routes.draw do |map|'
|
||||
|
||||
in_root do
|
||||
gsub_file 'config/routes.rb', /(#{Regexp.escape(sentinel)})/mi do |match|
|
||||
"#{match}\n #{routing_code}\n"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
# Get a user's input
|
||||
#
|
||||
# ==== Example
|
||||
#
|
||||
# answer = ask("Should I freeze the latest Rails?")
|
||||
# freeze! if ask("Should I freeze the latest Rails?") == "yes"
|
||||
#
|
||||
def ask(string)
|
||||
puts string
|
||||
gets.strip
|
||||
end
|
||||
|
||||
# Do something in the root of the Rails application or
|
||||
# a provided subfolder; the full path is yielded to the block you provide.
|
||||
# The path is set back to the previous path when the method exits.
|
||||
def inside(dir = '', &block)
|
||||
folder = File.join(root, dir)
|
||||
FileUtils.mkdir_p(folder) unless File.exist?(folder)
|
||||
FileUtils.cd(folder) { block.arity == 1 ? yield(folder) : yield }
|
||||
end
|
||||
|
||||
def in_root
|
||||
FileUtils.cd(root) { yield }
|
||||
end
|
||||
|
||||
# Helper to test if the user says yes(y)?
|
||||
#
|
||||
# ==== Example
|
||||
#
|
||||
# freeze! if yes?("Should I freeze the latest Rails?")
|
||||
#
|
||||
def yes?(question)
|
||||
answer = ask(question).downcase
|
||||
answer == "y" || answer == "yes"
|
||||
end
|
||||
|
||||
# Helper to test if the user does NOT say yes(y)?
|
||||
#
|
||||
# ==== Example
|
||||
#
|
||||
# capify! if no?("Will you be using vlad to deploy your application?")
|
||||
#
|
||||
def no?(question)
|
||||
!yes?(question)
|
||||
end
|
||||
|
||||
def gsub_file(relative_destination, regexp, *args, &block)
|
||||
path = destination_path(relative_destination)
|
||||
content = File.read(path).gsub(regexp, *args, &block)
|
||||
File.open(path, 'wb') { |file| file.write(content) }
|
||||
end
|
||||
|
||||
def destination_path(relative_destination)
|
||||
File.join(root, relative_destination)
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,7 +1,12 @@
|
||||
namespace :db do
|
||||
task :load_config => :rails_env do
|
||||
require 'active_record'
|
||||
ActiveRecord::Base.configurations = Rails::Configuration.new.database_configuration
|
||||
end
|
||||
|
||||
namespace :create do
|
||||
desc 'Create all the local databases defined in config/database.yml'
|
||||
task :all => :environment do
|
||||
task :all => :load_config do
|
||||
ActiveRecord::Base.configurations.each_value do |config|
|
||||
# Skip entries that don't have a database key, such as the first entry here:
|
||||
#
|
||||
@@ -22,7 +27,7 @@ namespace :db do
|
||||
end
|
||||
|
||||
desc 'Create the database defined in config/database.yml for the current RAILS_ENV'
|
||||
task :create => :environment do
|
||||
task :create => :load_config do
|
||||
create_database(ActiveRecord::Base.configurations[RAILS_ENV])
|
||||
end
|
||||
|
||||
@@ -76,7 +81,7 @@ namespace :db do
|
||||
|
||||
namespace :drop do
|
||||
desc 'Drops all the local databases defined in config/database.yml'
|
||||
task :all => :environment do
|
||||
task :all => :load_config do
|
||||
ActiveRecord::Base.configurations.each_value do |config|
|
||||
# Skip entries that don't have a database key
|
||||
next unless config['database']
|
||||
@@ -87,7 +92,7 @@ namespace :db do
|
||||
end
|
||||
|
||||
desc 'Drops the database for the current RAILS_ENV'
|
||||
task :drop => :environment do
|
||||
task :drop => :load_config do
|
||||
config = ActiveRecord::Base.configurations[RAILS_ENV || 'development']
|
||||
begin
|
||||
drop_database(config)
|
||||
@@ -393,6 +398,7 @@ end
|
||||
def drop_database(config)
|
||||
case config['adapter']
|
||||
when 'mysql'
|
||||
ActiveRecord::Base.establish_connection(config)
|
||||
ActiveRecord::Base.connection.drop_database config['database']
|
||||
when /^sqlite/
|
||||
FileUtils.rm(File.join(RAILS_ROOT, config['database']))
|
||||
|
||||
@@ -128,6 +128,7 @@ namespace :rails do
|
||||
desc "Generate dispatcher files in RAILS_ROOT/public"
|
||||
task :generate_dispatchers do
|
||||
require 'railties_path'
|
||||
FileUtils.cp(RAILTIES_PATH + '/dispatches/config.ru', RAILS_ROOT + '/config.ru')
|
||||
FileUtils.cp(RAILTIES_PATH + '/dispatches/dispatch.fcgi', RAILS_ROOT + '/public/dispatch.fcgi')
|
||||
FileUtils.cp(RAILTIES_PATH + '/dispatches/dispatch.rb', RAILS_ROOT + '/public/dispatch.rb')
|
||||
FileUtils.cp(RAILTIES_PATH + '/dispatches/dispatch.rb', RAILS_ROOT + '/public/dispatch.cgi')
|
||||
|
||||
7
railties/lib/tasks/middleware.rake
Normal file
7
railties/lib/tasks/middleware.rake
Normal file
@@ -0,0 +1,7 @@
|
||||
desc 'Prints out your Rack middleware stack'
|
||||
task :middleware => :environment do
|
||||
ActionController::Dispatcher.middleware.each do |middleware|
|
||||
puts "use #{middleware.inspect}"
|
||||
end
|
||||
puts "run ActionController::Dispatcher.new"
|
||||
end
|
||||
@@ -3,6 +3,12 @@ task :environment do
|
||||
require(File.join(RAILS_ROOT, 'config', 'environment'))
|
||||
end
|
||||
|
||||
task :rails_env do
|
||||
unless defined? RAILS_ENV
|
||||
RAILS_ENV = ENV['RAILS_ENV'] ||= 'development'
|
||||
end
|
||||
end
|
||||
|
||||
desc 'Generate a crytographically secure secret key. This is typically used to generate a secret for cookie sessions.'
|
||||
task :secret do
|
||||
puts ActiveSupport::SecureRandom.hex(64)
|
||||
|
||||
@@ -129,5 +129,19 @@ uses_mocha "Plugin Tests" do
|
||||
assert_equal '1.0.0', DUMMY_GEM_E_VERSION
|
||||
end
|
||||
|
||||
def test_gem_handle_missing_dependencies
|
||||
dummy_gem = Rails::GemDependency.new "dummy-gem-g"
|
||||
dummy_gem.add_load_paths
|
||||
dummy_gem.load
|
||||
assert dummy_gem.loaded?
|
||||
debugger
|
||||
assert_equal 2, dummy_gem.dependencies.size
|
||||
assert_nothing_raised do
|
||||
dummy_gem.dependencies.each do |g|
|
||||
g.dependencies
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
@@ -314,10 +314,10 @@ end
|
||||
|
||||
class RailsRootTest < Test::Unit::TestCase
|
||||
def test_rails_dot_root_equals_rails_root
|
||||
assert_equal RAILS_ROOT, Rails.root
|
||||
assert_equal RAILS_ROOT, Rails.root.to_s
|
||||
end
|
||||
|
||||
def test_rails_dot_root_accepts_arguments_for_file_dot_join
|
||||
assert_equal File.join(RAILS_ROOT, 'app', 'controllers'), Rails.root('app', 'controllers')
|
||||
def test_rails_dot_root_should_be_a_pathname
|
||||
assert_equal File.join(RAILS_ROOT, 'app', 'controllers'), Rails.root.join('app', 'controllers').to_s
|
||||
end
|
||||
end
|
||||
39
railties/test/vendor/gems/dummy-gem-f-1.0.0/.specification
vendored
Normal file
39
railties/test/vendor/gems/dummy-gem-f-1.0.0/.specification
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
--- !ruby/object:Gem::Specification
|
||||
name: dummy-gem-f
|
||||
version: !ruby/object:Gem::Version
|
||||
version: 1.3.0
|
||||
platform: ruby
|
||||
authors:
|
||||
- "Nobody"
|
||||
date: 2008-10-03 00:00:00 -04:00
|
||||
dependencies:
|
||||
- !ruby/object:Gem::Dependency
|
||||
name: absolutely-no-such-gem
|
||||
type: :runtime
|
||||
version_requirement:
|
||||
version_requirements: !ruby/object:Gem::Requirement
|
||||
requirements:
|
||||
- - ">="
|
||||
- !ruby/object:Gem::Version
|
||||
version: 1.0.0
|
||||
version:
|
||||
files:
|
||||
- lib
|
||||
- lib/dummy-gem-f.rb
|
||||
require_paths:
|
||||
- lib
|
||||
required_ruby_version: !ruby/object:Gem::Requirement
|
||||
requirements:
|
||||
- - ">="
|
||||
- !ruby/object:Gem::Version
|
||||
version: "0"
|
||||
version:
|
||||
required_rubygems_version: !ruby/object:Gem::Requirement
|
||||
requirements:
|
||||
- - ">="
|
||||
- !ruby/object:Gem::Version
|
||||
version: "0"
|
||||
version:
|
||||
requirements: []
|
||||
specification_version: 2
|
||||
summary: Dummy Gem F
|
||||
1
railties/test/vendor/gems/dummy-gem-f-1.0.0/lib/dummy-gem-f.rb
vendored
Normal file
1
railties/test/vendor/gems/dummy-gem-f-1.0.0/lib/dummy-gem-f.rb
vendored
Normal file
@@ -0,0 +1 @@
|
||||
DUMMY_GEM_F_VERSION="1.0.0"
|
||||
39
railties/test/vendor/gems/dummy-gem-g-1.0.0/.specification
vendored
Normal file
39
railties/test/vendor/gems/dummy-gem-g-1.0.0/.specification
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
--- !ruby/object:Gem::Specification
|
||||
name: dummy-gem-g
|
||||
version: !ruby/object:Gem::Version
|
||||
version: 1.3.0
|
||||
platform: ruby
|
||||
authors:
|
||||
- "Nobody"
|
||||
date: 2008-10-03 00:00:00 -04:00
|
||||
dependencies:
|
||||
- !ruby/object:Gem::Dependency
|
||||
name: dummy-gem-f
|
||||
type: :development
|
||||
version_requirement:
|
||||
version_requirements: !ruby/object:Gem::Requirement
|
||||
requirements:
|
||||
- - ">="
|
||||
- !ruby/object:Gem::Version
|
||||
version: 1.0.0
|
||||
version:
|
||||
files:
|
||||
- lib
|
||||
- lib/dummy-gem-g.rb
|
||||
require_paths:
|
||||
- lib
|
||||
required_ruby_version: !ruby/object:Gem::Requirement
|
||||
requirements:
|
||||
- - ">="
|
||||
- !ruby/object:Gem::Version
|
||||
version: "0"
|
||||
version:
|
||||
required_rubygems_version: !ruby/object:Gem::Requirement
|
||||
requirements:
|
||||
- - ">="
|
||||
- !ruby/object:Gem::Version
|
||||
version: "0"
|
||||
version:
|
||||
requirements: []
|
||||
specification_version: 2
|
||||
summary: Dummy Gem G
|
||||
1
railties/test/vendor/gems/dummy-gem-g-1.0.0/lib/dummy-gem-g.rb
vendored
Normal file
1
railties/test/vendor/gems/dummy-gem-g-1.0.0/lib/dummy-gem-g.rb
vendored
Normal file
@@ -0,0 +1 @@
|
||||
DUMMY_GEM_G_VERSION="1.0.0"
|
||||
Reference in New Issue
Block a user