dtr 1.0.0 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (109) hide show
  1. data/CHANGES +21 -0
  2. data/README.rdoc +39 -28
  3. data/Rakefile +1 -1
  4. data/TODO +1 -3
  5. data/bin/dtr +20 -13
  6. data/dtr.gemspec +3 -3
  7. data/lib/dtr.rb +2 -2
  8. data/lib/dtr/agent.rb +12 -5
  9. data/lib/dtr/agent/brain.rb +45 -19
  10. data/lib/dtr/agent/herald.rb +8 -10
  11. data/lib/dtr/agent/process_root.rb +23 -0
  12. data/lib/dtr/agent/rails_ext.rb +57 -0
  13. data/lib/dtr/agent/runner.rb +19 -39
  14. data/lib/dtr/agent/sync_codebase.rb +10 -19
  15. data/lib/dtr/agent/sync_logger.rb +1 -0
  16. data/lib/dtr/agent/worker.rb +13 -61
  17. data/lib/dtr/agent/working_env_ext.rb +51 -17
  18. data/lib/dtr/agent/working_status.rb +34 -0
  19. data/lib/dtr/facade.rb +19 -17
  20. data/lib/dtr/master.rb +2 -0
  21. data/lib/dtr/monitor.rb +2 -2
  22. data/lib/dtr/raketasks.rb +14 -19
  23. data/lib/dtr/shared.rb +1 -0
  24. data/lib/dtr/shared/adapter.rb +2 -101
  25. data/lib/dtr/shared/adapter/base.rb +118 -0
  26. data/lib/dtr/shared/adapter/mortality.rb +41 -0
  27. data/lib/dtr/shared/configuration.rb +32 -14
  28. data/lib/dtr/shared/root.rb +20 -0
  29. data/lib/dtr/shared/sync_codebase/master_ext.rb +2 -2
  30. data/lib/dtr/shared/sync_codebase/sync_service.rb +7 -4
  31. data/lib/dtr/shared/utils/cmd.rb +4 -2
  32. data/lib/dtr/shared/utils/env_store.rb +16 -24
  33. data/lib/dtr/shared/working_env.rb +8 -0
  34. data/lib/dtr/test_unit/drb_test_runner.rb +1 -1
  35. data/lib/dtr/test_unit/thread_safe_test_result.rb +56 -3
  36. data/test/acceptance/dtr_package_task_test.rb +3 -3
  37. data/test/acceptance/general_test.rb +3 -3
  38. data/test/acceptance/rails_ext_test.rb +86 -0
  39. data/test/acceptance/raketasks_test.rb +14 -0
  40. data/test/acceptance/sync_codebase_test.rb +8 -31
  41. data/test/acceptance/sync_logger_test.rb +6 -3
  42. data/test/agent_helper.rb +24 -16
  43. data/test/logger_stub.rb +3 -3
  44. data/test/test_helper.rb +12 -9
  45. data/test/unit/adapter_test.rb +1 -1
  46. data/test/unit/configuration_test.rb +36 -4
  47. data/test/unit/database_initializer_test.rb +36 -0
  48. data/test/unit/facade_test.rb +11 -1
  49. data/test/unit/thread_safe_test_result_test.rb +41 -0
  50. data/test/unit/working_env_test.rb +11 -21
  51. data/testdata/rails_projects/simple_project/README +256 -0
  52. data/testdata/rails_projects/simple_project/Rakefile +10 -0
  53. data/testdata/rails_projects/simple_project/app/controllers/application.rb +15 -0
  54. data/testdata/rails_projects/simple_project/app/controllers/products_controller.rb +5 -0
  55. data/testdata/rails_projects/simple_project/app/helpers/application_helper.rb +3 -0
  56. data/testdata/rails_projects/simple_project/app/helpers/products_helper.rb +2 -0
  57. data/testdata/rails_projects/simple_project/app/models/product.rb +5 -0
  58. data/testdata/rails_projects/simple_project/app/views/products/index.rhtml +7 -0
  59. data/testdata/rails_projects/simple_project/config/boot.rb +109 -0
  60. data/testdata/rails_projects/simple_project/config/database.yml +19 -0
  61. data/testdata/rails_projects/simple_project/config/database.yml.mysql +12 -0
  62. data/testdata/rails_projects/simple_project/config/environment.rb +67 -0
  63. data/testdata/rails_projects/simple_project/config/environments/development.rb +17 -0
  64. data/testdata/rails_projects/simple_project/config/environments/production.rb +22 -0
  65. data/testdata/rails_projects/simple_project/config/environments/test.rb +22 -0
  66. data/testdata/rails_projects/simple_project/config/initializers/inflections.rb +10 -0
  67. data/testdata/rails_projects/simple_project/config/initializers/mime_types.rb +5 -0
  68. data/testdata/rails_projects/simple_project/config/initializers/new_rails_defaults.rb +17 -0
  69. data/testdata/rails_projects/simple_project/config/routes.rb +43 -0
  70. data/testdata/rails_projects/simple_project/db/migrate/20081027133744_create_products.rb +13 -0
  71. data/testdata/rails_projects/simple_project/db/schema.rb +21 -0
  72. data/testdata/rails_projects/simple_project/doc/README_FOR_APP +2 -0
  73. data/testdata/rails_projects/simple_project/public/404.html +30 -0
  74. data/testdata/rails_projects/simple_project/public/422.html +30 -0
  75. data/testdata/rails_projects/simple_project/public/500.html +30 -0
  76. data/testdata/rails_projects/simple_project/public/dispatch.cgi +10 -0
  77. data/testdata/rails_projects/simple_project/public/dispatch.fcgi +24 -0
  78. data/testdata/rails_projects/simple_project/public/dispatch.rb +10 -0
  79. data/testdata/rails_projects/simple_project/public/favicon.ico +0 -0
  80. data/testdata/rails_projects/simple_project/public/images/rails.png +0 -0
  81. data/testdata/rails_projects/simple_project/public/index.html +274 -0
  82. data/testdata/rails_projects/simple_project/public/javascripts/application.js +2 -0
  83. data/testdata/rails_projects/simple_project/public/javascripts/controls.js +963 -0
  84. data/testdata/rails_projects/simple_project/public/javascripts/dragdrop.js +972 -0
  85. data/testdata/rails_projects/simple_project/public/javascripts/effects.js +1120 -0
  86. data/testdata/rails_projects/simple_project/public/javascripts/prototype.js +4225 -0
  87. data/testdata/rails_projects/simple_project/public/robots.txt +5 -0
  88. data/testdata/rails_projects/simple_project/script/about +4 -0
  89. data/testdata/rails_projects/simple_project/script/console +3 -0
  90. data/testdata/rails_projects/simple_project/script/dbconsole +3 -0
  91. data/testdata/rails_projects/simple_project/script/destroy +3 -0
  92. data/testdata/rails_projects/simple_project/script/generate +3 -0
  93. data/testdata/rails_projects/simple_project/script/performance/benchmarker +3 -0
  94. data/testdata/rails_projects/simple_project/script/performance/profiler +3 -0
  95. data/testdata/rails_projects/simple_project/script/performance/request +3 -0
  96. data/testdata/rails_projects/simple_project/script/plugin +3 -0
  97. data/testdata/rails_projects/simple_project/script/process/inspector +3 -0
  98. data/testdata/rails_projects/simple_project/script/process/reaper +3 -0
  99. data/testdata/rails_projects/simple_project/script/process/spawner +3 -0
  100. data/testdata/rails_projects/simple_project/script/runner +3 -0
  101. data/testdata/rails_projects/simple_project/script/server +3 -0
  102. data/testdata/rails_projects/simple_project/test/fixtures/products.yml +9 -0
  103. data/testdata/rails_projects/simple_project/test/functional/products_controller_test.rb +11 -0
  104. data/testdata/rails_projects/simple_project/test/test_helper.rb +38 -0
  105. data/testdata/rails_projects/simple_project/test/unit/product_test.rb +27 -0
  106. data/testdata/raketasks/Rakefile +1 -1
  107. metadata +90 -5
  108. data/testdata/verify_dir_pwd/Rakefile +0 -6
  109. data/testdata/verify_dir_pwd/verify_dir_pwd_test_case.rb +0 -10
@@ -1,35 +1,43 @@
1
1
  require 'fileutils'
2
2
  module DTR
3
3
  module AgentHelper
4
- GROUP = 'dtr acceptance tests'
5
- def start_agents(size = 3)
4
+ include Adapter::Master
5
+ GROUP = 'dtr_acceptance_tests'
6
+ def start_agents(options={})
7
+ options = {:size => 3, :clean_dir => true}.merge(options)
6
8
  @agents_dir = File.join(Dir.pwd, 'agents')
7
- @agents = []
8
- @agents << start_agent_at(File.join(@agents_dir, 'agent1'), size)
9
- # @agents << start_agent_at(File.join(@agents_dir, 'agent2'), 1)
9
+ start_agent_at(agent1_dir, options)
10
10
  end
11
11
 
12
- def start_agent_at(agent_dir, size, clean_dir=true)
13
- FileUtils.rm_rf(agent_dir) if clean_dir
12
+ def agent1_dir
13
+ File.join(@agents_dir, 'agent1')
14
+ end
15
+
16
+ def agent1_runner1_dir
17
+ File.join(agent1_dir, Socket.gethostname.gsub(/[^\d\w]/, '_'), 'tance_rails_ext_test', 'runner1')
18
+ end
19
+
20
+ def start_agent_at(agent_dir, options={})
21
+ FileUtils.rm_rf(agent_dir) if options[:clean_dir]
14
22
  FileUtils.mkdir_p(agent_dir)
15
23
  runner_names = []
16
- size.times {|i| runner_names << "runner#{i}"}
24
+ options[:size].times {|i| runner_names << "runner#{i}"}
17
25
  Process.fork do
18
26
  Dir.chdir(agent_dir) do
27
+ DTR.configuration.refresh
28
+ DTR.configuration.follower_listen_heartbeat_timeout = options[:follower_listen_heartbeat_timeout] || 3
19
29
  DTR.configuration.group = GROUP
20
- DTR.launch_agent(runner_names, nil)
30
+ DTR.configuration.agent_runners = runner_names
31
+ DTR.configuration.save
32
+ DTR.run_script("DTR::Agent.start(:hypnotize)")
21
33
  end
22
34
  end
23
35
  end
24
36
 
25
37
  def stop_agents
26
- if @agents
27
- @agents.each do |agent|
28
- DTR.kill_process agent
29
- end
30
- Process.waitall
31
- sleep 1
32
- end
38
+ group_agents_should_die(GROUP)
39
+ Process.waitall
40
+ sleep 1
33
41
  ensure
34
42
  FileUtils.rm_rf(@agents_dir) rescue nil
35
43
  end
@@ -1,8 +1,8 @@
1
1
  class LoggerStub
2
2
  def initialize
3
- @store = DTR::EnvStore.new
4
- clear
3
+ @store = DTR::EnvStore.new('.logger_stub')
5
4
  end
5
+
6
6
  def debug(message=nil, &block)
7
7
  output(:debug, message, &block)
8
8
  end
@@ -29,6 +29,6 @@ class LoggerStub
29
29
  end
30
30
 
31
31
  def clear
32
- @store[:logs] = []
32
+ @store.destroy
33
33
  end
34
34
  end
@@ -7,17 +7,22 @@ require 'rubygems'
7
7
  require 'growling_test'
8
8
  require 'dtr'
9
9
  require 'dtr/test_unit'
10
- DTR.configuration.master_heartbeat_interval = 2
11
- DTR.configuration.follower_listen_heartbeat_timeout = 3
12
10
 
13
11
  require File.dirname(__FILE__) + '/agent_helper'
14
12
  require File.dirname(__FILE__) + '/logger_stub'
15
13
 
16
14
  ENV['DTR_ENV'] = 'test'
15
+ # ENV['JRUBY_DTR'] = 'true'
17
16
 
18
17
  module Test
19
18
  module Unit
20
19
  class TestCase
20
+ # For safe fork & kill sub process, should use Process.kill and Process.fork
21
+ # At least have problem on ruby 1.8.6 114 with Kernel#kill & fork
22
+ def kill_process(pid)
23
+ Process.kill 'TERM', pid rescue nil
24
+ end
25
+
21
26
  def assert_false(o)
22
27
  assert !o
23
28
  end
@@ -25,18 +30,19 @@ module Test
25
30
  pid = Process.fork do
26
31
  Dir.chdir(File.expand_path(File.dirname(__FILE__) + "/../testdata/")) do
27
32
  setup_test_env
28
- with_agent_helper_group(&block)
33
+ with_agent_configuration(&block)
29
34
  end
30
35
  exit 0
31
36
  end
32
37
  Process.waitpid pid
33
38
  assert_equal 0, $?.exitstatus
34
39
  ensure
35
- DTR.kill_process pid
40
+ kill_process pid
36
41
  end
37
42
 
38
- def with_agent_helper_group(&block)
43
+ def with_agent_configuration(&block)
39
44
  DTR.configuration.group = DTR::AgentHelper::GROUP
45
+ DTR.configuration.master_heartbeat_interval = 2
40
46
  begin
41
47
  block.call
42
48
  ensure
@@ -52,16 +58,13 @@ module Test
52
58
  require 'a_file_system_test_case'
53
59
  require 'scenario_test_case'
54
60
  require 'setup_agent_env_test_case'
61
+ DTR.configuration.refresh
55
62
  DTR.inject
56
63
  end
57
64
 
58
65
  def runit(suite)
59
66
  Test::Unit::UI::Console::TestRunner.run(suite, Test::Unit::UI::SILENT)
60
67
  end
61
- def clear_configuration
62
- DTR::EnvStore.destroy
63
- DTR.configuration.load
64
- end
65
68
  end
66
69
  end
67
70
  end
@@ -15,7 +15,7 @@ class AdapterTest < Test::Unit::TestCase
15
15
  end
16
16
 
17
17
  def teardown
18
- clear_configuration
18
+ DTR.configuration.refresh
19
19
  end
20
20
 
21
21
  def test_should_be_sleep_if_never_wakeup
@@ -1,14 +1,19 @@
1
1
  require File.dirname(__FILE__) + '/../test_helper'
2
2
 
3
3
  class ConfigurationTest < Test::Unit::TestCase
4
+
4
5
  def teardown
5
- clear_configuration
6
+ DTR.configuration.refresh
6
7
  end
7
8
 
8
- def test_should_not_save_rinda_server_port
9
+ def test_should_save_rinda_server_port
9
10
  DTR.configuration.rinda_server_port = '3456'
10
11
  assert_equal '3456', DTR.configuration.rinda_server_port
11
- assert_nil DTR::EnvStore.new[:rinda_server_port]
12
+ DTR.configuration.save
13
+ assert_equal '3456', DTR::EnvStore.new[:rinda_server_port]
14
+
15
+ DTR.configuration.load
16
+ assert_equal '3456', DTR.configuration.rinda_server_port
12
17
  end
13
18
 
14
19
  def test_group_defualt_is_dangerous_group
@@ -41,4 +46,31 @@ class ConfigurationTest < Test::Unit::TestCase
41
46
  DTR.configuration.load
42
47
  assert_equal 'new group', DTR.configuration.group
43
48
  end
44
- end
49
+
50
+ def test_agent_env_setup_cmd
51
+ DTR.configuration.agent_env_setup_cmd = 'rake db:test:prepare'
52
+ assert_equal 'rake db:test:prepare', DTR.configuration.agent_env_setup_cmd
53
+ DTR.configuration.save
54
+ assert_equal 'rake db:test:prepare', DTR::EnvStore.new[:agent_env_setup_cmd]
55
+ end
56
+
57
+ def test_agent_runners
58
+ DTR.configuration.agent_runners = ['r1', 'r2']
59
+ assert_equal ['r1', 'r2'], DTR.configuration.agent_runners
60
+ DTR.configuration.save
61
+ assert_equal ['r1', 'r2'], DTR::EnvStore.new[:agent_runners]
62
+ end
63
+
64
+ def test_working_env_should_be_saved_directly
65
+ env = DTR::WorkingEnv.new
66
+ DTR.configuration.working_env = env
67
+ assert_equal env, DTR.configuration.working_env
68
+ assert_equal env, DTR::EnvStore.new[:working_env]
69
+ end
70
+
71
+ def test_working_env_should_always_load_from_pstore
72
+ env = DTR::WorkingEnv.new
73
+ DTR::EnvStore.new[:working_env] = env
74
+ assert_equal env, DTR.configuration.working_env
75
+ end
76
+ end
@@ -0,0 +1,36 @@
1
+ require File.dirname(__FILE__) + '/../test_helper'
2
+ require 'dtr/agent/rails_ext'
3
+
4
+ class DatabaseInitializerTest < Test::Unit::TestCase
5
+ include DTR::Agent::RailsExt::DatabaseInitializer
6
+
7
+ def test_should_be_nil_when_no_config_database_yml_and_database_yml_dtr_exist
8
+ assert_nil preparing_database_command
9
+ end
10
+
11
+ def test_should_overwrite_config_database_yml_if_config_database_yml_dtr_exists
12
+ FileUtils.mkdir_p('config')
13
+ File.open('config/database.yml', 'w+') do |io|
14
+ io.syswrite("database.yml")
15
+ end
16
+ File.open('config/database.yml.dtr', 'w+') do |io|
17
+ io.syswrite("database.yml.dtr")
18
+ end
19
+ assert_not_nil preparing_database_command
20
+ assert_equal 'database.yml.dtr', File.new('config/database.yml').read
21
+ ensure
22
+ FileUtils.rm_rf('config')
23
+ end
24
+
25
+ def test_should_include_runner_name_in_environment
26
+ ENV['DTR_RUNNER_NAME'] = 'runner_name'
27
+ FileUtils.mkdir_p('config')
28
+ File.open('config/database.yml', 'w+') do |io|
29
+ io.syswrite("database.yml")
30
+ end
31
+ assert_equal "rake db:create db:migrate db:test:prepare DTR_RUNNER_NAME=runner_name", preparing_database_command
32
+ ensure
33
+ ENV['DTR_RUNNER_NAME'] = nil
34
+ FileUtils.rm_rf('config')
35
+ end
36
+ end
@@ -5,7 +5,7 @@ class FacadeTest < Test::Unit::TestCase
5
5
  include DTR::Facade
6
6
 
7
7
  def teardown
8
- clear_configuration
8
+ DTR.configuration.refresh
9
9
  end
10
10
 
11
11
  def test_lib_path
@@ -28,6 +28,16 @@ class FacadeTest < Test::Unit::TestCase
28
28
  assert_equal '7890', DTR::EnvStore.new[:agent_listen_port]
29
29
  end
30
30
 
31
+ def test_save_agent_env_setup_cmd
32
+ self.agent_env_setup_cmd = 'rake db:test:prepare'
33
+ assert_equal 'rake db:test:prepare', DTR::EnvStore.new[:agent_env_setup_cmd]
34
+ end
35
+
36
+ def test_save_agent_runners
37
+ self.agent_runners = ['r1', 'r2']
38
+ assert_equal ['r1', 'r2'], DTR::EnvStore.new[:agent_runners]
39
+ end
40
+
31
41
  def fork_and_kill_process
32
42
  pid = fork_process do
33
43
  loop do
@@ -0,0 +1,41 @@
1
+ require File.dirname(__FILE__) + '/../test_helper'
2
+ require 'dtr/test_unit/thread_safe_test_result'
3
+
4
+ class ThreadSafeTestResultTest < Test::Unit::TestCase
5
+ class DRbObjectStub
6
+ def initialize(uri)
7
+ @uri = uri
8
+ end
9
+ end
10
+ def test_should_sort_runner_test_results
11
+ results = DTR::TestUnit::ThreadSafeTestResult::RunnerTestResults.new
12
+ runner1 = DRbObjectStub.new('runner1')
13
+ runner2 = DRbObjectStub.new('runner2')
14
+ runner3 = DRbObjectStub.new('runner3')
15
+ r1 = results.fetch(runner1)
16
+ r1.add_run
17
+
18
+ r2 = results.fetch(runner2)
19
+ r2.add_run
20
+ r2.add_run
21
+ r2.add_run
22
+
23
+ r3 = results.fetch(runner3)
24
+ r3.add_run
25
+ r3.add_run
26
+
27
+ assert_equal %{runner2 => 3 tests, 0 assertions, 0 failures, 0 errors
28
+ runner3 => 2 tests, 0 assertions, 0 failures, 0 errors
29
+ runner1 => 1 tests, 0 assertions, 0 failures, 0 errors}, results.to_s
30
+ end
31
+
32
+ def test_pair_should_multicast_messages
33
+ r1 = Test::Unit::TestResult.new
34
+ r2 = Test::Unit::TestResult.new
35
+ pair = DTR::TestUnit::ThreadSafeTestResult::Pair.new(r1, r2)
36
+ pair.add_run
37
+
38
+ assert_equal 1, r1.run_count
39
+ assert_equal 1, r2.run_count
40
+ end
41
+ end
@@ -17,28 +17,22 @@ class WorkingEnvTest < Test::Unit::TestCase
17
17
  assert nil != env2
18
18
  end
19
19
 
20
- def test_working_dir_within_env_should_be_based_on_host_and_pwd
20
+ def test_env_base_dir_should_be_based_on_host_and_pwd
21
21
  env = DTR::WorkingEnv.new
22
22
  env[:pwd] = 'pwd'
23
23
  env[:host] = 'hostname'
24
- working_dir = nil
25
- env.within do
26
- working_dir = Dir.pwd
27
- end
28
- assert_equal File.expand_path('hostname/pwd'), working_dir
24
+ base_dir = env.base_dir
25
+ assert_equal File.expand_path('hostname/pwd'), base_dir
29
26
  ensure
30
27
  FileUtils.rm_rf File.expand_path('hostname')
31
28
  end
32
29
 
33
- def test_should_truncate_pwd_if_it_is_too_long_for_working_dir
30
+ def test_should_truncate_pwd_if_it_is_too_long_for_base_dir
34
31
  env = DTR::WorkingEnv.new
35
32
  env[:pwd] = 'pwd_pwd_pwd_pwd_pwd_pwd_pwd_pwd_pwd_pwd' #40
36
33
  env[:host] = 'hostname'
37
- working_dir = nil
38
- env.within do
39
- working_dir = Dir.pwd
40
- end
41
- assert_equal File.expand_path('hostname/_pwd_pwd_pwd_pwd_pwd'), working_dir
34
+ base_dir = env.base_dir
35
+ assert_equal File.expand_path('hostname/_pwd_pwd_pwd_pwd_pwd'), base_dir
42
36
  ensure
43
37
  FileUtils.rm_rf File.expand_path('hostname')
44
38
  end
@@ -47,24 +41,20 @@ class WorkingEnvTest < Test::Unit::TestCase
47
41
  env = DTR::WorkingEnv.new
48
42
  env[:pwd] = 'pwd pwd' #40
49
43
  env[:host] = 'xli.local:1234'
50
- working_dir = nil
51
- env.within do
52
- working_dir = Dir.pwd
53
- end
54
- assert_equal File.expand_path('xli_local_1234/pwd_pwd'), working_dir
44
+ base_dir = env.base_dir
45
+ assert_equal File.expand_path('xli_local_1234/pwd_pwd'), base_dir
55
46
  ensure
56
47
  FileUtils.rm_rf File.expand_path('xli_local_1234')
57
48
  end
58
49
 
59
- def test_working_dir_should_be_created_if_it_does_not_exist
50
+ def test_base_dir_should_be_created_if_it_does_not_exist
60
51
  env = DTR::WorkingEnv.new
61
52
  env[:pwd] = 'pwd'
62
53
  env[:host] = 'hostname'
63
54
 
64
55
  assert !File.exists?(File.expand_path('hostname'))
65
- env.within do
66
- assert File.exists?(Dir.pwd)
67
- end
56
+ base_dir = env.base_dir
57
+ assert File.exists?(base_dir)
68
58
  ensure
69
59
  FileUtils.rm_rf File.expand_path('hostname')
70
60
  end
@@ -0,0 +1,256 @@
1
+ == Welcome to Rails
2
+
3
+ Rails is a web-application framework that includes everything needed to create
4
+ database-backed web applications according to the Model-View-Control pattern.
5
+
6
+ This pattern splits the view (also called the presentation) into "dumb" templates
7
+ that are primarily responsible for inserting pre-built data in between HTML tags.
8
+ The model contains the "smart" domain objects (such as Account, Product, Person,
9
+ Post) that holds all the business logic and knows how to persist themselves to
10
+ a database. The controller handles the incoming requests (such as Save New Account,
11
+ Update Product, Show Post) by manipulating the model and directing data to the view.
12
+
13
+ In Rails, the model is handled by what's called an object-relational mapping
14
+ layer entitled Active Record. This layer allows you to present the data from
15
+ database rows as objects and embellish these data objects with business logic
16
+ methods. You can read more about Active Record in
17
+ link:files/vendor/rails/activerecord/README.html.
18
+
19
+ The controller and view are handled by the Action Pack, which handles both
20
+ layers by its two parts: Action View and Action Controller. These two layers
21
+ are bundled in a single package due to their heavy interdependence. This is
22
+ unlike the relationship between the Active Record and Action Pack that is much
23
+ more separate. Each of these packages can be used independently outside of
24
+ Rails. You can read more about Action Pack in
25
+ link:files/vendor/rails/actionpack/README.html.
26
+
27
+
28
+ == Getting Started
29
+
30
+ 1. At the command prompt, start a new Rails application using the <tt>rails</tt> command
31
+ and your application name. Ex: rails myapp
32
+ 2. Change directory into myapp and start the web server: <tt>script/server</tt> (run with --help for options)
33
+ 3. Go to http://localhost:3000/ and get "Welcome aboard: You're riding the Rails!"
34
+ 4. Follow the guidelines to start developing your application
35
+
36
+
37
+ == Web Servers
38
+
39
+ By default, Rails will try to use Mongrel and lighttpd if they are installed, otherwise
40
+ Rails will use WEBrick, the webserver that ships with Ruby. When you run script/server,
41
+ Rails will check if Mongrel exists, then lighttpd and finally fall back to WEBrick. This ensures
42
+ that you can always get up and running quickly.
43
+
44
+ Mongrel is a Ruby-based webserver with a C component (which requires compilation) that is
45
+ suitable for development and deployment of Rails applications. If you have Ruby Gems installed,
46
+ getting up and running with mongrel is as easy as: <tt>gem install mongrel</tt>.
47
+ More info at: http://mongrel.rubyforge.org
48
+
49
+ If Mongrel is not installed, Rails will look for lighttpd. It's considerably faster than
50
+ Mongrel and WEBrick and also suited for production use, but requires additional
51
+ installation and currently only works well on OS X/Unix (Windows users are encouraged
52
+ to start with Mongrel). We recommend version 1.4.11 and higher. You can download it from
53
+ http://www.lighttpd.net.
54
+
55
+ And finally, if neither Mongrel or lighttpd are installed, Rails will use the built-in Ruby
56
+ web server, WEBrick. WEBrick is a small Ruby web server suitable for development, but not
57
+ for production.
58
+
59
+ But of course its also possible to run Rails on any platform that supports FCGI.
60
+ Apache, LiteSpeed, IIS are just a few. For more information on FCGI,
61
+ please visit: http://wiki.rubyonrails.com/rails/pages/FastCGI
62
+
63
+
64
+ == Apache .htaccess example
65
+
66
+ # General Apache options
67
+ AddHandler fastcgi-script .fcgi
68
+ AddHandler cgi-script .cgi
69
+ Options +FollowSymLinks +ExecCGI
70
+
71
+ # If you don't want Rails to look in certain directories,
72
+ # use the following rewrite rules so that Apache won't rewrite certain requests
73
+ #
74
+ # Example:
75
+ # RewriteCond %{REQUEST_URI} ^/notrails.*
76
+ # RewriteRule .* - [L]
77
+
78
+ # Redirect all requests not available on the filesystem to Rails
79
+ # By default the cgi dispatcher is used which is very slow
80
+ #
81
+ # For better performance replace the dispatcher with the fastcgi one
82
+ #
83
+ # Example:
84
+ # RewriteRule ^(.*)$ dispatch.fcgi [QSA,L]
85
+ RewriteEngine On
86
+
87
+ # If your Rails application is accessed via an Alias directive,
88
+ # then you MUST also set the RewriteBase in this htaccess file.
89
+ #
90
+ # Example:
91
+ # Alias /myrailsapp /path/to/myrailsapp/public
92
+ # RewriteBase /myrailsapp
93
+
94
+ RewriteRule ^$ index.html [QSA]
95
+ RewriteRule ^([^.]+)$ $1.html [QSA]
96
+ RewriteCond %{REQUEST_FILENAME} !-f
97
+ RewriteRule ^(.*)$ dispatch.cgi [QSA,L]
98
+
99
+ # In case Rails experiences terminal errors
100
+ # Instead of displaying this message you can supply a file here which will be rendered instead
101
+ #
102
+ # Example:
103
+ # ErrorDocument 500 /500.html
104
+
105
+ ErrorDocument 500 "<h2>Application error</h2>Rails application failed to start properly"
106
+
107
+
108
+ == Debugging Rails
109
+
110
+ Sometimes your application goes wrong. Fortunately there are a lot of tools that
111
+ will help you debug it and get it back on the rails.
112
+
113
+ First area to check is the application log files. Have "tail -f" commands running
114
+ on the server.log and development.log. Rails will automatically display debugging
115
+ and runtime information to these files. Debugging info will also be shown in the
116
+ browser on requests from 127.0.0.1.
117
+
118
+ You can also log your own messages directly into the log file from your code using
119
+ the Ruby logger class from inside your controllers. Example:
120
+
121
+ class WeblogController < ActionController::Base
122
+ def destroy
123
+ @weblog = Weblog.find(params[:id])
124
+ @weblog.destroy
125
+ logger.info("#{Time.now} Destroyed Weblog ID ##{@weblog.id}!")
126
+ end
127
+ end
128
+
129
+ The result will be a message in your log file along the lines of:
130
+
131
+ Mon Oct 08 14:22:29 +1000 2007 Destroyed Weblog ID #1
132
+
133
+ More information on how to use the logger is at http://www.ruby-doc.org/core/
134
+
135
+ Also, Ruby documentation can be found at http://www.ruby-lang.org/ including:
136
+
137
+ * The Learning Ruby (Pickaxe) Book: http://www.ruby-doc.org/docs/ProgrammingRuby/
138
+ * Learn to Program: http://pine.fm/LearnToProgram/ (a beginners guide)
139
+
140
+ These two online (and free) books will bring you up to speed on the Ruby language
141
+ and also on programming in general.
142
+
143
+
144
+ == Debugger
145
+
146
+ Debugger support is available through the debugger command when you start your Mongrel or
147
+ Webrick server with --debugger. This means that you can break out of execution at any point
148
+ in the code, investigate and change the model, AND then resume execution!
149
+ You need to install ruby-debug to run the server in debugging mode. With gems, use 'gem install ruby-debug'
150
+ Example:
151
+
152
+ class WeblogController < ActionController::Base
153
+ def index
154
+ @posts = Post.find(:all)
155
+ debugger
156
+ end
157
+ end
158
+
159
+ So the controller will accept the action, run the first line, then present you
160
+ with a IRB prompt in the server window. Here you can do things like:
161
+
162
+ >> @posts.inspect
163
+ => "[#<Post:0x14a6be8 @attributes={\"title\"=>nil, \"body\"=>nil, \"id\"=>\"1\"}>,
164
+ #<Post:0x14a6620 @attributes={\"title\"=>\"Rails you know!\", \"body\"=>\"Only ten..\", \"id\"=>\"2\"}>]"
165
+ >> @posts.first.title = "hello from a debugger"
166
+ => "hello from a debugger"
167
+
168
+ ...and even better is that you can examine how your runtime objects actually work:
169
+
170
+ >> f = @posts.first
171
+ => #<Post:0x13630c4 @attributes={"title"=>nil, "body"=>nil, "id"=>"1"}>
172
+ >> f.
173
+ Display all 152 possibilities? (y or n)
174
+
175
+ Finally, when you're ready to resume execution, you enter "cont"
176
+
177
+
178
+ == Console
179
+
180
+ You can interact with the domain model by starting the console through <tt>script/console</tt>.
181
+ Here you'll have all parts of the application configured, just like it is when the
182
+ application is running. You can inspect domain models, change values, and save to the
183
+ database. Starting the script without arguments will launch it in the development environment.
184
+ Passing an argument will specify a different environment, like <tt>script/console production</tt>.
185
+
186
+ To reload your controllers and models after launching the console run <tt>reload!</tt>
187
+
188
+ == dbconsole
189
+
190
+ You can go to the command line of your database directly through <tt>script/dbconsole</tt>.
191
+ You would be connected to the database with the credentials defined in database.yml.
192
+ Starting the script without arguments will connect you to the development database. Passing an
193
+ argument will connect you to a different database, like <tt>script/dbconsole production</tt>.
194
+ Currently works for mysql, postgresql and sqlite.
195
+
196
+ == Description of Contents
197
+
198
+ app
199
+ Holds all the code that's specific to this particular application.
200
+
201
+ app/controllers
202
+ Holds controllers that should be named like weblogs_controller.rb for
203
+ automated URL mapping. All controllers should descend from ApplicationController
204
+ which itself descends from ActionController::Base.
205
+
206
+ app/models
207
+ Holds models that should be named like post.rb.
208
+ Most models will descend from ActiveRecord::Base.
209
+
210
+ app/views
211
+ Holds the template files for the view that should be named like
212
+ weblogs/index.html.erb for the WeblogsController#index action. All views use eRuby
213
+ syntax.
214
+
215
+ app/views/layouts
216
+ Holds the template files for layouts to be used with views. This models the common
217
+ header/footer method of wrapping views. In your views, define a layout using the
218
+ <tt>layout :default</tt> and create a file named default.html.erb. Inside default.html.erb,
219
+ call <% yield %> to render the view using this layout.
220
+
221
+ app/helpers
222
+ Holds view helpers that should be named like weblogs_helper.rb. These are generated
223
+ for you automatically when using script/generate for controllers. Helpers can be used to
224
+ wrap functionality for your views into methods.
225
+
226
+ config
227
+ Configuration files for the Rails environment, the routing map, the database, and other dependencies.
228
+
229
+ db
230
+ Contains the database schema in schema.rb. db/migrate contains all
231
+ the sequence of Migrations for your schema.
232
+
233
+ doc
234
+ This directory is where your application documentation will be stored when generated
235
+ using <tt>rake doc:app</tt>
236
+
237
+ lib
238
+ Application specific libraries. Basically, any kind of custom code that doesn't
239
+ belong under controllers, models, or helpers. This directory is in the load path.
240
+
241
+ public
242
+ The directory available for the web server. Contains subdirectories for images, stylesheets,
243
+ and javascripts. Also contains the dispatchers and the default HTML files. This should be
244
+ set as the DOCUMENT_ROOT of your web server.
245
+
246
+ script
247
+ Helper scripts for automation and generation.
248
+
249
+ test
250
+ Unit and functional tests along with fixtures. When using the script/generate scripts, template
251
+ test files will be generated for you and placed in this directory.
252
+
253
+ vendor
254
+ External libraries that the application depends on. Also includes the plugins subdirectory.
255
+ If the app has frozen rails, those gems also go here, under vendor/rails/.
256
+ This directory is in the load path.