openskies 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.md +87 -0
- data/README.rdoc +35 -0
- data/bin/openskies +9 -0
- data/guides/assets/images/belongs_to.png +0 -0
- data/guides/assets/images/book_icon.gif +0 -0
- data/guides/assets/images/bullet.gif +0 -0
- data/guides/assets/images/challenge.png +0 -0
- data/guides/assets/images/chapters_icon.gif +0 -0
- data/guides/assets/images/check_bullet.gif +0 -0
- data/guides/assets/images/credits_pic_blank.gif +0 -0
- data/guides/assets/images/csrf.png +0 -0
- data/guides/assets/images/customized_error_messages.png +0 -0
- data/guides/assets/images/edge_badge.png +0 -0
- data/guides/assets/images/error_messages.png +0 -0
- data/guides/assets/images/feature_tile.gif +0 -0
- data/guides/assets/images/footer_tile.gif +0 -0
- data/guides/assets/images/fxn.png +0 -0
- data/guides/assets/images/grey_bullet.gif +0 -0
- data/guides/assets/images/habtm.png +0 -0
- data/guides/assets/images/has_many.png +0 -0
- data/guides/assets/images/has_many_through.png +0 -0
- data/guides/assets/images/has_one.png +0 -0
- data/guides/assets/images/has_one_through.png +0 -0
- data/guides/assets/images/header_backdrop.png +0 -0
- data/guides/assets/images/header_tile.gif +0 -0
- data/guides/assets/images/i18n/demo_html_safe.png +0 -0
- data/guides/assets/images/i18n/demo_localized_pirate.png +0 -0
- data/guides/assets/images/i18n/demo_translated_en.png +0 -0
- data/guides/assets/images/i18n/demo_translated_pirate.png +0 -0
- data/guides/assets/images/i18n/demo_translation_missing.png +0 -0
- data/guides/assets/images/i18n/demo_untranslated.png +0 -0
- data/guides/assets/images/icons/README +5 -0
- data/guides/assets/images/icons/callouts/1.png +0 -0
- data/guides/assets/images/icons/callouts/10.png +0 -0
- data/guides/assets/images/icons/callouts/11.png +0 -0
- data/guides/assets/images/icons/callouts/12.png +0 -0
- data/guides/assets/images/icons/callouts/13.png +0 -0
- data/guides/assets/images/icons/callouts/14.png +0 -0
- data/guides/assets/images/icons/callouts/15.png +0 -0
- data/guides/assets/images/icons/callouts/2.png +0 -0
- data/guides/assets/images/icons/callouts/3.png +0 -0
- data/guides/assets/images/icons/callouts/4.png +0 -0
- data/guides/assets/images/icons/callouts/5.png +0 -0
- data/guides/assets/images/icons/callouts/6.png +0 -0
- data/guides/assets/images/icons/callouts/7.png +0 -0
- data/guides/assets/images/icons/callouts/8.png +0 -0
- data/guides/assets/images/icons/callouts/9.png +0 -0
- data/guides/assets/images/icons/caution.png +0 -0
- data/guides/assets/images/icons/example.png +0 -0
- data/guides/assets/images/icons/home.png +0 -0
- data/guides/assets/images/icons/important.png +0 -0
- data/guides/assets/images/icons/next.png +0 -0
- data/guides/assets/images/icons/note.png +0 -0
- data/guides/assets/images/icons/prev.png +0 -0
- data/guides/assets/images/icons/tip.png +0 -0
- data/guides/assets/images/icons/up.png +0 -0
- data/guides/assets/images/icons/warning.png +0 -0
- data/guides/assets/images/jaimeiniesta.jpg +0 -0
- data/guides/assets/images/nav_arrow.gif +0 -0
- data/guides/assets/images/polymorphic.png +0 -0
- data/guides/assets/images/posts_index.png +0 -0
- data/guides/assets/images/radar.png +0 -0
- data/guides/assets/images/rails_guides_kindle_cover.jpg +0 -0
- data/guides/assets/images/rails_guides_logo.gif +0 -0
- data/guides/assets/images/rails_logo_remix.gif +0 -0
- data/guides/assets/images/rails_welcome.png +0 -0
- data/guides/assets/images/session_fixation.png +0 -0
- data/guides/assets/images/tab_grey.gif +0 -0
- data/guides/assets/images/tab_info.gif +0 -0
- data/guides/assets/images/tab_note.gif +0 -0
- data/guides/assets/images/tab_red.gif +0 -0
- data/guides/assets/images/tab_yellow.gif +0 -0
- data/guides/assets/images/tab_yellow.png +0 -0
- data/guides/assets/images/validation_error_messages.png +0 -0
- data/guides/assets/images/vijaydev.jpg +0 -0
- data/guides/assets/javascripts/guides.js +7 -0
- data/guides/assets/javascripts/syntaxhighlighter/shBrushAS3.js +59 -0
- data/guides/assets/javascripts/syntaxhighlighter/shBrushAppleScript.js +75 -0
- data/guides/assets/javascripts/syntaxhighlighter/shBrushBash.js +59 -0
- data/guides/assets/javascripts/syntaxhighlighter/shBrushCSharp.js +65 -0
- data/guides/assets/javascripts/syntaxhighlighter/shBrushColdFusion.js +100 -0
- data/guides/assets/javascripts/syntaxhighlighter/shBrushCpp.js +97 -0
- data/guides/assets/javascripts/syntaxhighlighter/shBrushCss.js +91 -0
- data/guides/assets/javascripts/syntaxhighlighter/shBrushDelphi.js +55 -0
- data/guides/assets/javascripts/syntaxhighlighter/shBrushDiff.js +41 -0
- data/guides/assets/javascripts/syntaxhighlighter/shBrushErlang.js +52 -0
- data/guides/assets/javascripts/syntaxhighlighter/shBrushGroovy.js +67 -0
- data/guides/assets/javascripts/syntaxhighlighter/shBrushJScript.js +52 -0
- data/guides/assets/javascripts/syntaxhighlighter/shBrushJava.js +57 -0
- data/guides/assets/javascripts/syntaxhighlighter/shBrushJavaFX.js +58 -0
- data/guides/assets/javascripts/syntaxhighlighter/shBrushPerl.js +72 -0
- data/guides/assets/javascripts/syntaxhighlighter/shBrushPhp.js +88 -0
- data/guides/assets/javascripts/syntaxhighlighter/shBrushPlain.js +33 -0
- data/guides/assets/javascripts/syntaxhighlighter/shBrushPowerShell.js +74 -0
- data/guides/assets/javascripts/syntaxhighlighter/shBrushPython.js +64 -0
- data/guides/assets/javascripts/syntaxhighlighter/shBrushRuby.js +55 -0
- data/guides/assets/javascripts/syntaxhighlighter/shBrushSass.js +94 -0
- data/guides/assets/javascripts/syntaxhighlighter/shBrushScala.js +51 -0
- data/guides/assets/javascripts/syntaxhighlighter/shBrushSql.js +66 -0
- data/guides/assets/javascripts/syntaxhighlighter/shBrushVb.js +56 -0
- data/guides/assets/javascripts/syntaxhighlighter/shBrushXml.js +69 -0
- data/guides/assets/javascripts/syntaxhighlighter/shCore.js +17 -0
- data/guides/assets/stylesheets/fixes.css +16 -0
- data/guides/assets/stylesheets/kindle.css +11 -0
- data/guides/assets/stylesheets/main.css +453 -0
- data/guides/assets/stylesheets/print.css +52 -0
- data/guides/assets/stylesheets/reset.css +43 -0
- data/guides/assets/stylesheets/style.css +13 -0
- data/guides/assets/stylesheets/syntaxhighlighter/shCore.css +226 -0
- data/guides/assets/stylesheets/syntaxhighlighter/shCoreDefault.css +328 -0
- data/guides/assets/stylesheets/syntaxhighlighter/shCoreDjango.css +331 -0
- data/guides/assets/stylesheets/syntaxhighlighter/shCoreEclipse.css +339 -0
- data/guides/assets/stylesheets/syntaxhighlighter/shCoreEmacs.css +324 -0
- data/guides/assets/stylesheets/syntaxhighlighter/shCoreFadeToGrey.css +328 -0
- data/guides/assets/stylesheets/syntaxhighlighter/shCoreMDUltra.css +324 -0
- data/guides/assets/stylesheets/syntaxhighlighter/shCoreMidnight.css +324 -0
- data/guides/assets/stylesheets/syntaxhighlighter/shCoreRDark.css +324 -0
- data/guides/assets/stylesheets/syntaxhighlighter/shThemeDefault.css +117 -0
- data/guides/assets/stylesheets/syntaxhighlighter/shThemeDjango.css +120 -0
- data/guides/assets/stylesheets/syntaxhighlighter/shThemeEclipse.css +128 -0
- data/guides/assets/stylesheets/syntaxhighlighter/shThemeEmacs.css +113 -0
- data/guides/assets/stylesheets/syntaxhighlighter/shThemeFadeToGrey.css +117 -0
- data/guides/assets/stylesheets/syntaxhighlighter/shThemeMDUltra.css +113 -0
- data/guides/assets/stylesheets/syntaxhighlighter/shThemeMidnight.css +113 -0
- data/guides/assets/stylesheets/syntaxhighlighter/shThemeRDark.css +113 -0
- data/guides/assets/stylesheets/syntaxhighlighter/shThemeRailsGuides.css +116 -0
- data/guides/code/getting_started/Gemfile +38 -0
- data/guides/code/getting_started/README.rdoc +261 -0
- data/guides/code/getting_started/Rakefile +7 -0
- data/guides/code/getting_started/app/assets/images/rails.png +0 -0
- data/guides/code/getting_started/app/assets/javascripts/application.js +15 -0
- data/guides/code/getting_started/app/assets/javascripts/comments.js.coffee +3 -0
- data/guides/code/getting_started/app/assets/javascripts/home.js.coffee +3 -0
- data/guides/code/getting_started/app/assets/javascripts/posts.js.coffee +3 -0
- data/guides/code/getting_started/app/assets/stylesheets/application.css +13 -0
- data/guides/code/getting_started/app/assets/stylesheets/comments.css.scss +3 -0
- data/guides/code/getting_started/app/assets/stylesheets/home.css.scss +3 -0
- data/guides/code/getting_started/app/assets/stylesheets/posts.css.scss +3 -0
- data/guides/code/getting_started/app/assets/stylesheets/scaffolds.css.scss +56 -0
- data/guides/code/getting_started/app/controllers/application_controller.rb +3 -0
- data/guides/code/getting_started/app/controllers/comments_controller.rb +16 -0
- data/guides/code/getting_started/app/controllers/home_controller.rb +5 -0
- data/guides/code/getting_started/app/controllers/posts_controller.rb +84 -0
- data/guides/code/getting_started/app/helpers/application_helper.rb +2 -0
- data/guides/code/getting_started/app/helpers/comments_helper.rb +2 -0
- data/guides/code/getting_started/app/helpers/home_helper.rb +2 -0
- data/guides/code/getting_started/app/helpers/posts_helper.rb +5 -0
- data/guides/code/getting_started/app/models/comment.rb +3 -0
- data/guides/code/getting_started/app/models/post.rb +11 -0
- data/guides/code/getting_started/app/models/tag.rb +3 -0
- data/guides/code/getting_started/app/views/comments/_comment.html.erb +15 -0
- data/guides/code/getting_started/app/views/comments/_form.html.erb +13 -0
- data/guides/code/getting_started/app/views/home/index.html.erb +2 -0
- data/guides/code/getting_started/app/views/layouts/application.html.erb +14 -0
- data/guides/code/getting_started/app/views/posts/_form.html.erb +32 -0
- data/guides/code/getting_started/app/views/posts/edit.html.erb +6 -0
- data/guides/code/getting_started/app/views/posts/index.html.erb +27 -0
- data/guides/code/getting_started/app/views/posts/new.html.erb +5 -0
- data/guides/code/getting_started/app/views/posts/show.html.erb +31 -0
- data/guides/code/getting_started/app/views/tags/_form.html.erb +12 -0
- data/guides/code/getting_started/config/application.rb +59 -0
- data/guides/code/getting_started/config/boot.rb +6 -0
- data/guides/code/getting_started/config/database.yml +25 -0
- data/guides/code/getting_started/config/environment.rb +5 -0
- data/guides/code/getting_started/config/environments/development.rb +37 -0
- data/guides/code/getting_started/config/environments/production.rb +67 -0
- data/guides/code/getting_started/config/environments/test.rb +37 -0
- data/guides/code/getting_started/config/initializers/backtrace_silencers.rb +7 -0
- data/guides/code/getting_started/config/initializers/inflections.rb +15 -0
- data/guides/code/getting_started/config/initializers/mime_types.rb +5 -0
- data/guides/code/getting_started/config/initializers/secret_token.rb +7 -0
- data/guides/code/getting_started/config/initializers/session_store.rb +8 -0
- data/guides/code/getting_started/config/initializers/wrap_parameters.rb +14 -0
- data/guides/code/getting_started/config/locales/en.yml +5 -0
- data/guides/code/getting_started/config/routes.rb +64 -0
- data/guides/code/getting_started/config.ru +4 -0
- data/guides/code/getting_started/db/migrate/20110901012504_create_posts.rb +11 -0
- data/guides/code/getting_started/db/migrate/20110901012815_create_comments.rb +12 -0
- data/guides/code/getting_started/db/migrate/20110901013701_create_tags.rb +11 -0
- data/guides/code/getting_started/db/schema.rb +43 -0
- data/guides/code/getting_started/db/seeds.rb +7 -0
- data/guides/code/getting_started/doc/README_FOR_APP +2 -0
- data/guides/code/getting_started/public/404.html +26 -0
- data/guides/code/getting_started/public/422.html +26 -0
- data/guides/code/getting_started/public/500.html +25 -0
- data/guides/code/getting_started/public/favicon.ico +0 -0
- data/guides/code/getting_started/public/robots.txt +5 -0
- data/guides/code/getting_started/script/rails +6 -0
- data/guides/code/getting_started/test/fixtures/comments.yml +11 -0
- data/guides/code/getting_started/test/fixtures/posts.yml +11 -0
- data/guides/code/getting_started/test/fixtures/tags.yml +9 -0
- data/guides/code/getting_started/test/functional/comments_controller_test.rb +7 -0
- data/guides/code/getting_started/test/functional/home_controller_test.rb +9 -0
- data/guides/code/getting_started/test/functional/posts_controller_test.rb +49 -0
- data/guides/code/getting_started/test/performance/browsing_test.rb +12 -0
- data/guides/code/getting_started/test/test_helper.rb +13 -0
- data/guides/code/getting_started/test/unit/comment_test.rb +7 -0
- data/guides/code/getting_started/test/unit/helpers/comments_helper_test.rb +4 -0
- data/guides/code/getting_started/test/unit/helpers/home_helper_test.rb +4 -0
- data/guides/code/getting_started/test/unit/helpers/posts_helper_test.rb +4 -0
- data/guides/code/getting_started/test/unit/post_test.rb +7 -0
- data/guides/code/getting_started/test/unit/tag_test.rb +7 -0
- data/guides/rails_guides/generator.rb +310 -0
- data/guides/rails_guides/helpers.rb +45 -0
- data/guides/rails_guides/indexer.rb +69 -0
- data/guides/rails_guides/levenshtein.rb +31 -0
- data/guides/rails_guides/textile_extensions.rb +63 -0
- data/guides/rails_guides.rb +50 -0
- data/guides/source/2_2_release_notes.textile +422 -0
- data/guides/source/2_3_release_notes.textile +610 -0
- data/guides/source/3_0_release_notes.textile +595 -0
- data/guides/source/3_1_release_notes.textile +553 -0
- data/guides/source/3_2_release_notes.textile +540 -0
- data/guides/source/_license.html.erb +2 -0
- data/guides/source/_welcome.html.erb +19 -0
- data/guides/source/action_controller_overview.textile +820 -0
- data/guides/source/action_mailer_basics.textile +516 -0
- data/guides/source/action_view_overview.textile +1497 -0
- data/guides/source/active_model_basics.textile +205 -0
- data/guides/source/active_record_basics.textile +218 -0
- data/guides/source/active_record_querying.textile +1433 -0
- data/guides/source/active_record_validations_callbacks.textile +1283 -0
- data/guides/source/active_resource_basics.textile +120 -0
- data/guides/source/active_support_core_extensions.textile +3713 -0
- data/guides/source/ajax_on_rails.textile +267 -0
- data/guides/source/api_documentation_guidelines.textile +185 -0
- data/guides/source/asset_pipeline.textile +707 -0
- data/guides/source/association_basics.textile +1959 -0
- data/guides/source/caching_with_rails.textile +437 -0
- data/guides/source/command_line.textile +574 -0
- data/guides/source/configuring.textile +641 -0
- data/guides/source/contributing_to_ruby_on_rails.textile +448 -0
- data/guides/source/credits.html.erb +72 -0
- data/guides/source/debugging_rails_applications.textile +714 -0
- data/guides/source/documents.yaml +157 -0
- data/guides/source/engines.textile +618 -0
- data/guides/source/form_helpers.textile +798 -0
- data/guides/source/generators.textile +621 -0
- data/guides/source/getting_started.textile +1929 -0
- data/guides/source/i18n.textile +931 -0
- data/guides/source/index.html.erb +30 -0
- data/guides/source/initialization.textile +1116 -0
- data/guides/source/kindle/KINDLE.md +26 -0
- data/guides/source/kindle/copyright.html.erb +1 -0
- data/guides/source/kindle/layout.html.erb +27 -0
- data/guides/source/kindle/rails_guides.opf.erb +52 -0
- data/guides/source/kindle/toc.html.erb +24 -0
- data/guides/source/kindle/toc.ncx.erb +64 -0
- data/guides/source/kindle/welcome.html.erb +5 -0
- data/guides/source/layout.html.erb +124 -0
- data/guides/source/layouts_and_rendering.textile +1237 -0
- data/guides/source/migrations.textile +900 -0
- data/guides/source/nested_model_forms.textile +222 -0
- data/guides/source/performance_testing.textile +597 -0
- data/guides/source/plugins.textile +464 -0
- data/guides/source/rails_application_templates.textile +240 -0
- data/guides/source/rails_on_rack.textile +236 -0
- data/guides/source/routing.textile +885 -0
- data/guides/source/ruby_on_rails_guides_guidelines.textile +79 -0
- data/guides/source/security.textile +1004 -0
- data/guides/source/testing.textile +947 -0
- data/guides/w3c_validator.rb +91 -0
- data/lib/rails/all.rb +15 -0
- data/lib/rails/application/bootstrap.rb +73 -0
- data/lib/rails/application/configuration.rb +151 -0
- data/lib/rails/application/finisher.rb +98 -0
- data/lib/rails/application/railties.rb +13 -0
- data/lib/rails/application/route_inspector.rb +84 -0
- data/lib/rails/application/routes_reloader.rb +56 -0
- data/lib/rails/application.rb +320 -0
- data/lib/rails/backtrace_cleaner.rb +42 -0
- data/lib/rails/cli.rb +16 -0
- data/lib/rails/code_statistics.rb +118 -0
- data/lib/rails/commands/application.rb +38 -0
- data/lib/rails/commands/benchmarker.rb +34 -0
- data/lib/rails/commands/console.rb +55 -0
- data/lib/rails/commands/dbconsole.rb +123 -0
- data/lib/rails/commands/destroy.rb +10 -0
- data/lib/rails/commands/generate.rb +12 -0
- data/lib/rails/commands/plugin.rb +544 -0
- data/lib/rails/commands/plugin_new.rb +11 -0
- data/lib/rails/commands/profiler.rb +32 -0
- data/lib/rails/commands/runner.rb +54 -0
- data/lib/rails/commands/server.rb +100 -0
- data/lib/rails/commands/update.rb +9 -0
- data/lib/rails/commands.rb +104 -0
- data/lib/rails/configuration.rb +89 -0
- data/lib/rails/console/app.rb +36 -0
- data/lib/rails/console/helpers.rb +11 -0
- data/lib/rails/engine/commands.rb +43 -0
- data/lib/rails/engine/configuration.rb +84 -0
- data/lib/rails/engine/railties.rb +33 -0
- data/lib/rails/engine.rb +657 -0
- data/lib/rails/generators/actions.rb +325 -0
- data/lib/rails/generators/active_model.rb +78 -0
- data/lib/rails/generators/app_base.rb +281 -0
- data/lib/rails/generators/base.rb +390 -0
- data/lib/rails/generators/css/assets/assets_generator.rb +13 -0
- data/lib/rails/generators/css/assets/templates/stylesheet.css +4 -0
- data/lib/rails/generators/css/scaffold/scaffold_generator.rb +16 -0
- data/lib/rails/generators/erb/controller/controller_generator.rb +20 -0
- data/lib/rails/generators/erb/controller/templates/view.html.erb +2 -0
- data/lib/rails/generators/erb/mailer/mailer_generator.rb +13 -0
- data/lib/rails/generators/erb/mailer/templates/view.text.erb +3 -0
- data/lib/rails/generators/erb/scaffold/scaffold_generator.rb +29 -0
- data/lib/rails/generators/erb/scaffold/templates/_form.html.erb +23 -0
- data/lib/rails/generators/erb/scaffold/templates/edit.html.erb +6 -0
- data/lib/rails/generators/erb/scaffold/templates/index.html.erb +27 -0
- data/lib/rails/generators/erb/scaffold/templates/new.html.erb +5 -0
- data/lib/rails/generators/erb/scaffold/templates/show.html.erb +12 -0
- data/lib/rails/generators/erb.rb +21 -0
- data/lib/rails/generators/generated_attribute.rb +107 -0
- data/lib/rails/generators/js/assets/assets_generator.rb +13 -0
- data/lib/rails/generators/js/assets/templates/javascript.js +2 -0
- data/lib/rails/generators/migration.rb +68 -0
- data/lib/rails/generators/named_base.rb +202 -0
- data/lib/rails/generators/rails/app/USAGE +15 -0
- data/lib/rails/generators/rails/app/app_generator.rb +303 -0
- data/lib/rails/generators/rails/app/templates/Gemfile +26 -0
- data/lib/rails/generators/rails/app/templates/README +261 -0
- data/lib/rails/generators/rails/app/templates/Rakefile +7 -0
- data/lib/rails/generators/rails/app/templates/app/assets/images/rails.png +0 -0
- data/lib/rails/generators/rails/app/templates/app/assets/javascripts/application.js.tt +17 -0
- data/lib/rails/generators/rails/app/templates/app/assets/stylesheets/application.css +13 -0
- data/lib/rails/generators/rails/app/templates/app/controllers/application_controller.rb +3 -0
- data/lib/rails/generators/rails/app/templates/app/helpers/application_helper.rb +2 -0
- data/lib/rails/generators/rails/app/templates/app/mailers/.empty_directory +0 -0
- data/lib/rails/generators/rails/app/templates/app/models/.empty_directory +0 -0
- data/lib/rails/generators/rails/app/templates/app/views/layouts/application.html.erb.tt +14 -0
- data/lib/rails/generators/rails/app/templates/config/application.rb +74 -0
- data/lib/rails/generators/rails/app/templates/config/boot.rb +6 -0
- data/lib/rails/generators/rails/app/templates/config/databases/frontbase.yml +31 -0
- data/lib/rails/generators/rails/app/templates/config/databases/ibm_db.yml +86 -0
- data/lib/rails/generators/rails/app/templates/config/databases/jdbc.yml +62 -0
- data/lib/rails/generators/rails/app/templates/config/databases/jdbcmysql.yml +33 -0
- data/lib/rails/generators/rails/app/templates/config/databases/jdbcpostgresql.yml +43 -0
- data/lib/rails/generators/rails/app/templates/config/databases/jdbcsqlite3.yml +20 -0
- data/lib/rails/generators/rails/app/templates/config/databases/mysql.yml +54 -0
- data/lib/rails/generators/rails/app/templates/config/databases/oracle.yml +39 -0
- data/lib/rails/generators/rails/app/templates/config/databases/postgresql.yml +55 -0
- data/lib/rails/generators/rails/app/templates/config/databases/sqlite3.yml +25 -0
- data/lib/rails/generators/rails/app/templates/config/environment.rb +5 -0
- data/lib/rails/generators/rails/app/templates/config/environments/development.rb.tt +41 -0
- data/lib/rails/generators/rails/app/templates/config/environments/production.rb.tt +73 -0
- data/lib/rails/generators/rails/app/templates/config/environments/test.rb.tt +39 -0
- data/lib/rails/generators/rails/app/templates/config/initializers/backtrace_silencers.rb +7 -0
- data/lib/rails/generators/rails/app/templates/config/initializers/inflections.rb +15 -0
- data/lib/rails/generators/rails/app/templates/config/initializers/mime_types.rb +5 -0
- data/lib/rails/generators/rails/app/templates/config/initializers/secret_token.rb.tt +7 -0
- data/lib/rails/generators/rails/app/templates/config/initializers/session_store.rb.tt +8 -0
- data/lib/rails/generators/rails/app/templates/config/initializers/wrap_parameters.rb.tt +16 -0
- data/lib/rails/generators/rails/app/templates/config/locales/en.yml +5 -0
- data/lib/rails/generators/rails/app/templates/config/routes.rb +58 -0
- data/lib/rails/generators/rails/app/templates/config.ru +4 -0
- data/lib/rails/generators/rails/app/templates/db/seeds.rb.tt +7 -0
- data/lib/rails/generators/rails/app/templates/doc/README_FOR_APP +2 -0
- data/lib/rails/generators/rails/app/templates/gitignore +15 -0
- data/lib/rails/generators/rails/app/templates/public/404.html +26 -0
- data/lib/rails/generators/rails/app/templates/public/422.html +26 -0
- data/lib/rails/generators/rails/app/templates/public/500.html +25 -0
- data/lib/rails/generators/rails/app/templates/public/favicon.ico +0 -0
- data/lib/rails/generators/rails/app/templates/public/index.html +241 -0
- data/lib/rails/generators/rails/app/templates/public/robots.txt +5 -0
- data/lib/rails/generators/rails/app/templates/public/stylesheets/.empty_directory +0 -0
- data/lib/rails/generators/rails/app/templates/script/rails +5 -0
- data/lib/rails/generators/rails/app/templates/test/fixtures/.empty_directory +0 -0
- data/lib/rails/generators/rails/app/templates/test/functional/.empty_directory +0 -0
- data/lib/rails/generators/rails/app/templates/test/integration/.empty_directory +0 -0
- data/lib/rails/generators/rails/app/templates/test/performance/browsing_test.rb +12 -0
- data/lib/rails/generators/rails/app/templates/test/test_helper.rb +15 -0
- data/lib/rails/generators/rails/app/templates/test/unit/.empty_directory +0 -0
- data/lib/rails/generators/rails/assets/USAGE +20 -0
- data/lib/rails/generators/rails/assets/assets_generator.rb +25 -0
- data/lib/rails/generators/rails/assets/templates/javascript.js +2 -0
- data/lib/rails/generators/rails/assets/templates/stylesheet.css +4 -0
- data/lib/rails/generators/rails/controller/USAGE +18 -0
- data/lib/rails/generators/rails/controller/controller_generator.rb +20 -0
- data/lib/rails/generators/rails/controller/templates/controller.rb +13 -0
- data/lib/rails/generators/rails/generator/USAGE +12 -0
- data/lib/rails/generators/rails/generator/generator_generator.rb +25 -0
- data/lib/rails/generators/rails/generator/templates/%file_name%_generator.rb.tt +3 -0
- data/lib/rails/generators/rails/generator/templates/USAGE.tt +8 -0
- data/lib/rails/generators/rails/generator/templates/templates/.empty_directory +0 -0
- data/lib/rails/generators/rails/helper/USAGE +17 -0
- data/lib/rails/generators/rails/helper/helper_generator.rb +13 -0
- data/lib/rails/generators/rails/helper/templates/helper.rb +4 -0
- data/lib/rails/generators/rails/integration_test/USAGE +10 -0
- data/lib/rails/generators/rails/integration_test/integration_test_generator.rb +7 -0
- data/lib/rails/generators/rails/migration/USAGE +29 -0
- data/lib/rails/generators/rails/migration/migration_generator.rb +8 -0
- data/lib/rails/generators/rails/model/USAGE +45 -0
- data/lib/rails/generators/rails/model/model_generator.rb +8 -0
- data/lib/rails/generators/rails/observer/USAGE +12 -0
- data/lib/rails/generators/rails/observer/observer_generator.rb +7 -0
- data/lib/rails/generators/rails/performance_test/USAGE +10 -0
- data/lib/rails/generators/rails/performance_test/performance_test_generator.rb +7 -0
- data/lib/rails/generators/rails/plugin_new/USAGE +10 -0
- data/lib/rails/generators/rails/plugin_new/plugin_new_generator.rb +318 -0
- data/lib/rails/generators/rails/plugin_new/templates/%name%.gemspec +29 -0
- data/lib/rails/generators/rails/plugin_new/templates/Gemfile +23 -0
- data/lib/rails/generators/rails/plugin_new/templates/MIT-LICENSE +20 -0
- data/lib/rails/generators/rails/plugin_new/templates/README.rdoc +3 -0
- data/lib/rails/generators/rails/plugin_new/templates/Rakefile +31 -0
- data/lib/rails/generators/rails/plugin_new/templates/app/controllers/%name%/application_controller.rb.tt +4 -0
- data/lib/rails/generators/rails/plugin_new/templates/app/helpers/%name%/application_helper.rb.tt +4 -0
- data/lib/rails/generators/rails/plugin_new/templates/app/mailers/.empty_directory +0 -0
- data/lib/rails/generators/rails/plugin_new/templates/app/models/.empty_directory +0 -0
- data/lib/rails/generators/rails/plugin_new/templates/app/views/layouts/%name%/application.html.erb.tt +14 -0
- data/lib/rails/generators/rails/plugin_new/templates/config/routes.rb +6 -0
- data/lib/rails/generators/rails/plugin_new/templates/gitignore +7 -0
- data/lib/rails/generators/rails/plugin_new/templates/lib/%name%/engine.rb +7 -0
- data/lib/rails/generators/rails/plugin_new/templates/lib/%name%/version.rb +3 -0
- data/lib/rails/generators/rails/plugin_new/templates/lib/%name%.rb +6 -0
- data/lib/rails/generators/rails/plugin_new/templates/lib/tasks/%name%_tasks.rake +4 -0
- data/lib/rails/generators/rails/plugin_new/templates/rails/application.rb +18 -0
- data/lib/rails/generators/rails/plugin_new/templates/rails/boot.rb +10 -0
- data/lib/rails/generators/rails/plugin_new/templates/rails/routes.rb +4 -0
- data/lib/rails/generators/rails/plugin_new/templates/script/rails.tt +7 -0
- data/lib/rails/generators/rails/plugin_new/templates/test/%name%_test.rb +7 -0
- data/lib/rails/generators/rails/plugin_new/templates/test/integration/navigation_test.rb +12 -0
- data/lib/rails/generators/rails/plugin_new/templates/test/test_helper.rb +15 -0
- data/lib/rails/generators/rails/resource/USAGE +23 -0
- data/lib/rails/generators/rails/resource/resource_generator.rb +20 -0
- data/lib/rails/generators/rails/resource_route/resource_route_generator.rb +50 -0
- data/lib/rails/generators/rails/scaffold/USAGE +35 -0
- data/lib/rails/generators/rails/scaffold/scaffold_generator.rb +23 -0
- data/lib/rails/generators/rails/scaffold/templates/scaffold.css +56 -0
- data/lib/rails/generators/rails/scaffold_controller/USAGE +19 -0
- data/lib/rails/generators/rails/scaffold_controller/scaffold_controller_generator.rb +25 -0
- data/lib/rails/generators/rails/scaffold_controller/templates/controller.rb +89 -0
- data/lib/rails/generators/rails/session_migration/USAGE +8 -0
- data/lib/rails/generators/rails/session_migration/session_migration_generator.rb +8 -0
- data/lib/rails/generators/rails/task/USAGE +9 -0
- data/lib/rails/generators/rails/task/task_generator.rb +12 -0
- data/lib/rails/generators/rails/task/templates/task.rb +8 -0
- data/lib/rails/generators/resource_helpers.rb +80 -0
- data/lib/rails/generators/test_case.rb +247 -0
- data/lib/rails/generators/test_unit/controller/controller_generator.rb +15 -0
- data/lib/rails/generators/test_unit/controller/templates/functional_test.rb +19 -0
- data/lib/rails/generators/test_unit/helper/helper_generator.rb +13 -0
- data/lib/rails/generators/test_unit/helper/templates/helper_test.rb +6 -0
- data/lib/rails/generators/test_unit/integration/integration_generator.rb +13 -0
- data/lib/rails/generators/test_unit/integration/templates/integration_test.rb +7 -0
- data/lib/rails/generators/test_unit/mailer/mailer_generator.rb +14 -0
- data/lib/rails/generators/test_unit/mailer/templates/functional_test.rb +21 -0
- data/lib/rails/generators/test_unit/model/model_generator.rb +24 -0
- data/lib/rails/generators/test_unit/model/templates/fixtures.yml +23 -0
- data/lib/rails/generators/test_unit/model/templates/unit_test.rb +9 -0
- data/lib/rails/generators/test_unit/observer/observer_generator.rb +13 -0
- data/lib/rails/generators/test_unit/observer/templates/unit_test.rb +9 -0
- data/lib/rails/generators/test_unit/performance/performance_generator.rb +13 -0
- data/lib/rails/generators/test_unit/performance/templates/performance_test.rb +12 -0
- data/lib/rails/generators/test_unit/plugin/plugin_generator.rb +13 -0
- data/lib/rails/generators/test_unit/plugin/templates/%file_name%_test.rb.tt +7 -0
- data/lib/rails/generators/test_unit/plugin/templates/test_helper.rb +3 -0
- data/lib/rails/generators/test_unit/scaffold/scaffold_generator.rb +38 -0
- data/lib/rails/generators/test_unit/scaffold/templates/functional_test.rb +51 -0
- data/lib/rails/generators/test_unit.rb +8 -0
- data/lib/rails/generators.rb +339 -0
- data/lib/rails/info.rb +116 -0
- data/lib/rails/info_controller.rb +15 -0
- data/lib/rails/initializable.rb +89 -0
- data/lib/rails/paths.rb +211 -0
- data/lib/rails/performance_test_help.rb +3 -0
- data/lib/rails/plugin.rb +92 -0
- data/lib/rails/rack/debugger.rb +24 -0
- data/lib/rails/rack/log_tailer.rb +34 -0
- data/lib/rails/rack/logger.rb +60 -0
- data/lib/rails/rack.rb +7 -0
- data/lib/rails/railtie/configurable.rb +35 -0
- data/lib/rails/railtie/configuration.rb +90 -0
- data/lib/rails/railtie.rb +202 -0
- data/lib/rails/ruby_version_check.rb +23 -0
- data/lib/rails/rubyprof_ext.rb +35 -0
- data/lib/rails/script_rails_loader.rb +29 -0
- data/lib/rails/source_annotation_extractor.rb +104 -0
- data/lib/rails/tasks/annotations.rake +20 -0
- data/lib/rails/tasks/documentation.rake +155 -0
- data/lib/rails/tasks/engine.rake +72 -0
- data/lib/rails/tasks/framework.rake +76 -0
- data/lib/rails/tasks/log.rake +9 -0
- data/lib/rails/tasks/middleware.rake +7 -0
- data/lib/rails/tasks/misc.rake +67 -0
- data/lib/rails/tasks/routes.rake +9 -0
- data/lib/rails/tasks/statistics.rake +16 -0
- data/lib/rails/tasks/tmp.rake +37 -0
- data/lib/rails/tasks.rb +16 -0
- data/lib/rails/test_help.rb +56 -0
- data/lib/rails/test_unit/railtie.rb +15 -0
- data/lib/rails/test_unit/sub_test_task.rb +8 -0
- data/lib/rails/test_unit/testing.rake +146 -0
- data/lib/rails/version.rb +10 -0
- data/lib/rails.rb +126 -0
- metadata +609 -0
@@ -0,0 +1,900 @@
|
|
1
|
+
h2. Migrations
|
2
|
+
|
3
|
+
Migrations are a convenient way for you to alter your database in a structured
|
4
|
+
and organized manner. You could edit fragments of SQL by hand but you would then
|
5
|
+
be responsible for telling other developers that they need to go and run them.
|
6
|
+
You'd also have to keep track of which changes need to be run against the
|
7
|
+
production machines next time you deploy.
|
8
|
+
|
9
|
+
Active Record tracks which migrations have already been run so all you have to
|
10
|
+
do is update your source and run +rake db:migrate+. Active Record will work out
|
11
|
+
which migrations should be run. It will also update your +db/schema.rb+ file to
|
12
|
+
match the structure of your database.
|
13
|
+
|
14
|
+
Migrations also allow you to describe these transformations using Ruby. The
|
15
|
+
great thing about this is that (like most of Active Record's functionality) it
|
16
|
+
is database independent: you don't need to worry about the precise syntax of
|
17
|
+
+CREATE TABLE+ any more than you worry about variations on +SELECT *+ (you can
|
18
|
+
drop down to raw SQL for database specific features). For example you could use
|
19
|
+
SQLite3 in development, but MySQL in production.
|
20
|
+
|
21
|
+
In this guide, you'll learn all about migrations including:
|
22
|
+
|
23
|
+
* The generators you can use to create them
|
24
|
+
* The methods Active Record provides to manipulate your database
|
25
|
+
* The Rake tasks that manipulate them
|
26
|
+
* How they relate to +schema.rb+
|
27
|
+
|
28
|
+
endprologue.
|
29
|
+
|
30
|
+
h3. Anatomy of a Migration
|
31
|
+
|
32
|
+
Before we dive into the details of a migration, here are a few examples of the
|
33
|
+
sorts of things you can do:
|
34
|
+
|
35
|
+
<ruby>
|
36
|
+
class CreateProducts < ActiveRecord::Migration
|
37
|
+
def up
|
38
|
+
create_table :products do |t|
|
39
|
+
t.string :name
|
40
|
+
t.text :description
|
41
|
+
|
42
|
+
t.timestamps
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def down
|
47
|
+
drop_table :products
|
48
|
+
end
|
49
|
+
end
|
50
|
+
</ruby>
|
51
|
+
|
52
|
+
This migration adds a table called +products+ with a string column called +name+
|
53
|
+
and a text column called +description+. A primary key column called +id+ will
|
54
|
+
also be added, however since this is the default we do not need to ask for this.
|
55
|
+
The timestamp columns +created_at+ and +updated_at+ which Active Record
|
56
|
+
populates automatically will also be added. Reversing this migration is as
|
57
|
+
simple as dropping the table.
|
58
|
+
|
59
|
+
Migrations are not limited to changing the schema. You can also use them to fix
|
60
|
+
bad data in the database or populate new fields:
|
61
|
+
|
62
|
+
<ruby>
|
63
|
+
class AddReceiveNewsletterToUsers < ActiveRecord::Migration
|
64
|
+
def up
|
65
|
+
change_table :users do |t|
|
66
|
+
t.boolean :receive_newsletter, :default => false
|
67
|
+
end
|
68
|
+
User.update_all ["receive_newsletter = ?", true]
|
69
|
+
end
|
70
|
+
|
71
|
+
def down
|
72
|
+
remove_column :users, :receive_newsletter
|
73
|
+
end
|
74
|
+
end
|
75
|
+
</ruby>
|
76
|
+
|
77
|
+
NOTE: Some "caveats":#using-models-in-your-migrations apply to using models in
|
78
|
+
your migrations.
|
79
|
+
|
80
|
+
This migration adds a +receive_newsletter+ column to the +users+ table. We want
|
81
|
+
it to default to +false+ for new users, but existing users are considered to
|
82
|
+
have already opted in, so we use the User model to set the flag to +true+ for
|
83
|
+
existing users.
|
84
|
+
|
85
|
+
Rails 3.1 makes migrations smarter by providing a new <tt>change</tt> method.
|
86
|
+
This method is preferred for writing constructive migrations (adding columns or
|
87
|
+
tables). The migration knows how to migrate your database and reverse it when
|
88
|
+
the migration is rolled back without the need to write a separate +down+ method.
|
89
|
+
|
90
|
+
<ruby>
|
91
|
+
class CreateProducts < ActiveRecord::Migration
|
92
|
+
def change
|
93
|
+
create_table :products do |t|
|
94
|
+
t.string :name
|
95
|
+
t.text :description
|
96
|
+
|
97
|
+
t.timestamps
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
</ruby>
|
102
|
+
|
103
|
+
h4. Migrations are Classes
|
104
|
+
|
105
|
+
A migration is a subclass of <tt>ActiveRecord::Migration</tt> that implements
|
106
|
+
two methods: +up+ (perform the required transformations) and +down+ (revert
|
107
|
+
them).
|
108
|
+
|
109
|
+
Active Record provides methods that perform common data definition tasks in a
|
110
|
+
database independent way (you'll read about them in detail later):
|
111
|
+
|
112
|
+
* +add_column+
|
113
|
+
* +add_index+
|
114
|
+
* +change_column+
|
115
|
+
* +change_table+
|
116
|
+
* +create_table+
|
117
|
+
* +drop_table+
|
118
|
+
* +remove_column+
|
119
|
+
* +remove_index+
|
120
|
+
* +rename_column+
|
121
|
+
|
122
|
+
If you need to perform tasks specific to your database (for example create a
|
123
|
+
"foreign key":#active-record-and-referential-integrity constraint) then the
|
124
|
+
+execute+ method allows you to execute arbitrary SQL. A migration is just a
|
125
|
+
regular Ruby class so you're not limited to these functions. For example after
|
126
|
+
adding a column you could write code to set the value of that column for
|
127
|
+
existing records (if necessary using your models).
|
128
|
+
|
129
|
+
On databases that support transactions with statements that change the schema
|
130
|
+
(such as PostgreSQL or SQLite3), migrations are wrapped in a transaction. If the
|
131
|
+
database does not support this (for example MySQL) then when a migration fails
|
132
|
+
the parts of it that succeeded will not be rolled back. You will have to rollback
|
133
|
+
the changes that were made by hand.
|
134
|
+
|
135
|
+
h4. What's in a Name
|
136
|
+
|
137
|
+
Migrations are stored as files in the +db/migrate+ directory, one for each
|
138
|
+
migration class. The name of the file is of the form
|
139
|
+
+YYYYMMDDHHMMSS_create_products.rb+, that is to say a UTC timestamp
|
140
|
+
identifying the migration followed by an underscore followed by the name
|
141
|
+
of the migration. The name of the migration class (CamelCased version)
|
142
|
+
should match the latter part of the file name. For example
|
143
|
+
+20080906120000_create_products.rb+ should define class +CreateProducts+ and
|
144
|
+
+20080906120001_add_details_to_products.rb+ should define
|
145
|
+
+AddDetailsToProducts+. If you do feel the need to change the file name then you
|
146
|
+
<em>have to</em> update the name of the class inside or Rails will complain
|
147
|
+
about a missing class.
|
148
|
+
|
149
|
+
Internally Rails only uses the migration's number (the timestamp) to identify
|
150
|
+
them. Prior to Rails 2.1 the migration number started at 1 and was incremented
|
151
|
+
each time a migration was generated. With multiple developers it was easy for
|
152
|
+
these to clash requiring you to rollback migrations and renumber them. With
|
153
|
+
Rails 2.1+ this is largely avoided by using the creation time of the migration
|
154
|
+
to identify them. You can revert to the old numbering scheme by adding the
|
155
|
+
following line to +config/application.rb+.
|
156
|
+
|
157
|
+
<ruby>
|
158
|
+
config.active_record.timestamped_migrations = false
|
159
|
+
</ruby>
|
160
|
+
|
161
|
+
The combination of timestamps and recording which migrations have been run
|
162
|
+
allows Rails to handle common situations that occur with multiple developers.
|
163
|
+
|
164
|
+
For example Alice adds migrations +20080906120000+ and +20080906123000+ and Bob
|
165
|
+
adds +20080906124500+ and runs it. Alice finishes her changes and checks in her
|
166
|
+
migrations and Bob pulls down the latest changes. When Bob runs +rake db:migrate+,
|
167
|
+
Rails knows that it has not run Alice's two migrations so it executes the +up+ method for each migration.
|
168
|
+
|
169
|
+
Of course this is no substitution for communication within the team. For
|
170
|
+
example, if Alice's migration removed a table that Bob's migration assumed to
|
171
|
+
exist, then trouble would certainly strike.
|
172
|
+
|
173
|
+
h4. Changing Migrations
|
174
|
+
|
175
|
+
Occasionally you will make a mistake when writing a migration. If you have
|
176
|
+
already run the migration then you cannot just edit the migration and run the
|
177
|
+
migration again: Rails thinks it has already run the migration and so will do
|
178
|
+
nothing when you run +rake db:migrate+. You must rollback the migration (for
|
179
|
+
example with +rake db:rollback+), edit your migration and then run +rake db:migrate+ to run the corrected version.
|
180
|
+
|
181
|
+
In general editing existing migrations is not a good idea: you will be creating
|
182
|
+
extra work for yourself and your co-workers and cause major headaches if the
|
183
|
+
existing version of the migration has already been run on production machines.
|
184
|
+
Instead, you should write a new migration that performs the changes you require.
|
185
|
+
Editing a freshly generated migration that has not yet been committed to source
|
186
|
+
control (or, more generally, which has not been propagated beyond your
|
187
|
+
development machine) is relatively harmless.
|
188
|
+
|
189
|
+
h4. Supported Types
|
190
|
+
|
191
|
+
Active Record supports the following database column types:
|
192
|
+
|
193
|
+
* +:binary+
|
194
|
+
* +:boolean+
|
195
|
+
* +:date+
|
196
|
+
* +:datetime+
|
197
|
+
* +:decimal+
|
198
|
+
* +:float+
|
199
|
+
* +:integer+
|
200
|
+
* +:primary_key+
|
201
|
+
* +:string+
|
202
|
+
* +:text+
|
203
|
+
* +:time+
|
204
|
+
* +:timestamp+
|
205
|
+
|
206
|
+
These will be mapped onto an appropriate underlying database type. For example,
|
207
|
+
with MySQL the type +:string+ is mapped to +VARCHAR(255)+. You can create
|
208
|
+
columns of types not supported by Active Record when using the non-sexy syntax,
|
209
|
+
for example
|
210
|
+
|
211
|
+
<ruby>
|
212
|
+
create_table :products do |t|
|
213
|
+
t.column :name, 'polygon', :null => false
|
214
|
+
end
|
215
|
+
</ruby>
|
216
|
+
|
217
|
+
This may however hinder portability to other databases.
|
218
|
+
|
219
|
+
h3. Creating a Migration
|
220
|
+
|
221
|
+
h4. Creating a Model
|
222
|
+
|
223
|
+
The model and scaffold generators will create migrations appropriate for adding
|
224
|
+
a new model. This migration will already contain instructions for creating the
|
225
|
+
relevant table. If you tell Rails what columns you want, then statements for
|
226
|
+
adding these columns will also be created. For example, running
|
227
|
+
|
228
|
+
<shell>
|
229
|
+
$ rails generate model Product name:string description:text
|
230
|
+
</shell>
|
231
|
+
|
232
|
+
will create a migration that looks like this
|
233
|
+
|
234
|
+
<ruby>
|
235
|
+
class CreateProducts < ActiveRecord::Migration
|
236
|
+
def change
|
237
|
+
create_table :products do |t|
|
238
|
+
t.string :name
|
239
|
+
t.text :description
|
240
|
+
|
241
|
+
t.timestamps
|
242
|
+
end
|
243
|
+
end
|
244
|
+
end
|
245
|
+
</ruby>
|
246
|
+
|
247
|
+
You can append as many column name/type pairs as you want. By default, the
|
248
|
+
generated migration will include +t.timestamps+ (which creates the
|
249
|
+
+updated_at+ and +created_at+ columns that are automatically populated
|
250
|
+
by Active Record).
|
251
|
+
|
252
|
+
h4. Creating a Standalone Migration
|
253
|
+
|
254
|
+
If you are creating migrations for other purposes (for example to add a column
|
255
|
+
to an existing table) then you can also use the migration generator:
|
256
|
+
|
257
|
+
<shell>
|
258
|
+
$ rails generate migration AddPartNumberToProducts
|
259
|
+
</shell>
|
260
|
+
|
261
|
+
This will create an empty but appropriately named migration:
|
262
|
+
|
263
|
+
<ruby>
|
264
|
+
class AddPartNumberToProducts < ActiveRecord::Migration
|
265
|
+
def change
|
266
|
+
end
|
267
|
+
end
|
268
|
+
</ruby>
|
269
|
+
|
270
|
+
If the migration name is of the form "AddXXXToYYY" or "RemoveXXXFromYYY" and is
|
271
|
+
followed by a list of column names and types then a migration containing the
|
272
|
+
appropriate +add_column+ and +remove_column+ statements will be created.
|
273
|
+
|
274
|
+
<shell>
|
275
|
+
$ rails generate migration AddPartNumberToProducts part_number:string
|
276
|
+
</shell>
|
277
|
+
|
278
|
+
will generate
|
279
|
+
|
280
|
+
<ruby>
|
281
|
+
class AddPartNumberToProducts < ActiveRecord::Migration
|
282
|
+
def change
|
283
|
+
add_column :products, :part_number, :string
|
284
|
+
end
|
285
|
+
end
|
286
|
+
</ruby>
|
287
|
+
|
288
|
+
Similarly,
|
289
|
+
|
290
|
+
<shell>
|
291
|
+
$ rails generate migration RemovePartNumberFromProducts part_number:string
|
292
|
+
</shell>
|
293
|
+
|
294
|
+
generates
|
295
|
+
|
296
|
+
<ruby>
|
297
|
+
class RemovePartNumberFromProducts < ActiveRecord::Migration
|
298
|
+
def up
|
299
|
+
remove_column :products, :part_number
|
300
|
+
end
|
301
|
+
|
302
|
+
def down
|
303
|
+
add_column :products, :part_number, :string
|
304
|
+
end
|
305
|
+
end
|
306
|
+
</ruby>
|
307
|
+
|
308
|
+
You are not limited to one magically generated column, for example
|
309
|
+
|
310
|
+
<shell>
|
311
|
+
$ rails generate migration AddDetailsToProducts part_number:string price:decimal
|
312
|
+
</shell>
|
313
|
+
|
314
|
+
generates
|
315
|
+
|
316
|
+
<ruby>
|
317
|
+
class AddDetailsToProducts < ActiveRecord::Migration
|
318
|
+
def change
|
319
|
+
add_column :products, :part_number, :string
|
320
|
+
add_column :products, :price, :decimal
|
321
|
+
end
|
322
|
+
end
|
323
|
+
</ruby>
|
324
|
+
|
325
|
+
As always, what has been generated for you is just a starting point. You can add
|
326
|
+
or remove from it as you see fit by editing the
|
327
|
+
db/migrate/YYYYMMDDHHMMSS_add_details_to_products.rb file.
|
328
|
+
|
329
|
+
NOTE: The generated migration file for destructive migrations will still be
|
330
|
+
old-style using the +up+ and +down+ methods. This is because Rails needs to know
|
331
|
+
the original data types defined when you made the original changes.
|
332
|
+
|
333
|
+
h3. Writing a Migration
|
334
|
+
|
335
|
+
Once you have created your migration using one of the generators it's time to
|
336
|
+
get to work!
|
337
|
+
|
338
|
+
h4. Creating a Table
|
339
|
+
|
340
|
+
Migration method +create_table+ will be one of your workhorses. A typical use
|
341
|
+
would be
|
342
|
+
|
343
|
+
<ruby>
|
344
|
+
create_table :products do |t|
|
345
|
+
t.string :name
|
346
|
+
end
|
347
|
+
</ruby>
|
348
|
+
|
349
|
+
which creates a +products+ table with a column called +name+ (and as discussed
|
350
|
+
below, an implicit +id+ column).
|
351
|
+
|
352
|
+
The object yielded to the block allows you to create columns on the table. There
|
353
|
+
are two ways of doing it. The first (traditional) form looks like
|
354
|
+
|
355
|
+
<ruby>
|
356
|
+
create_table :products do |t|
|
357
|
+
t.column :name, :string, :null => false
|
358
|
+
end
|
359
|
+
</ruby>
|
360
|
+
|
361
|
+
The second form, the so called "sexy" migration, drops the somewhat redundant
|
362
|
+
+column+ method. Instead, the +string+, +integer+, etc. methods create a column
|
363
|
+
of that type. Subsequent parameters are the same.
|
364
|
+
|
365
|
+
<ruby>
|
366
|
+
create_table :products do |t|
|
367
|
+
t.string :name, :null => false
|
368
|
+
end
|
369
|
+
</ruby>
|
370
|
+
|
371
|
+
By default, +create_table+ will create a primary key called +id+. You can change
|
372
|
+
the name of the primary key with the +:primary_key+ option (don't forget to
|
373
|
+
update the corresponding model) or, if you don't want a primary key at all (for
|
374
|
+
example for a HABTM join table), you can pass the option +:id => false+. If you
|
375
|
+
need to pass database specific options you can place an SQL fragment in the
|
376
|
+
+:options+ option. For example,
|
377
|
+
|
378
|
+
<ruby>
|
379
|
+
create_table :products, :options => "ENGINE=BLACKHOLE" do |t|
|
380
|
+
t.string :name, :null => false
|
381
|
+
end
|
382
|
+
</ruby>
|
383
|
+
|
384
|
+
will append +ENGINE=BLACKHOLE+ to the SQL statement used to create the table
|
385
|
+
(when using MySQL, the default is +ENGINE=InnoDB+).
|
386
|
+
|
387
|
+
h4. Changing Tables
|
388
|
+
|
389
|
+
A close cousin of +create_table+ is +change_table+, used for changing existing
|
390
|
+
tables. It is used in a similar fashion to +create_table+ but the object yielded
|
391
|
+
to the block knows more tricks. For example
|
392
|
+
|
393
|
+
<ruby>
|
394
|
+
change_table :products do |t|
|
395
|
+
t.remove :description, :name
|
396
|
+
t.string :part_number
|
397
|
+
t.index :part_number
|
398
|
+
t.rename :upccode, :upc_code
|
399
|
+
end
|
400
|
+
</ruby>
|
401
|
+
|
402
|
+
removes the +description+ and +name+ columns, creates a +part_number+ string
|
403
|
+
column and adds an index on it. Finally it renames the +upccode+ column.
|
404
|
+
|
405
|
+
h4. Special Helpers
|
406
|
+
|
407
|
+
Active Record provides some shortcuts for common functionality. It is for
|
408
|
+
example very common to add both the +created_at+ and +updated_at+ columns and so
|
409
|
+
there is a method that does exactly that:
|
410
|
+
|
411
|
+
<ruby>
|
412
|
+
create_table :products do |t|
|
413
|
+
t.timestamps
|
414
|
+
end
|
415
|
+
</ruby>
|
416
|
+
|
417
|
+
will create a new products table with those two columns (plus the +id+ column)
|
418
|
+
whereas
|
419
|
+
|
420
|
+
<ruby>
|
421
|
+
change_table :products do |t|
|
422
|
+
t.timestamps
|
423
|
+
end
|
424
|
+
</ruby>
|
425
|
+
adds those columns to an existing table.
|
426
|
+
|
427
|
+
Another helper is called +references+ (also available as +belongs_to+). In its
|
428
|
+
simplest form it just adds some readability.
|
429
|
+
|
430
|
+
<ruby>
|
431
|
+
create_table :products do |t|
|
432
|
+
t.references :category
|
433
|
+
end
|
434
|
+
</ruby>
|
435
|
+
|
436
|
+
will create a +category_id+ column of the appropriate type. Note that you pass
|
437
|
+
the model name, not the column name. Active Record adds the +_id+ for you. If
|
438
|
+
you have polymorphic +belongs_to+ associations then +references+ will add both
|
439
|
+
of the columns required:
|
440
|
+
|
441
|
+
<ruby>
|
442
|
+
create_table :products do |t|
|
443
|
+
t.references :attachment, :polymorphic => {:default => 'Photo'}
|
444
|
+
end
|
445
|
+
</ruby>
|
446
|
+
|
447
|
+
will add an +attachment_id+ column and a string +attachment_type+ column with
|
448
|
+
a default value of 'Photo'.
|
449
|
+
|
450
|
+
NOTE: The +references+ helper does not actually create foreign key constraints
|
451
|
+
for you. You will need to use +execute+ or a plugin that adds "foreign key
|
452
|
+
support":#active-record-and-referential-integrity.
|
453
|
+
|
454
|
+
If the helpers provided by Active Record aren't enough you can use the +execute+
|
455
|
+
method to execute arbitrary SQL.
|
456
|
+
|
457
|
+
For more details and examples of individual methods, check the API documentation,
|
458
|
+
in particular the documentation for
|
459
|
+
"<tt>ActiveRecord::ConnectionAdapters::SchemaStatements</tt>":http://api.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/SchemaStatements.html
|
460
|
+
(which provides the methods available in the +up+ and +down+ methods),
|
461
|
+
"<tt>ActiveRecord::ConnectionAdapters::TableDefinition</tt>":http://api.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/TableDefinition.html
|
462
|
+
(which provides the methods available on the object yielded by +create_table+)
|
463
|
+
and
|
464
|
+
"<tt>ActiveRecord::ConnectionAdapters::Table</tt>":http://api.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/Table.html
|
465
|
+
(which provides the methods available on the object yielded by +change_table+).
|
466
|
+
|
467
|
+
h4. Using the +change+ Method
|
468
|
+
|
469
|
+
The +change+ method removes the need to write both +up+ and +down+ methods in
|
470
|
+
those cases that Rails know how to revert the changes automatically. Currently,
|
471
|
+
the +change+ method supports only these migration definitions:
|
472
|
+
|
473
|
+
* +add_column+
|
474
|
+
* +add_index+
|
475
|
+
* +add_timestamps+
|
476
|
+
* +create_table+
|
477
|
+
* +remove_timestamps+
|
478
|
+
* +rename_column+
|
479
|
+
* +rename_index+
|
480
|
+
* +rename_table+
|
481
|
+
|
482
|
+
If you're going to need to use any other methods, you'll have to write the
|
483
|
+
+up+ and +down+ methods instead of using the +change+ method.
|
484
|
+
|
485
|
+
h4. Using the +up+/+down+ Methods
|
486
|
+
|
487
|
+
The +down+ method of your migration should revert the transformations done by
|
488
|
+
the +up+ method. In other words, the database schema should be unchanged if you
|
489
|
+
do an +up+ followed by a +down+. For example, if you create a table in the +up+
|
490
|
+
method, you should drop it in the +down+ method. It is wise to reverse the
|
491
|
+
transformations in precisely the reverse order they were made in the +up+
|
492
|
+
method. For example,
|
493
|
+
|
494
|
+
<ruby>
|
495
|
+
class ExampleMigration < ActiveRecord::Migration
|
496
|
+
def up
|
497
|
+
create_table :products do |t|
|
498
|
+
t.references :category
|
499
|
+
end
|
500
|
+
#add a foreign key
|
501
|
+
execute <<-SQL
|
502
|
+
ALTER TABLE products
|
503
|
+
ADD CONSTRAINT fk_products_categories
|
504
|
+
FOREIGN KEY (category_id)
|
505
|
+
REFERENCES categories(id)
|
506
|
+
SQL
|
507
|
+
add_column :users, :home_page_url, :string
|
508
|
+
rename_column :users, :email, :email_address
|
509
|
+
end
|
510
|
+
|
511
|
+
def down
|
512
|
+
rename_column :users, :email_address, :email
|
513
|
+
remove_column :users, :home_page_url
|
514
|
+
execute <<-SQL
|
515
|
+
ALTER TABLE products
|
516
|
+
DROP FOREIGN KEY fk_products_categories
|
517
|
+
SQL
|
518
|
+
drop_table :products
|
519
|
+
end
|
520
|
+
end
|
521
|
+
</ruby>
|
522
|
+
|
523
|
+
Sometimes your migration will do something which is just plain irreversible; for
|
524
|
+
example, it might destroy some data. In such cases, you can raise
|
525
|
+
+ActiveRecord::IrreversibleMigration+ from your +down+ method. If someone tries
|
526
|
+
to revert your migration, an error message will be displayed saying that it
|
527
|
+
can't be done.
|
528
|
+
|
529
|
+
h3. Running Migrations
|
530
|
+
|
531
|
+
Rails provides a set of rake tasks to work with migrations which boil down to
|
532
|
+
running certain sets of migrations.
|
533
|
+
|
534
|
+
The very first migration related rake task you will use will probably be
|
535
|
+
+rake db:migrate+. In its most basic form it just runs the +up+ or +change+
|
536
|
+
method for all the migrations that have not yet been run. If there are
|
537
|
+
no such migrations, it exits. It will run these migrations in order based
|
538
|
+
on the date of the migration.
|
539
|
+
|
540
|
+
Note that running the +db:migrate+ also invokes the +db:schema:dump+ task, which
|
541
|
+
will update your db/schema.rb file to match the structure of your database.
|
542
|
+
|
543
|
+
If you specify a target version, Active Record will run the required migrations
|
544
|
+
(up, down or change) until it has reached the specified version. The version
|
545
|
+
is the numerical prefix on the migration's filename. For example, to migrate
|
546
|
+
to version 20080906120000 run
|
547
|
+
|
548
|
+
<shell>
|
549
|
+
$ rake db:migrate VERSION=20080906120000
|
550
|
+
</shell>
|
551
|
+
|
552
|
+
If version 20080906120000 is greater than the current version (i.e., it is
|
553
|
+
migrating upwards), this will run the +up+ method on all migrations up to and
|
554
|
+
including 20080906120000, and will not execute any later migrations. If
|
555
|
+
migrating downwards, this will run the +down+ method on all the migrations
|
556
|
+
down to, but not including, 20080906120000.
|
557
|
+
|
558
|
+
h4. Rolling Back
|
559
|
+
|
560
|
+
A common task is to rollback the last migration, for example if you made a
|
561
|
+
mistake in it and wish to correct it. Rather than tracking down the version
|
562
|
+
number associated with the previous migration you can run
|
563
|
+
|
564
|
+
<shell>
|
565
|
+
$ rake db:rollback
|
566
|
+
</shell>
|
567
|
+
|
568
|
+
This will run the +down+ method from the latest migration. If you need to undo
|
569
|
+
several migrations you can provide a +STEP+ parameter:
|
570
|
+
|
571
|
+
<shell>
|
572
|
+
$ rake db:rollback STEP=3
|
573
|
+
</shell>
|
574
|
+
|
575
|
+
will run the +down+ method from the last 3 migrations.
|
576
|
+
|
577
|
+
The +db:migrate:redo+ task is a shortcut for doing a rollback and then migrating
|
578
|
+
back up again. As with the +db:rollback+ task, you can use the +STEP+ parameter
|
579
|
+
if you need to go more than one version back, for example
|
580
|
+
|
581
|
+
<shell>
|
582
|
+
$ rake db:migrate:redo STEP=3
|
583
|
+
</shell>
|
584
|
+
|
585
|
+
Neither of these Rake tasks do anything you could not do with +db:migrate+. They
|
586
|
+
are simply more convenient, since you do not need to explicitly specify the
|
587
|
+
version to migrate to.
|
588
|
+
|
589
|
+
h4. Resetting the database
|
590
|
+
|
591
|
+
The +rake db:reset+ task will drop the database, recreate it and load the
|
592
|
+
current schema into it.
|
593
|
+
|
594
|
+
NOTE: This is not the same as running all the migrations - see the section on
|
595
|
+
"schema.rb":#schema-dumping-and-you.
|
596
|
+
|
597
|
+
h4. Running specific migrations
|
598
|
+
|
599
|
+
If you need to run a specific migration up or down, the +db:migrate:up+ and
|
600
|
+
+db:migrate:down+ tasks will do that. Just specify the appropriate version and
|
601
|
+
the corresponding migration will have its +up+ or +down+ method invoked, for
|
602
|
+
example,
|
603
|
+
|
604
|
+
<shell>
|
605
|
+
$ rake db:migrate:up VERSION=20080906120000
|
606
|
+
</shell>
|
607
|
+
|
608
|
+
will run the +up+ method from the 20080906120000 migration. These tasks still
|
609
|
+
check whether the migration has already run, so for example +db:migrate:up
|
610
|
+
VERSION=20080906120000+ will do nothing if Active Record believes that
|
611
|
+
20080906120000 has already been run.
|
612
|
+
|
613
|
+
h4. Changing the output of running migrations
|
614
|
+
|
615
|
+
By default migrations tell you exactly what they're doing and how long it took.
|
616
|
+
A migration creating a table and adding an index might produce output like this
|
617
|
+
|
618
|
+
<shell>
|
619
|
+
== CreateProducts: migrating =================================================
|
620
|
+
-- create_table(:products)
|
621
|
+
-> 0.0028s
|
622
|
+
== CreateProducts: migrated (0.0028s) ========================================
|
623
|
+
</shell>
|
624
|
+
|
625
|
+
Several methods are provided in migrations that allow you to control all this:
|
626
|
+
|
627
|
+
|_.Method |_.Purpose|
|
628
|
+
|suppress_messages |Takes a block as an argument and suppresses any output
|
629
|
+
generated by the block.|
|
630
|
+
|say |Takes a message argument and outputs it as is. A second
|
631
|
+
boolean argument can be passed to specify whether to
|
632
|
+
indent or not.|
|
633
|
+
|say_with_time |Outputs text along with how long it took to run its
|
634
|
+
block. If the block returns an integer it assumes it
|
635
|
+
is the number of rows affected.|
|
636
|
+
|
637
|
+
For example, this migration
|
638
|
+
|
639
|
+
<ruby>
|
640
|
+
class CreateProducts < ActiveRecord::Migration
|
641
|
+
def change
|
642
|
+
suppress_messages do
|
643
|
+
create_table :products do |t|
|
644
|
+
t.string :name
|
645
|
+
t.text :description
|
646
|
+
t.timestamps
|
647
|
+
end
|
648
|
+
end
|
649
|
+
say "Created a table"
|
650
|
+
suppress_messages {add_index :products, :name}
|
651
|
+
say "and an index!", true
|
652
|
+
say_with_time 'Waiting for a while' do
|
653
|
+
sleep 10
|
654
|
+
250
|
655
|
+
end
|
656
|
+
end
|
657
|
+
end
|
658
|
+
</ruby>
|
659
|
+
|
660
|
+
generates the following output
|
661
|
+
|
662
|
+
<shell>
|
663
|
+
== CreateProducts: migrating =================================================
|
664
|
+
-- Created a table
|
665
|
+
-> and an index!
|
666
|
+
-- Waiting for a while
|
667
|
+
-> 10.0013s
|
668
|
+
-> 250 rows
|
669
|
+
== CreateProducts: migrated (10.0054s) =======================================
|
670
|
+
</shell>
|
671
|
+
|
672
|
+
If you want Active Record to not output anything, then running +rake db:migrate
|
673
|
+
VERBOSE=false+ will suppress all output.
|
674
|
+
|
675
|
+
h3. Using Models in Your Migrations
|
676
|
+
|
677
|
+
When creating or updating data in a migration it is often tempting to use one of
|
678
|
+
your models. After all, they exist to provide easy access to the underlying
|
679
|
+
data. This can be done, but some caution should be observed.
|
680
|
+
|
681
|
+
For example, problems occur when the model uses database columns which are (1)
|
682
|
+
not currently in the database and (2) will be created by this or a subsequent
|
683
|
+
migration.
|
684
|
+
|
685
|
+
Consider this example, where Alice and Bob are working on the same code base
|
686
|
+
which contains a +Product+ model:
|
687
|
+
|
688
|
+
Bob goes on vacation.
|
689
|
+
|
690
|
+
Alice creates a migration for the +products+ table which adds a new column and
|
691
|
+
initializes it. She also adds a validation to the +Product+ model for the new
|
692
|
+
column.
|
693
|
+
|
694
|
+
<ruby>
|
695
|
+
# db/migrate/20100513121110_add_flag_to_product.rb
|
696
|
+
|
697
|
+
class AddFlagToProduct < ActiveRecord::Migration
|
698
|
+
def change
|
699
|
+
add_column :products, :flag, :boolean
|
700
|
+
Product.all.each do |product|
|
701
|
+
product.update_attributes!(:flag => 'false')
|
702
|
+
end
|
703
|
+
end
|
704
|
+
end
|
705
|
+
</ruby>
|
706
|
+
|
707
|
+
<ruby>
|
708
|
+
# app/model/product.rb
|
709
|
+
|
710
|
+
class Product < ActiveRecord::Base
|
711
|
+
validates :flag, :presence => true
|
712
|
+
end
|
713
|
+
</ruby>
|
714
|
+
|
715
|
+
Alice adds a second migration which adds and initializes another column to the
|
716
|
+
+products+ table and also adds a validation to the +Product+ model for the new
|
717
|
+
column.
|
718
|
+
|
719
|
+
<ruby>
|
720
|
+
# db/migrate/20100515121110_add_fuzz_to_product.rb
|
721
|
+
|
722
|
+
class AddFuzzToProduct < ActiveRecord::Migration
|
723
|
+
def change
|
724
|
+
add_column :products, :fuzz, :string
|
725
|
+
Product.all.each do |product|
|
726
|
+
product.update_attributes! :fuzz => 'fuzzy'
|
727
|
+
end
|
728
|
+
end
|
729
|
+
end
|
730
|
+
</ruby>
|
731
|
+
|
732
|
+
<ruby>
|
733
|
+
# app/model/product.rb
|
734
|
+
|
735
|
+
class Product < ActiveRecord::Base
|
736
|
+
validates :flag, :fuzz, :presence => true
|
737
|
+
end
|
738
|
+
</ruby>
|
739
|
+
|
740
|
+
Both migrations work for Alice.
|
741
|
+
|
742
|
+
Bob comes back from vacation and:
|
743
|
+
|
744
|
+
# Updates the source - which contains both migrations and the latests version of
|
745
|
+
the Product model.
|
746
|
+
# Runs outstanding migrations with +rake db:migrate+, which
|
747
|
+
includes the one that updates the +Product+ model.
|
748
|
+
|
749
|
+
The migration crashes because when the model attempts to save, it tries to
|
750
|
+
validate the second added column, which is not in the database when the _first_
|
751
|
+
migration runs:
|
752
|
+
|
753
|
+
<plain>
|
754
|
+
rake aborted!
|
755
|
+
An error has occurred, this and all later migrations canceled:
|
756
|
+
|
757
|
+
undefined method `fuzz' for #<Product:0x000001049b14a0>
|
758
|
+
</plain>
|
759
|
+
|
760
|
+
A fix for this is to create a local model within the migration. This keeps rails
|
761
|
+
from running the validations, so that the migrations run to completion.
|
762
|
+
|
763
|
+
When using a faux model, it's a good idea to call
|
764
|
+
+Product.reset_column_information+ to refresh the +ActiveRecord+ cache for the
|
765
|
+
+Product+ model prior to updating data in the database.
|
766
|
+
|
767
|
+
If Alice had done this instead, there would have been no problem:
|
768
|
+
|
769
|
+
<ruby>
|
770
|
+
# db/migrate/20100513121110_add_flag_to_product.rb
|
771
|
+
|
772
|
+
class AddFlagToProduct < ActiveRecord::Migration
|
773
|
+
class Product < ActiveRecord::Base
|
774
|
+
end
|
775
|
+
|
776
|
+
def change
|
777
|
+
add_column :products, :flag, :integer
|
778
|
+
Product.reset_column_information
|
779
|
+
Product.all.each do |product|
|
780
|
+
product.update_attributes!(:flag => false)
|
781
|
+
end
|
782
|
+
end
|
783
|
+
end
|
784
|
+
</ruby>
|
785
|
+
|
786
|
+
<ruby>
|
787
|
+
# db/migrate/20100515121110_add_fuzz_to_product.rb
|
788
|
+
|
789
|
+
class AddFuzzToProduct < ActiveRecord::Migration
|
790
|
+
class Product < ActiveRecord::Base
|
791
|
+
end
|
792
|
+
|
793
|
+
def change
|
794
|
+
add_column :products, :fuzz, :string
|
795
|
+
Product.reset_column_information
|
796
|
+
Product.all.each do |product|
|
797
|
+
product.update_attributes!(:fuzz => 'fuzzy')
|
798
|
+
end
|
799
|
+
end
|
800
|
+
end
|
801
|
+
</ruby>
|
802
|
+
|
803
|
+
h3. Schema Dumping and You
|
804
|
+
|
805
|
+
h4. What are Schema Files for?
|
806
|
+
|
807
|
+
Migrations, mighty as they may be, are not the authoritative source for your
|
808
|
+
database schema. That role falls to either +db/schema.rb+ or an SQL file which
|
809
|
+
Active Record generates by examining the database. They are not designed to be
|
810
|
+
edited, they just represent the current state of the database.
|
811
|
+
|
812
|
+
There is no need (and it is error prone) to deploy a new instance of an app by
|
813
|
+
replaying the entire migration history. It is much simpler and faster to just
|
814
|
+
load into the database a description of the current schema.
|
815
|
+
|
816
|
+
For example, this is how the test database is created: the current development
|
817
|
+
database is dumped (either to +db/schema.rb+ or +db/structure.sql+) and then
|
818
|
+
loaded into the test database.
|
819
|
+
|
820
|
+
Schema files are also useful if you want a quick look at what attributes an
|
821
|
+
Active Record object has. This information is not in the model's code and is
|
822
|
+
frequently spread across several migrations, but the information is nicely
|
823
|
+
summed up in the schema file. The
|
824
|
+
"annotate_models":https://github.com/ctran/annotate_models gem automatically
|
825
|
+
adds and updates comments at the top of each model summarizing the schema if
|
826
|
+
you desire that functionality.
|
827
|
+
|
828
|
+
h4. Types of Schema Dumps
|
829
|
+
|
830
|
+
There are two ways to dump the schema. This is set in +config/application.rb+ by
|
831
|
+
the +config.active_record.schema_format+ setting, which may be either +:sql+ or
|
832
|
+
+:ruby+.
|
833
|
+
|
834
|
+
If +:ruby+ is selected then the schema is stored in +db/schema.rb+. If you look
|
835
|
+
at this file you'll find that it looks an awful lot like one very big migration:
|
836
|
+
|
837
|
+
<ruby>
|
838
|
+
ActiveRecord::Schema.define(:version => 20080906171750) do
|
839
|
+
create_table "authors", :force => true do |t|
|
840
|
+
t.string "name"
|
841
|
+
t.datetime "created_at"
|
842
|
+
t.datetime "updated_at"
|
843
|
+
end
|
844
|
+
|
845
|
+
create_table "products", :force => true do |t|
|
846
|
+
t.string "name"
|
847
|
+
t.text "description"
|
848
|
+
t.datetime "created_at"
|
849
|
+
t.datetime "updated_at"
|
850
|
+
t.string "part_number"
|
851
|
+
end
|
852
|
+
end
|
853
|
+
</ruby>
|
854
|
+
|
855
|
+
In many ways this is exactly what it is. This file is created by inspecting the
|
856
|
+
database and expressing its structure using +create_table+, +add_index+, and so
|
857
|
+
on. Because this is database-independent, it could be loaded into any database
|
858
|
+
that Active Record supports. This could be very useful if you were to distribute
|
859
|
+
an application that is able to run against multiple databases.
|
860
|
+
|
861
|
+
There is however a trade-off: +db/schema.rb+ cannot express database specific
|
862
|
+
items such as foreign key constraints, triggers, or stored procedures. While in
|
863
|
+
a migration you can execute custom SQL statements, the schema dumper cannot
|
864
|
+
reconstitute those statements from the database. If you are using features like
|
865
|
+
this, then you should set the schema format to +:sql+.
|
866
|
+
|
867
|
+
Instead of using Active Record's schema dumper, the database's structure will be
|
868
|
+
dumped using a tool specific to the database (via the +db:structure:dump+ Rake task)
|
869
|
+
into +db/structure.sql+. For example, for the PostgreSQL RDBMS, the
|
870
|
+
+pg_dump+ utility is used. For MySQL, this file will contain the output of +SHOW
|
871
|
+
CREATE TABLE+ for the various tables. Loading these schemas is simply a question
|
872
|
+
of executing the SQL statements they contain. By definition, this will create a
|
873
|
+
perfect copy of the database's structure. Using the +:sql+ schema format will,
|
874
|
+
however, prevent loading the schema into a RDBMS other than the one used to
|
875
|
+
create it.
|
876
|
+
|
877
|
+
h4. Schema Dumps and Source Control
|
878
|
+
|
879
|
+
Because schema dumps are the authoritative source for your database schema, it
|
880
|
+
is strongly recommended that you check them into source control.
|
881
|
+
|
882
|
+
h3. Active Record and Referential Integrity
|
883
|
+
|
884
|
+
The Active Record way claims that intelligence belongs in your models, not in
|
885
|
+
the database. As such, features such as triggers or foreign key constraints,
|
886
|
+
which push some of that intelligence back into the database, are not heavily
|
887
|
+
used.
|
888
|
+
|
889
|
+
Validations such as +validates :foreign_key, :uniqueness => true+ are one way in
|
890
|
+
which models can enforce data integrity. The +:dependent+ option on associations
|
891
|
+
allows models to automatically destroy child objects when the parent is
|
892
|
+
destroyed. Like anything which operates at the application level, these cannot
|
893
|
+
guarantee referential integrity and so some people augment them with foreign key
|
894
|
+
constraints in the database.
|
895
|
+
|
896
|
+
Although Active Record does not provide any tools for working directly with such
|
897
|
+
features, the +execute+ method can be used to execute arbitrary SQL. You could
|
898
|
+
also use some plugin like "foreigner":https://github.com/matthuhiggins/foreigner
|
899
|
+
which add foreign key support to Active Record (including support for dumping
|
900
|
+
foreign keys in +db/schema.rb+).
|